Compare commits

..

1 Commits

Author SHA1 Message Date
FabianLars 14381190e7 chore: Apply clippy suggestions 2025-07-23 12:44:36 +02:00
332 changed files with 9298 additions and 8363 deletions
+8 -2
View File
@@ -1,5 +1,11 @@
[advisories] [advisories]
ignore = [ ignore = [
# time crate can't be updated in the repo because of MSRV, users are unaffected # time 0.1
"RUSTSEC-2026-0009", "RUSTSEC-2020-0071",
# needs sqlx 0.7 (still in alpha)
"RUSTSEC-2022-0090",
# wry needs kuchiki on Android
"RUSTSEC-2023-0019",
# atty is only used when the `colored` feature is enabled on tauri-plugin-log
"RUSTSEC-2021-0145",
] ]
@@ -1,6 +0,0 @@
---
"sql": minor
"sql-js": minor
---
Add support for Postgres `NUMERIC` and custom data types.
-6
View File
@@ -1,6 +0,0 @@
---
"fs": minor
"fs-js": minor
---
Add `encoding` option for `readTextFile` and `readTextFileLines`
-6
View File
@@ -1,6 +0,0 @@
---
"http": patch
"http-js": patch
---
Correct Response header initialization to support cloning and ensure Set-Cookie visibility.
-6
View File
@@ -1,6 +0,0 @@
---
"updater": patch
"updater-js": patch
---
fix: preserve file extension of updater package, otherwise users may get confused when presented with a sudo dialog suggesting to install a file with the extension `.rpm` using `dpkg -i`
@@ -1,6 +0,0 @@
---
"dialog": minor
"dialog-js": minor
---
Re-use `message` command in Rust side for `ask` and `confirm` commands, `allow-ask` and `allow-confirm` permissions are now aliases to `allow-message`
-6
View File
@@ -1,6 +0,0 @@
---
"fs": minor
"fs-js": minor
---
Enable access for security-scoped resources on iOS by automatically calling `NSURL::startAccessingSecurityScopedResource` on resource access and adding the `stopAccessingSecurityScopedResource` API.
-6
View File
@@ -1,6 +0,0 @@
---
"deep-link": patch
"deep-link-js": patch
---
Validate Android new intent is actually a deep link before triggering the onOpenUrl event.
-63
View File
@@ -1,63 +0,0 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: 🐞 Bug Report
description: Report a bug
labels: ['type: bug']
body:
- type: markdown
attributes:
value: |
## First of all
1. Please search for [existing issues](https://github.com/tauri-apps/plugins-workspace/issues?q=is%3Aissue) about this problem first.
2. Make sure `rustc` and all relevant Tauri packages are up to date.
3. Make sure it's an issue with a tauri plugin and not something else you are using.
4. Remember to follow our community guidelines and be friendly.
- type: textarea
id: description
attributes:
label: Describe the bug
description: A clear description of what the bug is. Include screenshots if applicable.
placeholder: Bug description
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: A link to a reproduction repo or steps to reproduce the behaviour.
placeholder: |
Please provide a minimal reproduction or steps to reproduce, see this guide https://stackoverflow.com/help/minimal-reproducible-example
Why reproduction is required? see this article https://antfu.me/posts/why-reproductions-are-required
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: A clear description of what you expected to happen.
- type: textarea
id: info
attributes:
label: Full `tauri info` output
description: 'Output of `npm run tauri info` or `cargo tauri info`. Issues without this will be closed!'
render: text
validations:
required: true
- type: textarea
id: logs
attributes:
label: Stack trace
description: A stack trace or ANY error messages you may see.
render: text
- type: textarea
id: context
attributes:
label: Additional context
description: Add any other context about the problem here. For example a link to a Discord discussion.
-12
View File
@@ -1,12 +0,0 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
#blank_issues_enabled: false
contact_links:
- name: 💡 Request a new plugin
url: https://github.com/orgs/tauri-apps/discussions/new?category=plugin-requests
about: Propose a new Plugin to the community or the Tauri org.
- name: 💬 Discord Chat
url: https://discord.com/invite/tauri
about: Ask questions and talk to other Tauri users and the maintainers
-5
View File
@@ -1,5 +0,0 @@
---
name: 📚 Docs Report
about: Create a report to help us improve the docs
labels: 'type: documentation'
---
@@ -1,46 +0,0 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: 💡 Feature Request
description: Request a feature or enhancement for an existing plugin
labels: ['type: feature request']
body:
- type: markdown
attributes:
value: |
## First of all
- Please search for [existing issues](https://github.com/tauri-apps/plugins-workspace/issues?q=is%3Aissue) for this request first.
- Only requests for plugins that exist in this repo are allowed.
- You can request new plugins [here](https://github.com/orgs/tauri-apps/discussions/new?category=plugin-requests)
- type: textarea
id: problem
attributes:
label: Describe the problem
description: A clear description of the problem this feature would solve
placeholder: "I'm always frustrated when..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: "Describe the solution you'd like"
description: A clear description of what change you would like
placeholder: 'I would like to...'
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: "Any alternative solutions you've considered"
- type: textarea
id: context
attributes:
label: Additional context
description: Add any other context about the problem here.
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: rustsec/audit-check@v2 - uses: rustsec/audit-check@v1
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
# https://github.com/tauri-apps/plugins-workspace/issues/774 # https://github.com/tauri-apps/plugins-workspace/issues/774
@@ -11,7 +11,7 @@ on:
- v2 - v2
permissions: permissions:
# required for oidc token # required for npm provenance
id-token: write id-token: write
# required to create the GitHub Release # required to create the GitHub Release
contents: write contents: write
@@ -62,6 +62,7 @@ jobs:
id: covector id: covector
env: env:
CARGO_TARGET_DIR: /mnt/target CARGO_TARGET_DIR: /mnt/target
NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }}
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
command: 'version-or-publish' command: 'version-or-publish'
-1
View File
@@ -5,7 +5,6 @@
name: integration tests name: integration tests
on: on:
workflow_dispatch:
push: push:
branches: branches:
- v1 - v1
-1
View File
@@ -154,5 +154,4 @@ jobs:
run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings
- name: clippy ${{ matrix.package }} --all-features - name: clippy ${{ matrix.package }} --all-features
if: matrix.package != 'tauri-plugin-dialog'
run: cargo clippy --package ${{ matrix.package }} --all-targets --all-features -- -D warnings run: cargo clippy --package ${{ matrix.package }} --all-targets --all-features -- -D warnings
+2 -2
View File
@@ -246,9 +246,9 @@ jobs:
run: cargo +stable install cross --git https://github.com/cross-rs/cross run: cargo +stable install cross --git https://github.com/cross-rs/cross
- name: test ${{ matrix.package }} - name: test ${{ matrix.package }}
if: ${{ matrix.package != 'tauri-plugin-http' && matrix.package != 'tauri-plugin-dialog' }} if: matrix.package != 'tauri-plugin-http'
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features
- name: test ${{ matrix.package }} - name: test ${{ matrix.package }}
if: ${{ matrix.package == 'tauri-plugin-http' || matrix.package == 'tauri-plugin-dialog' }} if: matrix.package == 'tauri-plugin-http'
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets
+1 -2
View File
@@ -21,7 +21,6 @@ target/
package-lock.json package-lock.json
yarn.lock yarn.lock
bun.lockb bun.lockb
bun.lock
# rust compiled folders # rust compiled folders
target/ target/
@@ -59,4 +58,4 @@ pids
.idea .idea
debug.log debug.log
TODO.md TODO.md
.aider.* .aider*
Generated
+303 -856
View File
File diff suppressed because it is too large Load Diff
+5 -13
View File
@@ -12,16 +12,14 @@ resolver = "2"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
tracing = "0.1" tracing = "0.1"
log = "0.4" log = "0.4"
tauri = { version = "2.10", default-features = false } tauri = { version = "2.6", default-features = false }
tauri-runtime-wry = "2" tauri-build = "2.3"
tauri-runtime-cef = { git = "https://github.com/tauri-apps/tauri.git", branch = "refactor/runtime-feature-flag" } tauri-plugin = "2.3"
tauri-build = "2.5" tauri-utils = "2.5"
tauri-plugin = "2.5"
tauri-utils = "2.8"
serde_json = "1" serde_json = "1"
thiserror = "2" thiserror = "2"
url = "2" url = "2"
schemars = "1" schemars = "0.8"
dunce = "1" dunce = "1"
specta = "^2.0.0-rc.16" specta = "^2.0.0-rc.16"
glob = "0.3" glob = "0.3"
@@ -41,9 +39,3 @@ codegen-units = 1
lto = true lto = true
incremental = false incremental = false
opt-level = "s" opt-level = "s"
[patch.crates-io]
tauri = { git = "https://github.com/tauri-apps/tauri.git", branch = "refactor/runtime-feature-flag" }
tauri-utils = { git = "https://github.com/tauri-apps/tauri.git", branch = "refactor/runtime-feature-flag" }
tauri-plugin = { git = "https://github.com/tauri-apps/tauri.git", branch = "refactor/runtime-feature-flag" }
tauri-runtime-wry = { git = "https://github.com/tauri-apps/tauri.git", branch = "refactor/runtime-feature-flag" }
+1 -2
View File
@@ -3,12 +3,11 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import eslint from '@eslint/js' import eslint from '@eslint/js'
import { defineConfig } from 'eslint/config'
import eslintConfigPrettier from 'eslint-config-prettier' import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginSecurity from 'eslint-plugin-security' import eslintPluginSecurity from 'eslint-plugin-security'
import tseslint from 'typescript-eslint' import tseslint from 'typescript-eslint'
export default defineConfig( export default tseslint.config(
{ {
ignores: [ ignores: [
'**/target', '**/target',
-103
View File
@@ -1,108 +1,5 @@
# Changelog # Changelog
## \[2.0.37]
### Dependencies
- Upgraded to `updater-js@2.10.0`
- Upgraded to `barcode-scanner-js@2.4.4`
- Upgraded to `http-js@2.5.7`
- Upgraded to `shell-js@2.3.5`
## \[2.0.36]
### Dependencies
- Upgraded to `http-js@2.5.6`
- Upgraded to `dialog-js@2.6.0`
## \[2.0.35]
### Dependencies
- Upgraded to `dialog-js@2.5.0`
- Upgraded to `log-js@2.8.0`
- Upgraded to `shell-js@2.3.4`
- Upgraded to `barcode-scanner-js@2.4.3`
- Upgraded to `fs-js@2.4.5`
- Upgraded to `http-js@2.5.5`
- Upgraded to `nfc-js@2.3.4`
- Upgraded to `opener-js@2.5.3`
- Upgraded to `store-js@2.4.2`
## \[2.0.34]
### Dependencies
- Upgraded to `barcode-scanner-js@2.4.2`
- Upgraded to `biometric-js@2.3.2`
- Upgraded to `cli-js@2.4.1`
- Upgraded to `clipboard-manager-js@2.3.2`
- Upgraded to `dialog-js@2.4.2`
- Upgraded to `fs-js@2.4.4`
- Upgraded to `global-shortcut-js@2.3.1`
- Upgraded to `http-js@2.5.4`
- Upgraded to `log-js@2.7.1`
- Upgraded to `nfc-js@2.3.3`
- Upgraded to `notification-js@2.3.3`
- Upgraded to `opener-js@2.5.2`
- Upgraded to `os-js@2.3.2`
- Upgraded to `process-js@2.3.1`
- Upgraded to `shell-js@2.3.3`
- Upgraded to `store-js@2.4.1`
## \[2.0.33]
### Dependencies
- Upgraded to `barcode-scanner-js@2.4.1`
- Upgraded to `biometric-js@2.3.1`
- Upgraded to `clipboard-manager-js@2.3.1`
- Upgraded to `dialog-js@2.4.1`
- Upgraded to `fs-js@2.4.3`
- Upgraded to `nfc-js@2.3.2`
- Upgraded to `notification-js@2.3.2`
- Upgraded to `opener-js@2.5.1`
- Upgraded to `shell-js@2.3.2`
- Upgraded to `http-js@2.5.3`
## \[2.0.32]
### Dependencies
- Upgraded to `dialog-js@2.4.0`
- Upgraded to `log-js@2.7.0`
## \[2.0.31]
### Dependencies
- Upgraded to `shell-js@2.3.1`
## \[2.0.30]
### Dependencies
- Upgraded to `notification-js@2.3.1`
## \[2.0.29]
### Dependencies
- Upgraded to `fs-js@2.4.2`
- Upgraded to `nfc-js@2.3.1`
- Upgraded to `opener-js@2.5.0`
- Upgraded to `os-js@2.3.1`
- Upgraded to `store-js@2.4.0`
- Upgraded to `dialog-js@2.3.3`
- Upgraded to `http-js@2.5.2`
## \[2.0.28]
### Dependencies
- Upgraded to `dialog-js@2.3.2`
## \[2.0.27] ## \[2.0.27]
### Dependencies ### Dependencies
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta <meta
name="viewport" name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=0" content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/> />
<title>Svelte + Vite App</title> <title>Svelte + Vite App</title>
</head> </head>
+20 -20
View File
@@ -1,7 +1,7 @@
{ {
"name": "api", "name": "api",
"private": true, "private": true,
"version": "2.0.37", "version": "2.0.27",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --clearScreen false", "dev": "vite --clearScreen false",
@@ -10,25 +10,25 @@
"tauri": "tauri" "tauri": "tauri"
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.10.1", "@tauri-apps/api": "2.7.0",
"@tauri-apps/plugin-barcode-scanner": "^2.4.4", "@tauri-apps/plugin-barcode-scanner": "^2.4.0",
"@tauri-apps/plugin-biometric": "^2.3.2", "@tauri-apps/plugin-biometric": "^2.3.0",
"@tauri-apps/plugin-cli": "^2.4.1", "@tauri-apps/plugin-cli": "^2.4.0",
"@tauri-apps/plugin-clipboard-manager": "^2.3.2", "@tauri-apps/plugin-clipboard-manager": "^2.3.0",
"@tauri-apps/plugin-dialog": "^2.6.0", "@tauri-apps/plugin-dialog": "^2.3.1",
"@tauri-apps/plugin-fs": "^2.4.5", "@tauri-apps/plugin-fs": "^2.4.1",
"@tauri-apps/plugin-geolocation": "^2.2.0", "@tauri-apps/plugin-geolocation": "^2.2.0",
"@tauri-apps/plugin-global-shortcut": "^2.3.1", "@tauri-apps/plugin-global-shortcut": "^2.3.0",
"@tauri-apps/plugin-haptics": "^2.2.0", "@tauri-apps/plugin-haptics": "^2.2.0",
"@tauri-apps/plugin-http": "^2.5.7", "@tauri-apps/plugin-http": "^2.5.1",
"@tauri-apps/plugin-nfc": "^2.3.4", "@tauri-apps/plugin-nfc": "^2.3.0",
"@tauri-apps/plugin-notification": "^2.3.3", "@tauri-apps/plugin-notification": "^2.3.0",
"@tauri-apps/plugin-opener": "^2.5.3", "@tauri-apps/plugin-opener": "^2.4.0",
"@tauri-apps/plugin-os": "^2.3.2", "@tauri-apps/plugin-os": "^2.3.0",
"@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-process": "^2.3.0",
"@tauri-apps/plugin-shell": "^2.3.5", "@tauri-apps/plugin-shell": "^2.3.0",
"@tauri-apps/plugin-store": "^2.4.2", "@tauri-apps/plugin-store": "^2.3.0",
"@tauri-apps/plugin-updater": "^2.10.0", "@tauri-apps/plugin-updater": "^2.9.0",
"@tauri-apps/plugin-upload": "^2.3.0", "@tauri-apps/plugin-upload": "^2.3.0",
"@zerodevx/svelte-json-view": "1.0.11" "@zerodevx/svelte-json-view": "1.0.11"
}, },
@@ -36,10 +36,10 @@
"@iconify-json/codicon": "^1.2.12", "@iconify-json/codicon": "^1.2.12",
"@iconify-json/ph": "^1.2.2", "@iconify-json/ph": "^1.2.2",
"@sveltejs/vite-plugin-svelte": "^6.0.0", "@sveltejs/vite-plugin-svelte": "^6.0.0",
"@tauri-apps/cli": "2.10.1", "@tauri-apps/cli": "2.7.1",
"@unocss/extractor-svelte": "^66.3.3", "@unocss/extractor-svelte": "^66.3.3",
"svelte": "^5.20.4", "svelte": "^5.20.4",
"unocss": "^66.3.3", "unocss": "^66.3.3",
"vite": "^7.0.7" "vite": "^7.0.4"
} }
} }
-107
View File
@@ -1,112 +1,5 @@
# Changelog # Changelog
## \[2.0.41]
### Dependencies
- Upgraded to `updater@2.10.0`
- Upgraded to `barcode-scanner@2.4.4`
- Upgraded to `http@2.5.7`
- Upgraded to `shell@2.3.5`
## \[2.0.40]
### Dependencies
- Upgraded to `http@2.5.6`
- Upgraded to `dialog@2.6.0`
## \[2.0.39]
### Dependencies
- Upgraded to `dialog@2.5.0`
- Upgraded to `log@2.8.0`
- Upgraded to `shell@2.3.4`
- Upgraded to `barcode-scanner@2.4.3`
- Upgraded to `fs@2.4.5`
- Upgraded to `http@2.5.5`
- Upgraded to `nfc@2.3.4`
- Upgraded to `opener@2.5.3`
- Upgraded to `store@2.4.2`
## \[2.0.38]
### Dependencies
- Upgraded to `barcode-scanner@2.4.2`
- Upgraded to `biometric@2.3.2`
- Upgraded to `cli@2.4.1`
- Upgraded to `clipboard-manager@2.3.2`
- Upgraded to `dialog@2.4.2`
- Upgraded to `fs@2.4.4`
- Upgraded to `geolocation@2.3.2`
- Upgraded to `global-shortcut@2.3.1`
- Upgraded to `haptics@2.3.2`
- Upgraded to `http@2.5.4`
- Upgraded to `log@2.7.1`
- Upgraded to `nfc@2.3.3`
- Upgraded to `notification@2.3.3`
- Upgraded to `opener@2.5.2`
- Upgraded to `os@2.3.2`
- Upgraded to `process@2.3.1`
- Upgraded to `shell@2.3.3`
- Upgraded to `store@2.4.1`
## \[2.0.37]
### Dependencies
- Upgraded to `barcode-scanner@2.4.1`
- Upgraded to `biometric@2.3.1`
- Upgraded to `clipboard-manager@2.3.1`
- Upgraded to `dialog@2.4.1`
- Upgraded to `fs@2.4.3`
- Upgraded to `geolocation@2.3.1`
- Upgraded to `haptics@2.3.1`
- Upgraded to `nfc@2.3.2`
- Upgraded to `notification@2.3.2`
- Upgraded to `opener@2.5.1`
- Upgraded to `shell@2.3.2`
- Upgraded to `http@2.5.3`
## \[2.0.36]
### Dependencies
- Upgraded to `dialog@2.4.0`
- Upgraded to `log@2.7.0`
## \[2.0.35]
### Dependencies
- Upgraded to `shell@2.3.1`
## \[2.0.34]
### Dependencies
- Upgraded to `notification@2.3.1`
## \[2.0.33]
### Dependencies
- Upgraded to `fs@2.4.2`
- Upgraded to `nfc@2.3.1`
- Upgraded to `opener@2.5.0`
- Upgraded to `os@2.3.1`
- Upgraded to `store@2.4.0`
- Upgraded to `dialog@2.3.3`
- Upgraded to `http@2.5.2`
## \[2.0.32]
### Dependencies
- Upgraded to `dialog@2.3.2`
## \[2.0.31] ## \[2.0.31]
### Dependencies ### Dependencies
+23 -27
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "api" name = "api"
publish = false publish = false
version = "2.0.41" version = "2.0.31"
description = "An example Tauri Application showcasing the api" description = "An example Tauri Application showcasing the api"
edition = "2021" edition = "2021"
rust-version = { workspace = true } rust-version = { workspace = true }
@@ -20,33 +20,32 @@ serde = { workspace = true }
tiny_http = "0.12" tiny_http = "0.12"
time = "0.3" time = "0.3"
log = { workspace = true } log = { workspace = true }
tauri-plugin-log = { path = "../../../plugins/log", version = "2.8.0" } tauri-plugin-log = { path = "../../../plugins/log", version = "2.6.0" }
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.4.5", features = [ tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.4.1", features = [
"watch", "watch",
] } ] }
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.3.2" } tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.3.0" }
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.6.0" } tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.3.1" }
tauri-plugin-http = { path = "../../../plugins/http", features = [ tauri-plugin-http = { path = "../../../plugins/http", features = [
"multipart", "multipart",
"cookies", "cookies",
], version = "2.5.7" } ], version = "2.5.1" }
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.3.3", features = [ tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.3.0", features = [
"windows7-compat", "windows7-compat",
] } ] }
tauri-plugin-os = { path = "../../../plugins/os", version = "2.3.2" } tauri-plugin-os = { path = "../../../plugins/os", version = "2.3.0" }
tauri-plugin-process = { path = "../../../plugins/process", version = "2.3.1" } tauri-plugin-process = { path = "../../../plugins/process", version = "2.3.0" }
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.5.3" } tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.4.0" }
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.5" } tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.0" }
tauri-plugin-store = { path = "../../../plugins/store", version = "2.4.2" } tauri-plugin-store = { path = "../../../plugins/store", version = "2.3.0" }
tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" } tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" }
tauri-runtime-wry = { workspace = true, optional = true, features = [
"macos-private-api",
] }
tauri-runtime-cef = { workspace = true, optional = true }
[dependencies.tauri] [dependencies.tauri]
workspace = true workspace = true
features = [ features = [
"wry",
"common-controls-v6",
"x11",
"image-ico", "image-ico",
"image-png", "image-png",
"isolation", "isolation",
@@ -56,20 +55,17 @@ features = [
] ]
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.4.1" } tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.4.0" }
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.3.1" } tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.3.0" }
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.10.0" } tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.9.0" }
tauri-plugin-window-state = { path = "../../../plugins/window-state", version = "2.2.0" } tauri-plugin-window-state = { path = "../../../plugins/window-state", version = "2.2.0" }
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies] [target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.4" } tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.0" }
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.4" } tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.0" }
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.3.2" } tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.3.0" }
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.3.2" } tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.3.0" }
tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.3.2" } tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.3.0" }
[features] [features]
default = ["wry"]
wry = ["dep:tauri-runtime-wry"]
cef = ["dep:tauri-runtime-cef"]
prod = ["tauri/custom-protocol"] prod = ["tauri/custom-protocol"]
@@ -23,7 +23,11 @@
"core:window:allow-start-dragging", "core:window:allow-start-dragging",
"notification:default", "notification:default",
"os:allow-platform", "os:allow-platform",
"dialog:default", "dialog:allow-open",
"dialog:allow-ask",
"dialog:allow-save",
"dialog:allow-confirm",
"dialog:allow-message",
{ {
"identifier": "shell:allow-spawn", "identifier": "shell:allow-spawn",
"allow": [ "allow": [
@@ -64,9 +68,6 @@
"fs:allow-rename", "fs:allow-rename",
"fs:allow-mkdir", "fs:allow-mkdir",
"fs:allow-remove", "fs:allow-remove",
"fs:allow-stat",
"fs:allow-fstat",
"fs:allow-lstat",
"fs:allow-write-text-file", "fs:allow-write-text-file",
"fs:read-meta", "fs:read-meta",
"fs:scope-download-recursive", "fs:scope-download-recursive",
@@ -74,9 +75,6 @@
{ {
"identifier": "fs:scope-appdata-recursive", "identifier": "fs:scope-appdata-recursive",
"allow": [ "allow": [
{
"path": "$APPDATA/db/"
},
{ {
"path": "$APPDATA/db/**" "path": "$APPDATA/db/**"
} }
@@ -14,13 +14,13 @@ val tauriProperties = Properties().apply {
} }
android { android {
compileSdk = 36 compileSdk = 34
namespace = "com.tauri.api" namespace = "com.tauri.api"
defaultConfig { defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false" manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.tauri.api" applicationId = "com.tauri.api"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 34
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
} }
@@ -4,7 +4,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:8.11.0") classpath("com.android.tools.build:gradle:8.5.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
} }
} }
@@ -18,6 +18,6 @@ repositories {
dependencies { dependencies {
compileOnly(gradleApi()) compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:8.11.0") implementation("com.android.tools.build:gradle:8.5.1")
} }
+2 -2
View File
@@ -14,11 +14,11 @@ pub struct RequestBody {
#[command] #[command]
pub fn log_operation(event: String, payload: Option<String>) { pub fn log_operation(event: String, payload: Option<String>) {
log::info!("{} {:?}", event, payload); log::info!("{event} {payload:?}");
} }
#[command] #[command]
pub fn perform_request(endpoint: String, body: RequestBody) -> String { pub fn perform_request(endpoint: String, body: RequestBody) -> String {
println!("{} {:?}", endpoint, body); println!("{endpoint} {body:?}");
"message response".into() "message response".into()
} }
+4 -9
View File
@@ -6,11 +6,6 @@ mod cmd;
#[cfg(desktop)] #[cfg(desktop)]
mod tray; mod tray;
#[cfg(feature = "cef")]
type TauriRuntime = tauri_runtime_cef::CefRuntime<tauri::EventLoopMessage>;
#[cfg(feature = "wry")]
type TauriRuntime = tauri_runtime_wry::Wry<tauri::EventLoopMessage>;
use serde::Serialize; use serde::Serialize;
use tauri::{ use tauri::{
webview::{PageLoadEvent, WebviewWindowBuilder}, webview::{PageLoadEvent, WebviewWindowBuilder},
@@ -22,13 +17,13 @@ struct Reply {
data: String, data: String,
} }
pub type SetupHook<R> = Box<dyn FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error>> + Send>; pub type SetupHook = Box<dyn FnOnce(&mut App) -> Result<(), Box<dyn std::error::Error>> + Send>;
pub type OnEvent<R> = Box<dyn FnMut(&AppHandle<R>, RunEvent)>; pub type OnEvent = Box<dyn FnMut(&AppHandle, RunEvent)>;
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut builder = tauri::Builder::<TauriRuntime>::new() let mut builder = tauri::Builder::default()
.plugin( .plugin(
tauri_plugin_log::Builder::default() tauri_plugin_log::Builder::default()
.level(log::LevelFilter::Info) .level(log::LevelFilter::Info)
@@ -100,7 +95,7 @@ pub fn run() {
let server = match tiny_http::Server::http("localhost:3003") { let server = match tiny_http::Server::http("localhost:3003") {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
eprintln!("{}", e); eprintln!("{e}");
std::process::exit(1); std::process::exit(1);
} }
}; };
+15 -53
View File
@@ -8,8 +8,6 @@
let filter = null; let filter = null;
let multiple = false; let multiple = false;
let directory = false; let directory = false;
let pickerMode = "document";
let fileAccessMode = "scoped";
function arrayBufferToBase64(buffer, callback) { function arrayBufferToBase64(buffer, callback) {
var blob = new Blob([buffer], { var blob = new Blob([buffer], {
@@ -43,19 +41,11 @@
} }
async function msg() { async function msg() {
await message("Tauri is awesome!").then((res) => onMessage(res)); await message("Tauri is awesome!");
} }
async function msgCustom(result) { function openDialog() {
const buttons = { yes: "awesome", no: "amazing", cancel: "stunning" }; open({
await message(`Tauri is: `, { buttons })
.then((res) => onMessage(`Tauri is ${res}`))
.catch(onMessage);
}
async function openDialog() {
try {
var result = await open({
title: "My wonderful open dialog", title: "My wonderful open dialog",
defaultPath, defaultPath,
filters: filter filters: filter
@@ -68,18 +58,15 @@
: [], : [],
multiple, multiple,
directory, directory,
pickerMode,
fileAccessMode,
}) })
if (Array.isArray(result)) {
onMessage(result);
} else {
var pathToRead = result;
var isFile = pathToRead.match(/\S+\.\S+$/g);
await readFile(pathToRead)
.then(function (res) { .then(function (res) {
if (Array.isArray(res)) {
onMessage(res);
} else {
var pathToRead = res;
var isFile = pathToRead.match(/\S+\.\S+$/g);
readFile(pathToRead)
.then(function (response) {
if (isFile) { if (isFile) {
if ( if (
pathToRead.includes(".png") || pathToRead.includes(".png") ||
@@ -87,26 +74,23 @@
pathToRead.includes(".jpeg") pathToRead.includes(".jpeg")
) { ) {
arrayBufferToBase64( arrayBufferToBase64(
new Uint8Array(res), new Uint8Array(response),
function (base64) { function (base64) {
var src = "data:image/png;base64," + base64; var src = "data:image/png;base64," + base64;
insecureRenderHtml('<img src="' + src + '"></img>'); insecureRenderHtml('<img src="' + src + '"></img>');
} }
); );
} else { } else {
// Convert byte array to UTF-8 string onMessage(res);
const decoder = new TextDecoder('utf-8');
const text = decoder.decode(new Uint8Array(res));
onMessage(text);
} }
} else { } else {
onMessage(res); onMessage(res);
} }
}) })
.catch(onMessage(res));
} }
} catch(exception) { })
onMessage(exception) .catch(onMessage);
}
} }
function saveDialog() { function saveDialog() {
@@ -151,26 +135,7 @@
<input type="checkbox" id="dialog-directory" bind:checked={directory} /> <input type="checkbox" id="dialog-directory" bind:checked={directory} />
<label for="dialog-directory">Directory</label> <label for="dialog-directory">Directory</label>
</div> </div>
<div>
<label for="dialog-picker-mode">Picker Mode:</label>
<select id="dialog-picker-mode" bind:value={pickerMode}>
<option value="">None</option>
<option value="media">Media</option>
<option value="image">Image</option>
<option value="video">Video</option>
<option value="document">Document</option>
</select>
</div>
<div>
<label for="dialog-file-access-mode">File Access Mode:</label>
<select id="dialog-file-access-mode" bind:value={fileAccessMode}>
<option value="copy">Copy</option>
<option value="scoped">Scoped</option>
</select>
</div>
<br /> <br />
<div class="flex flex-wrap flex-col md:flex-row gap-2 children:flex-shrink-0">
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button> <button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
<button class="btn" id="save-dialog" on:click={saveDialog} <button class="btn" id="save-dialog" on:click={saveDialog}
>Open save dialog</button >Open save dialog</button
@@ -180,6 +145,3 @@
>Prompt (custom)</button >Prompt (custom)</button
> >
<button class="btn" id="message-dialog" on:click={msg}>Message</button> <button class="btn" id="message-dialog" on:click={msg}>Message</button>
<button class="btn" id="message-dialog" on:click={msgCustom}>Message (custom)</button>
</div>
+93 -114
View File
@@ -1,214 +1,194 @@
<script> <script>
import * as fs from '@tauri-apps/plugin-fs' import * as fs from "@tauri-apps/plugin-fs";
import * as os from '@tauri-apps/plugin-os' import { convertFileSrc } from "@tauri-apps/api/core";
import { convertFileSrc } from '@tauri-apps/api/core' import { arrayBufferToBase64 } from "../lib/utils";
import { arrayBufferToBase64 } from '../lib/utils' import { onDestroy } from "svelte";
import { onDestroy, onMount } from 'svelte'
const { onMessage, insecureRenderHtml } = $props() export let onMessage;
export let insecureRenderHtml;
let path = $state('') let path = "";
let img let img;
/** @type {fs.FileHandle} */ /** @type {fs.FileHandle} */
let file = $state() let file;
let renameTo = $state() let renameTo;
let watchPath = $state('') let watchPath = "";
let watchDebounceDelay = $state(0) let watchDebounceDelay = "0";
let watchRecursive = $state(false) let watchRecursive = false;
/** @type {fs.BaseDirectory | undefined} */ let unwatchFn;
let baseDir = $state() let unwatchPath = "";
let unwatchFn
let unwatchPath = ''
let isMobile = $state(false)
onMount(() => { function getDir() {
let platform = os.platform() const dirSelect = document.getElementById("dir");
isMobile = platform === 'android' || platform === 'ios' return dirSelect.value ? parseInt(dir.value) : null;
}) }
const dirOptions = Object.keys(fs.BaseDirectory).filter((key) => const DirOptions = Object.keys(fs.BaseDirectory)
isNaN(parseInt(key)) .filter((key) => isNaN(parseInt(key)))
) .map((dir) => [dir, fs.BaseDirectory[dir]]);
function open() { function open() {
fs.open(path, { fs.open(path, {
baseDir, baseDir: getDir(),
read: true, read: true,
write: true, write: true,
create: true create: true,
}) })
.then((f) => { .then((f) => {
file = f file = f;
onMessage(`Opened ${path}`) onMessage(`Opened ${path}`);
}) })
.catch(onMessage) .catch(onMessage);
} }
function mkdir() { function mkdir() {
fs.mkdir(path, { baseDir, recursive: true }) fs.mkdir(path, { baseDir: getDir() })
.then(() => { .then(() => {
onMessage(`Created dir ${path}`) onMessage(`Created dir ${path}`);
}) })
.catch(onMessage) .catch(onMessage);
} }
function remove() { function remove() {
fs.remove(path, { baseDir }) fs.remove(path, { baseDir: getDir() })
.then(() => { .then(() => {
onMessage(`Removed ${path}`) onMessage(`Removed ${path}`);
}) })
.catch(onMessage) .catch(onMessage);
} }
function rename() { function rename() {
fs.rename(path, renameTo, { fs.rename(path, renameTo, {
oldPathBaseDir, oldPathBaseDir: getDir(),
newPathBaseDir newPathBaseDir: getDir(),
}) })
.then(() => { .then(() => {
onMessage(`Renamed ${path} to ${renameTo}`) onMessage(`Renamed ${path} to ${renameTo}`);
}) })
.catch(onMessage) .catch(onMessage);
} }
function truncate() { function truncate() {
file file
.truncate(0) .truncate(0)
.then(() => { .then(() => {
onMessage(`Truncated file`) onMessage(`Truncated file`);
}) })
.catch(onMessage) .catch(onMessage);
}
function write() {
const encoder = new TextEncoder()
file
.write(encoder.encode('Hello from Tauri :)'))
.then(() => {
onMessage(`wrote to file`)
})
.catch(onMessage)
} }
function stat() { function stat() {
file file
.stat() .stat()
.then((stat) => { .then((stat) => {
onMessage(`File stat ${JSON.stringify(stat)}`) onMessage(`File stat ${JSON.stringify(stat)}`);
}) })
.catch(onMessage) .catch(onMessage);
} }
function read() { function read() {
const opts = { const opts = {
baseDir baseDir: getDir(),
} };
fs.stat(path, opts) fs.stat(path, opts)
.then((stat) => { .then((stat) => {
const isFile = stat.isFile const isFile = stat.isFile;
const promise = isFile const promise = isFile
? fs.readFile(path, opts) ? fs.readFile(path, opts)
: fs.readDir(path, opts) : fs.readDir(path, opts);
promise promise
.then(function (response) { .then(function (response) {
if (isFile) { if (isFile) {
if (path.includes('.png') || path.includes('.jpg')) { if (path.includes(".png") || path.includes(".jpg")) {
arrayBufferToBase64( arrayBufferToBase64(
new Uint8Array(response), new Uint8Array(response),
function (base64) { function (base64) {
const src = 'data:image/png;base64,' + base64 const src = "data:image/png;base64," + base64;
insecureRenderHtml('<img src="' + src + '"></img>') insecureRenderHtml('<img src="' + src + '"></img>');
} }
) );
} else { } else {
const value = String.fromCharCode.apply(null, response) const value = String.fromCharCode.apply(null, response);
insecureRenderHtml( insecureRenderHtml(
'<textarea id="file-response"></textarea><button id="file-save">Save</button>' '<textarea id="file-response"></textarea><button id="file-save">Save</button>'
) );
setTimeout(() => { setTimeout(() => {
const fileInput = document.getElementById('file-response') const fileInput = document.getElementById("file-response");
fileInput.value = value fileInput.value = value;
document document
.getElementById('file-save') .getElementById("file-save")
.addEventListener('click', function () { .addEventListener("click", function () {
fs.writeTextFile(path, fileInput.value, { fs.writeTextFile(path, fileInput.value, {
baseDir baseDir: getDir(),
}).catch(onMessage) }).catch(onMessage);
}) });
}) });
} }
} else { } else {
onMessage(response) onMessage(response);
} }
}) })
.catch(onMessage) .catch(onMessage);
}) })
.catch(onMessage) .catch(onMessage);
} }
function setSrc() { function setSrc() {
img.src = convertFileSrc(path) img.src = convertFileSrc(path);
} }
function watch() { function watch() {
unwatch() unwatch();
if (watchPath) { if (watchPath) {
onMessage(`Watching ${watchPath} for changes`) onMessage(`Watching ${watchPath} for changes`);
let options = { let options = {
recursive: watchRecursive, recursive: watchRecursive,
delayMs: watchDebounceDelay delayMs: parseInt(watchDebounceDelay),
} };
if (options.delayMs === 0) { if (options.delayMs === 0) {
fs.watchImmediate(watchPath, onMessage, options) fs.watchImmediate(watchPath, onMessage, options)
.then((fn) => { .then((fn) => {
unwatchFn = fn unwatchFn = fn;
unwatchPath = watchPath unwatchPath = watchPath;
}) })
.catch(onMessage) .catch(onMessage);
} else { } else {
fs.watch(watchPath, onMessage, options) fs.watch(watchPath, onMessage, options)
.then((fn) => { .then((fn) => {
unwatchFn = fn unwatchFn = fn;
unwatchPath = watchPath unwatchPath = watchPath;
}) })
.catch(onMessage) .catch(onMessage);
} }
} }
} }
function unwatch() { function unwatch() {
if (unwatchFn) { if (unwatchFn) {
onMessage(`Stopped watching ${unwatchPath} for changes`) onMessage(`Stopped watching ${unwatchPath} for changes`);
unwatchFn() unwatchFn();
} }
unwatchFn = undefined unwatchFn = undefined;
unwatchPath = undefined unwatchPath = undefined;
} }
onDestroy(() => { onDestroy(() => {
if (file) { if (file) {
file.close() file.close();
} }
if (unwatchFn) { if (unwatchFn) {
unwatchFn() unwatchFn();
} }
}) })
</script> </script>
<div class="flex flex-col"> <div class="flex flex-col">
{#if isMobile}
<div>
On mobile, paths outside of App* paths require the use of dialogs
regardless of Tauri's scope mechanism.
</div>
<br />
{/if}
<div class="flex gap-1"> <div class="flex gap-1">
<select class="input" bind:value={baseDir}> <select class="input" id="dir">
<option value={undefined} selected>None</option> <option value="">None</option>
{#each dirOptions as dir} {#each DirOptions as dir}
<option value={fs.BaseDirectory[dir]}>{dir}</option> <option value={dir[1]}>{dir[0]}</option>
{/each} {/each}
</select> </select>
<input <input
@@ -219,21 +199,20 @@
</div> </div>
<br /> <br />
<div> <div>
<button class="btn" onclick={open}>Open</button> <button class="btn" on:click={open}>Open</button>
<button class="btn" onclick={read}>Read</button> <button class="btn" on:click={read}>Read</button>
<button class="btn" onclick={mkdir}>Mkdir</button> <button class="btn" on:click={mkdir}>Mkdir</button>
<button class="btn" onclick={remove}>Remove</button> <button class="btn" on:click={remove}>Remove</button>
<div class="flex flex-row"> <div class="flex flex-row">
<button class="btn" onclick={rename}>Rename</button> <button class="btn" on:click={rename}>Rename</button>
<input class="input" bind:value={renameTo} placeholder="To" /> <input class="input" bind:value={renameTo} placeholder="To" />
</div> </div>
<button class="btn" type="button" onclick={setSrc}>Use as img src</button> <button class="btn" type="button" on:click={setSrc}>Use as img src</button>
</div> </div>
{#if file} {#if file}
<div> <div>
<button class="btn" onclick={write}>Write</button> <button class="btn" on:click={truncate}>Truncate</button>
<button class="btn" onclick={truncate}>Truncate</button> <button class="btn" on:click={stat}>Stat</button>
<button class="btn" onclick={stat}>Stat</button>
</div> </div>
{/if} {/if}
@@ -262,8 +241,8 @@
</div> </div>
<br /> <br />
<div> <div>
<button class="btn" onclick={watch}>Watch</button> <button class="btn" on:click={watch}>Watch</button>
<button class="btn" onclick={unwatch}>Unwatch</button> <button class="btn" on:click={unwatch}>Unwatch</button>
</div> </div>
</div> </div>
+4 -14
View File
@@ -1,21 +1,16 @@
<script> <script>
import { sendNotification } from '@tauri-apps/plugin-notification'
export let onMessage export let onMessage
let sound = ''
// send the notification directly // send the notification directly
// the backend is responsible for checking the permission // the backend is responsible for checking the permission
function _sendNotification() { function _sendNotification() {
sendNotification({ new Notification('Notification title', {
title: 'Notification title', body: 'This is the notification body'
body: 'This is the notification body',
sound: sound || null
}) })
} }
// alternatively, check the permission ourselves // alternatively, check the permission ourselves
function triggerNotification() { function sendNotification() {
if (Notification.permission === 'default') { if (Notification.permission === 'default') {
Notification.requestPermission() Notification.requestPermission()
.then(function (response) { .then(function (response) {
@@ -34,11 +29,6 @@
} }
</script> </script>
<input <button class="btn" id="notification" on:click={sendNotification}>
class="input grow"
placeholder="Notification sound..."
bind:value={sound}
/>
<button class="btn" id="notification" on:click={triggerNotification}>
Send test notification Send test notification
</button> </button>
+32 -49
View File
@@ -1,85 +1,71 @@
<script> <script>
import { appDataDir, resolve } from '@tauri-apps/api/path' import { LazyStore } from "@tauri-apps/plugin-store";
import { LazyStore } from '@tauri-apps/plugin-store' import { onMount } from "svelte";
import { onMount } from 'svelte'
let { onMessage } = $props() export let onMessage;
let key = $state() let key;
let value = $state() let value;
const storeName = 'cache.json' let store = new LazyStore("cache.json");
let cache = {};
let store = new LazyStore(storeName)
let path = $state('')
let cache = $state({})
async function refreshEntries() { async function refreshEntries() {
try { try {
const values = await store.entries() const values = await store.entries();
cache = {} cache = {};
for (const [key, value] of values) { for (const [key, value] of values) {
cache[key] = value cache[key] = value;
} }
} catch (error) { } catch (error) {
onMessage(error) onMessage(error);
} }
} }
onMount(async () => { onMount(async () => {
path = await resolve(await appDataDir(), storeName) await refreshEntries();
await refreshEntries() });
})
async function write(key, value) { async function write(key, value) {
try { try {
if (value) { if (value) {
await store.set(key, value) await store.set(key, value);
} else { } else {
await store.delete(key) await store.delete(key);
} }
const v = await store.get(key) const v = await store.get(key);
if (v === undefined) { if (v === undefined) {
delete cache[key] delete cache[key];
cache = cache cache = cache;
} else { } else {
cache[key] = v cache[key] = v;
} }
} catch (error) { } catch (error) {
onMessage(error) onMessage(error);
} }
} }
async function reset() { async function reset() {
try { try {
await store.reset() await store.reset();
} catch (error) { } catch (error) {
onMessage(error) onMessage(error);
} }
await refreshEntries() await refreshEntries();
}
async function reload() {
try {
await store.reload({ overrideDefaults: true })
} catch (error) {
onMessage(error)
}
await refreshEntries()
} }
async function close() { async function close() {
try { try {
await store.close() await store.close();
onMessage('Store is now closed, any new operations will error out') onMessage("Store is now closed, any new operations will error out");
} catch (error) { } catch (error) {
onMessage(error) onMessage(error);
} }
} }
function reopen() { function reopen() {
store = new LazyStore(storeName) store = new LazyStore("cache.json");
onMessage('We made a new `LazyStore` instance, operations will now work') onMessage("We made a new `LazyStore` instance, operations will now work");
} }
</script> </script>
@@ -96,17 +82,14 @@
</div> </div>
<div> <div>
<button class="btn" onclick={() => write(key, value)}>Write</button> <button class="btn" on:click={() => write(key, value)}>Write</button>
<button class="btn" onclick={() => reset()}>Reset</button> <button class="btn" on:click={() => reset()}>Reset</button>
<button class="btn" onclick={() => reload()}>Reload</button> <button class="btn" on:click={() => close()}>Close</button>
<button class="btn" onclick={() => close()}>Close</button> <button class="btn" on:click={() => reopen()}>Re-open</button>
<button class="btn" onclick={() => reopen()}>Re-open</button>
</div> </div>
<div>Store at <code>{path}</code> on disk</div>
</div> </div>
<div> <div>
<h2>Store Values</h2>
{#each Object.entries(cache) as [k, v]} {#each Object.entries(cache) as [k, v]}
<div>{k} = {v}</div> <div>{k} = {v}</div>
{/each} {/each}
+3 -44
View File
@@ -1,5 +1,5 @@
<script> <script>
import { download, upload, HttpMethod } from '@tauri-apps/plugin-upload' import { download, upload } from '@tauri-apps/plugin-upload'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { JsonView } from '@zerodevx/svelte-json-view' import { JsonView } from '@zerodevx/svelte-json-view'
import { appDataDir } from '@tauri-apps/api/path' import { appDataDir } from '@tauri-apps/api/path'
@@ -16,22 +16,6 @@
let uploadUrl = 'https://httpbin.org/post' let uploadUrl = 'https://httpbin.org/post'
let uploadFilePath = '' let uploadFilePath = ''
let uploadMethod = HttpMethod.Post
// Update URL when method changes
$: {
switch (uploadMethod) {
case HttpMethod.Post:
uploadUrl = 'https://httpbin.org/post'
break
case HttpMethod.Put:
uploadUrl = 'https://httpbin.org/put'
break
case HttpMethod.Patch:
uploadUrl = 'https://httpbin.org/patch'
break
}
}
let uploadProgress = null let uploadProgress = null
let uploadResult = null let uploadResult = null
let isUploading = false let isUploading = false
@@ -213,8 +197,7 @@
}, },
new Map([ new Map([
['User-Agent', 'Tauri Upload Plugin Demo'] ['User-Agent', 'Tauri Upload Plugin Demo']
]), ])
uploadMethod
) )
uploadResult = { uploadResult = {
@@ -357,36 +340,12 @@
</div> </div>
</div> </div>
<div>
<label for="upload-method" class="block text-sm font-medium text-gray-700 mb-1">HTTP Method:</label>
<select
id="upload-method"
bind:value={uploadMethod}
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
disabled={isUploading}
>
<option value={HttpMethod.Post}>POST</option>
<option value={HttpMethod.Put}>PUT</option>
<option value={HttpMethod.Patch}>PATCH</option>
</select>
<p class="text-xs text-gray-500 mt-1">Choose the HTTP method for the upload request</p>
</div>
<div class="bg-blue-50 border border-blue-200 p-3 rounded-md">
<div class="text-sm text-blue-800">
<strong>Upload Configuration:</strong>
<div class="font-mono text-xs mt-1">
Method: {uploadMethod} | URL: {uploadUrl || 'Not set'}
</div>
</div>
</div>
<button <button
on:click={startUpload} on:click={startUpload}
class="w-full px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 disabled:opacity-50 disabled:cursor-not-allowed" class="w-full px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 disabled:opacity-50 disabled:cursor-not-allowed"
disabled={isUploading || !uploadUrl || !uploadFilePath} disabled={isUploading || !uploadUrl || !uploadFilePath}
> >
{isUploading ? `Uploading (${uploadMethod})...` : `Upload File (${uploadMethod})`} {isUploading ? 'Uploading...' : 'Upload File'}
</button> </button>
{#if uploadProgress} {#if uploadProgress}
+12 -12
View File
@@ -11,20 +11,20 @@
"example:api:dev": "pnpm run --filter \"api\" tauri dev" "example:api:dev": "pnpm run --filter \"api\" tauri dev"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "10.0.1", "@eslint/js": "9.31.0",
"@rollup/plugin-node-resolve": "16.0.3", "@rollup/plugin-node-resolve": "16.0.1",
"@rollup/plugin-terser": "1.0.0", "@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-typescript": "12.3.0", "@rollup/plugin-typescript": "12.1.4",
"eslint": "10.0.2", "covector": "^0.12.4",
"eslint": "9.31.0",
"eslint-config-prettier": "10.1.8", "eslint-config-prettier": "10.1.8",
"eslint-plugin-security": "4.0.0", "eslint-plugin-security": "3.0.1",
"prettier": "3.8.1", "prettier": "3.6.2",
"rollup": "4.59.0", "rollup": "4.45.1",
"tslib": "2.8.1", "tslib": "2.8.1",
"typescript": "5.9.3", "typescript": "5.8.3",
"typescript-eslint": "8.56.1" "typescript-eslint": "8.38.0"
}, },
"minimumReleaseAge": 4320,
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"esbuild@<0.25.0": ">=0.25.0" "esbuild@<0.25.0": ">=0.25.0"
@@ -34,6 +34,6 @@
] ]
}, },
"engines": { "engines": {
"pnpm": "^10.16.0" "pnpm": "^10.0.0"
} }
} }
-4
View File
@@ -1,9 +1,5 @@
# Changelog # Changelog
## \[2.5.1]
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
## \[2.5.0] ## \[2.5.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6 - [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+5 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-autostart" name = "tauri-plugin-autostart"
version = "2.5.1" version = "2.5.0"
description = "Automatically launch your application at startup." description = "Automatically launch your application at startup."
authors = { workspace = true } authors = { workspace = true }
license = { workspace = true } license = { workspace = true }
@@ -9,6 +9,10 @@ rust-version = { workspace = true }
repository = { workspace = true } repository = { workspace = true }
links = "tauri-plugin-autostart" links = "tauri-plugin-autostart"
[package.metadata.docs.rs]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.platforms.support] [package.metadata.platforms.support]
windows = { level = "full", notes = "" } windows = { level = "full", notes = "" }
linux = { level = "full", notes = "" } linux = { level = "full", notes = "" }
+9
View File
@@ -33,12 +33,21 @@ tauri-plugin-autostart = { git = "https://github.com/tauri-apps/plugins-workspac
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
```sh ```sh
pnpm add @tauri-apps/plugin-autostart pnpm add @tauri-apps/plugin-autostart
# or # or
npm add @tauri-apps/plugin-autostart npm add @tauri-apps/plugin-autostart
# or # or
yarn add @tauri-apps/plugin-autostart yarn add @tauri-apps/plugin-autostart
# alternatively with Git:
pnpm add https://github.com/tauri-apps/tauri-plugin-autostart#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-autostart#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-autostart#v2
``` ```
## Usage ## Usage
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-autostart", "name": "@tauri-apps/plugin-autostart",
"version": "2.5.1", "version": "2.5.0",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
"Tauri Programme within The Commons Conservancy" "Tauri Programme within The Commons Conservancy"
@@ -24,6 +24,6 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.10.1" "@tauri-apps/api": "^2.6.0"
} }
} }
@@ -24,17 +24,20 @@
}, },
"permission": { "permission": {
"description": "A list of inlined permissions", "description": "A list of inlined permissions",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/Permission" "$ref": "#/definitions/Permission"
}, }
"default": []
} }
}, },
"definitions": { "definitions": {
"DefaultPermission": { "DefaultPermission": {
"description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
"type": "object", "type": "object",
"required": [
"permissions"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -43,10 +46,10 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -59,14 +62,16 @@
"type": "string" "type": "string"
} }
} }
}, }
"required": [
"permissions"
]
}, },
"PermissionSet": { "PermissionSet": {
"description": "A set of direct permissions grouped together under a new name.", "description": "A set of direct permissions grouped together under a new name.",
"type": "object", "type": "object",
"required": [
"description",
"identifier",
"permissions"
],
"properties": { "properties": {
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
@@ -80,19 +85,17 @@
"description": "All permissions this set contains.", "description": "All permissions this set contains.",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "$ref": "#/definitions/PermissionKind"
}
} }
} }
},
"required": [
"identifier",
"description",
"permissions"
]
}, },
"Permission": { "Permission": {
"description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
"type": "object", "type": "object",
"required": [
"identifier"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -101,14 +104,14 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
"type": "string" "type": "string"
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri internal convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -144,10 +147,7 @@
"$ref": "#/definitions/Target" "$ref": "#/definitions/Target"
} }
} }
}, }
"required": [
"identifier"
]
}, },
"Commands": { "Commands": {
"description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.",
@@ -155,24 +155,24 @@
"properties": { "properties": {
"allow": { "allow": {
"description": "Allowed command.", "description": "Allowed command.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
}, },
"deny": { "deny": {
"description": "Denied command, which takes priority.", "description": "Denied command, which takes priority.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
} }
} }
}, },
"Scopes": { "Scopes": {
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\nThe configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json\n{\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n}\n```", "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object", "type": "object",
"properties": { "properties": {
"allow": { "allow": {
@@ -257,27 +257,84 @@
{ {
"description": "MacOS.", "description": "MacOS.",
"type": "string", "type": "string",
"const": "macOS" "enum": [
"macOS"
]
}, },
{ {
"description": "Windows.", "description": "Windows.",
"type": "string", "type": "string",
"const": "windows" "enum": [
"windows"
]
}, },
{ {
"description": "Linux.", "description": "Linux.",
"type": "string", "type": "string",
"const": "linux" "enum": [
"linux"
]
}, },
{ {
"description": "Android.", "description": "Android.",
"type": "string", "type": "string",
"const": "android" "enum": [
"android"
]
}, },
{ {
"description": "iOS.", "description": "iOS.",
"type": "string", "type": "string",
"const": "iOS" "enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "Enables the disable command without any pre-configured scope.",
"type": "string",
"const": "allow-disable",
"markdownDescription": "Enables the disable command without any pre-configured scope."
},
{
"description": "Denies the disable command without any pre-configured scope.",
"type": "string",
"const": "deny-disable",
"markdownDescription": "Denies the disable command without any pre-configured scope."
},
{
"description": "Enables the enable command without any pre-configured scope.",
"type": "string",
"const": "allow-enable",
"markdownDescription": "Enables the enable command without any pre-configured scope."
},
{
"description": "Denies the enable command without any pre-configured scope.",
"type": "string",
"const": "deny-enable",
"markdownDescription": "Denies the enable command without any pre-configured scope."
},
{
"description": "Enables the is_enabled command without any pre-configured scope.",
"type": "string",
"const": "allow-is-enabled",
"markdownDescription": "Enables the is_enabled command without any pre-configured scope."
},
{
"description": "Denies the is_enabled command without any pre-configured scope.",
"type": "string",
"const": "deny-is-enabled",
"markdownDescription": "Denies the is_enabled command without any pre-configured scope."
},
{
"description": "This permission set configures if your\napplication can enable or disable auto\nstarting the application on boot.\n\n#### Granted Permissions\n\nIt allows all to check, enable and\ndisable the automatic start on boot.\n\n\n#### This default permission set includes:\n\n- `allow-enable`\n- `allow-disable`\n- `allow-is-enabled`",
"type": "string",
"const": "default",
"markdownDescription": "This permission set configures if your\napplication can enable or disable auto\nstarting the application on boot.\n\n#### Granted Permissions\n\nIt allows all to check, enable and\ndisable the automatic start on boot.\n\n\n#### This default permission set includes:\n\n- `allow-enable`\n- `allow-disable`\n- `allow-is-enabled`"
} }
] ]
} }
-20
View File
@@ -1,25 +1,5 @@
# Changelog # Changelog
## \[2.4.4]
- [`82fbb0c7`](https://github.com/tauri-apps/plugins-workspace/commit/82fbb0c790288eca72af9ade13828ded7700ff90) ([#3221](https://github.com/tauri-apps/plugins-workspace/pull/3221)) On iOS, fixed an application crash happening when the scanner was started when user denied permission before.
- [`b60dd887`](https://github.com/tauri-apps/plugins-workspace/commit/b60dd88702a2be2af942a3d104d728970a4c42d6) ([#3223](https://github.com/tauri-apps/plugins-workspace/pull/3223)) On iOS, start the scanning session on a separate thread to fix performance issues.
- [`c27af912`](https://github.com/tauri-apps/plugins-workspace/commit/c27af9128d6cc7a2424ec49e98005e68b2d0eb1a) ([#3222](https://github.com/tauri-apps/plugins-workspace/pull/3222)) On iOS, fixed an application crash happening when the scanner was started on the iOS Simulator (no camera available).
## \[2.4.3]
- [`d8bfe61f`](https://github.com/tauri-apps/plugins-workspace/commit/d8bfe61f20f235314bad93a9c50d8b7f3eade734) ([#3121](https://github.com/tauri-apps/plugins-workspace/pull/3121) by [@NKIPSC](https://github.com/tauri-apps/plugins-workspace/../../NKIPSC)) Remove unnecessary checks on Android when requesting camera permission.
- [`631d0e25`](https://github.com/tauri-apps/plugins-workspace/commit/631d0e256a37946b6a9102ca35511abfbebb92c5) ([#2440](https://github.com/tauri-apps/plugins-workspace/pull/2440) by [@kingsword09](https://github.com/tauri-apps/plugins-workspace/../../kingsword09)) Fix the `cameraView` is not removed after scanning in iOS.
## \[2.4.2]
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
## \[2.4.1]
- [`654bf489`](https://github.com/tauri-apps/plugins-workspace/commit/654bf4891a35769f7e82971641d3ad99974b2dfe) ([#3038](https://github.com/tauri-apps/plugins-workspace/pull/3038) by [@daniel-mader](https://github.com/tauri-apps/plugins-workspace/../../daniel-mader)) Update `androidx.camera` from `1.1.0` to `1.5.1` to support 16 KB memory page sizes.
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
## \[2.4.0] ## \[2.4.0]
- [`aa9140e1`](https://github.com/tauri-apps/plugins-workspace/commit/aa9140e1ac239ab9f015f92b2ed52bbf0eda7c12) ([#2437](https://github.com/tauri-apps/plugins-workspace/pull/2437) by [@enkhjile](https://github.com/tauri-apps/plugins-workspace/../../enkhjile)) Added support for GS1 DataBar on iOS 15.4+ - [`aa9140e1`](https://github.com/tauri-apps/plugins-workspace/commit/aa9140e1ac239ab9f015f92b2ed52bbf0eda7c12) ([#2437](https://github.com/tauri-apps/plugins-workspace/pull/2437) by [@enkhjile](https://github.com/tauri-apps/plugins-workspace/../../enkhjile)) Added support for GS1 DataBar on iOS 15.4+
+4 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-barcode-scanner" name = "tauri-plugin-barcode-scanner"
version = "2.4.4" version = "2.4.0"
description = "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS" description = "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS"
edition = { workspace = true } edition = { workspace = true }
authors = { workspace = true } authors = { workspace = true }
@@ -10,6 +10,8 @@ repository = { workspace = true }
links = "tauri-plugin-barcode-scanner" links = "tauri-plugin-barcode-scanner"
[package.metadata.docs.rs] [package.metadata.docs.rs]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
targets = ["x86_64-linux-android"] targets = ["x86_64-linux-android"]
[package.metadata.platforms.support] [package.metadata.platforms.support]
@@ -31,4 +33,4 @@ log = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
[target.'cfg(target_os = "ios")'.dependencies] [target.'cfg(target_os = "ios")'.dependencies]
tauri = { workspace = true } tauri = { workspace = true, features = ["wry"] }
+9
View File
@@ -33,12 +33,21 @@ tauri-plugin-barcode-scanner = { git = "https://github.com/tauri-apps/plugins-wo
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
```sh ```sh
pnpm add @tauri-apps/plugin-barcode-scanner pnpm add @tauri-apps/plugin-barcode-scanner
# or # or
npm add @tauri-apps/plugin-barcode-scanner npm add @tauri-apps/plugin-barcode-scanner
# or # or
yarn add @tauri-apps/plugin-barcode-scanner yarn add @tauri-apps/plugin-barcode-scanner
# alternatively with Git:
pnpm add https://github.com/tauri-apps/tauri-plugin-barcode-scanner#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-barcode-scanner#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-barcode-scanner#v2
``` ```
## Usage ## Usage
@@ -5,7 +5,7 @@ plugins {
android { android {
namespace = "app.tauri.barcodescanner" namespace = "app.tauri.barcodescanner"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
@@ -33,14 +33,16 @@ android {
} }
dependencies { dependencies {
val camerax_version = "1.5.1"
implementation("androidx.core:core-ktx:1.9.0") implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.0") implementation("androidx.appcompat:appcompat:1.6.0")
implementation("com.google.android.material:material:1.7.0") implementation("com.google.android.material:material:1.7.0")
implementation("androidx.camera:camera-core:${camerax_version}") implementation("androidx.camera:camera-core:1.1.0")
implementation("androidx.camera:camera-camera2:${camerax_version}") implementation("androidx.camera:camera-view:1.1.0")
implementation("androidx.camera:camera-lifecycle:${camerax_version}") implementation("androidx.camera:camera-lifecycle:1.1.0")
implementation("androidx.camera:camera-view:${camerax_version}") implementation("androidx.camera:camera-camera2:1.1.0")
implementation("androidx.camera:camera-lifecycle:1.1.0")
implementation("androidx.camera:camera-view:1.1.0")
implementation("com.google.android.gms:play-services-mlkit-barcode-scanning:18.1.0") implementation("com.google.android.gms:play-services-mlkit-barcode-scanning:18.1.0")
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5")
@@ -54,6 +54,7 @@ import java.util.concurrent.ExecutionException
private const val PERMISSION_ALIAS_CAMERA = "camera" private const val PERMISSION_ALIAS_CAMERA = "camera"
private const val PERMISSION_NAME = Manifest.permission.CAMERA private const val PERMISSION_NAME = Manifest.permission.CAMERA
private const val PREFS_PERMISSION_FIRST_TIME_ASKING = "PREFS_PERMISSION_FIRST_TIME_ASKING"
@InvokeArg @InvokeArg
class ScanOptions { class ScanOptions {
@@ -353,6 +354,17 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
} }
} }
private fun markFirstPermissionRequest() {
val sharedPreference: SharedPreferences =
activity.getSharedPreferences(PREFS_PERMISSION_FIRST_TIME_ASKING, MODE_PRIVATE)
sharedPreference.edit().putBoolean(PERMISSION_NAME, false).apply()
}
private fun firstPermissionRequest(): Boolean {
return activity.getSharedPreferences(PREFS_PERMISSION_FIRST_TIME_ASKING, MODE_PRIVATE)
.getBoolean(PERMISSION_NAME, true)
}
@SuppressLint("ObsoleteSdkInt") @SuppressLint("ObsoleteSdkInt")
@PermissionCallback @PermissionCallback
fun cameraPermissionCallback(invoke: Invoke) { fun cameraPermissionCallback(invoke: Invoke) {
@@ -368,7 +380,9 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED) requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
} else { } else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!activity.shouldShowRequestPermissionRationale(PERMISSION_NAME)) {
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED) requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED)
}
} else { } else {
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED) requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
} }
@@ -387,12 +401,20 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED) requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
} else { } else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (firstPermissionRequest() || activity.shouldShowRequestPermissionRationale(
PERMISSION_NAME
)
) {
markFirstPermissionRequest()
requestPermissionForAlias( requestPermissionForAlias(
PERMISSION_ALIAS_CAMERA, PERMISSION_ALIAS_CAMERA,
invoke, invoke,
"cameraPermissionCallback" "cameraPermissionCallback"
) )
return return
} else {
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED)
}
} else { } else {
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED) requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
} }
@@ -191,7 +191,6 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
if self.captureSession != nil { if self.captureSession != nil {
self.captureSession!.stopRunning() self.captureSession!.stopRunning()
self.cameraView.removePreviewLayer() self.cameraView.removePreviewLayer()
self.cameraView.removeFromSuperview()
self.captureVideoPreviewLayer = nil self.captureVideoPreviewLayer = nil
self.metaOutput = nil self.metaOutput = nil
self.captureSession = nil self.captureSession = nil
@@ -261,11 +260,6 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
} }
private func runScanner(_ invoke: Invoke, args: ScanOptions) { private func runScanner(_ invoke: Invoke, args: ScanOptions) {
if getPermissionState() != "granted" {
invoke.reject("Camera permission denied or not yet requested")
return
}
scanFormats = [AVMetadataObject.ObjectType]() scanFormats = [AVMetadataObject.ObjectType]()
(args.formats ?? []).forEach { format in (args.formats ?? []).forEach { format in
@@ -286,9 +280,7 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
} }
self.metaOutput!.metadataObjectTypes = self.scanFormats self.metaOutput!.metadataObjectTypes = self.scanFormats
DispatchQueue.main.async {
self.captureSession!.startRunning() self.captureSession!.startRunning()
}
self.isScanning = true self.isScanning = true
} }
@@ -305,13 +297,6 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
return return
} }
// Check if camera is available on this platform (iOS simulator doesn't have cameras)
let availableVideoDevices = discoverCaptureDevices()
if availableVideoDevices.isEmpty {
invoke.reject("No camera available on this device (e.g., iOS Simulator)")
return
}
var iOS14min: Bool = false var iOS14min: Bool = false
if #available(iOS 14.0, *) { iOS14min = true } if #available(iOS 14.0, *) { iOS14min = true }
if !iOS14min && self.getPermissionState() != "granted" { if !iOS14min && self.getPermissionState() != "granted" {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-barcode-scanner", "name": "@tauri-apps/plugin-barcode-scanner",
"version": "2.4.4", "version": "2.4.0",
"description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS", "description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
@@ -25,6 +25,6 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.10.1" "@tauri-apps/api": "^2.6.0"
} }
} }
@@ -24,17 +24,20 @@
}, },
"permission": { "permission": {
"description": "A list of inlined permissions", "description": "A list of inlined permissions",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/Permission" "$ref": "#/definitions/Permission"
}, }
"default": []
} }
}, },
"definitions": { "definitions": {
"DefaultPermission": { "DefaultPermission": {
"description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
"type": "object", "type": "object",
"required": [
"permissions"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -43,10 +46,10 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -59,14 +62,16 @@
"type": "string" "type": "string"
} }
} }
}, }
"required": [
"permissions"
]
}, },
"PermissionSet": { "PermissionSet": {
"description": "A set of direct permissions grouped together under a new name.", "description": "A set of direct permissions grouped together under a new name.",
"type": "object", "type": "object",
"required": [
"description",
"identifier",
"permissions"
],
"properties": { "properties": {
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
@@ -80,19 +85,17 @@
"description": "All permissions this set contains.", "description": "All permissions this set contains.",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "$ref": "#/definitions/PermissionKind"
}
} }
} }
},
"required": [
"identifier",
"description",
"permissions"
]
}, },
"Permission": { "Permission": {
"description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
"type": "object", "type": "object",
"required": [
"identifier"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -101,14 +104,14 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
"type": "string" "type": "string"
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri internal convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -144,10 +147,7 @@
"$ref": "#/definitions/Target" "$ref": "#/definitions/Target"
} }
} }
}, }
"required": [
"identifier"
]
}, },
"Commands": { "Commands": {
"description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.",
@@ -155,24 +155,24 @@
"properties": { "properties": {
"allow": { "allow": {
"description": "Allowed command.", "description": "Allowed command.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
}, },
"deny": { "deny": {
"description": "Denied command, which takes priority.", "description": "Denied command, which takes priority.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
} }
} }
}, },
"Scopes": { "Scopes": {
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\nThe configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json\n{\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n}\n```", "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object", "type": "object",
"properties": { "properties": {
"allow": { "allow": {
@@ -257,27 +257,120 @@
{ {
"description": "MacOS.", "description": "MacOS.",
"type": "string", "type": "string",
"const": "macOS" "enum": [
"macOS"
]
}, },
{ {
"description": "Windows.", "description": "Windows.",
"type": "string", "type": "string",
"const": "windows" "enum": [
"windows"
]
}, },
{ {
"description": "Linux.", "description": "Linux.",
"type": "string", "type": "string",
"const": "linux" "enum": [
"linux"
]
}, },
{ {
"description": "Android.", "description": "Android.",
"type": "string", "type": "string",
"const": "android" "enum": [
"android"
]
}, },
{ {
"description": "iOS.", "description": "iOS.",
"type": "string", "type": "string",
"const": "iOS" "enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "Enables the cancel command without any pre-configured scope.",
"type": "string",
"const": "allow-cancel",
"markdownDescription": "Enables the cancel command without any pre-configured scope."
},
{
"description": "Denies the cancel command without any pre-configured scope.",
"type": "string",
"const": "deny-cancel",
"markdownDescription": "Denies the cancel command without any pre-configured scope."
},
{
"description": "Enables the check_permissions command without any pre-configured scope.",
"type": "string",
"const": "allow-check-permissions",
"markdownDescription": "Enables the check_permissions command without any pre-configured scope."
},
{
"description": "Denies the check_permissions command without any pre-configured scope.",
"type": "string",
"const": "deny-check-permissions",
"markdownDescription": "Denies the check_permissions command without any pre-configured scope."
},
{
"description": "Enables the open_app_settings command without any pre-configured scope.",
"type": "string",
"const": "allow-open-app-settings",
"markdownDescription": "Enables the open_app_settings command without any pre-configured scope."
},
{
"description": "Denies the open_app_settings command without any pre-configured scope.",
"type": "string",
"const": "deny-open-app-settings",
"markdownDescription": "Denies the open_app_settings command without any pre-configured scope."
},
{
"description": "Enables the request_permissions command without any pre-configured scope.",
"type": "string",
"const": "allow-request-permissions",
"markdownDescription": "Enables the request_permissions command without any pre-configured scope."
},
{
"description": "Denies the request_permissions command without any pre-configured scope.",
"type": "string",
"const": "deny-request-permissions",
"markdownDescription": "Denies the request_permissions command without any pre-configured scope."
},
{
"description": "Enables the scan command without any pre-configured scope.",
"type": "string",
"const": "allow-scan",
"markdownDescription": "Enables the scan command without any pre-configured scope."
},
{
"description": "Denies the scan command without any pre-configured scope.",
"type": "string",
"const": "deny-scan",
"markdownDescription": "Denies the scan command without any pre-configured scope."
},
{
"description": "Enables the vibrate command without any pre-configured scope.",
"type": "string",
"const": "allow-vibrate",
"markdownDescription": "Enables the vibrate command without any pre-configured scope."
},
{
"description": "Denies the vibrate command without any pre-configured scope.",
"type": "string",
"const": "deny-vibrate",
"markdownDescription": "Denies the vibrate command without any pre-configured scope."
},
{
"description": "This permission set configures which\nbarcode scanning features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all barcode related features.\n\n\n#### This default permission set includes:\n\n- `allow-cancel`\n- `allow-check-permissions`\n- `allow-open-app-settings`\n- `allow-request-permissions`\n- `allow-scan`\n- `allow-vibrate`",
"type": "string",
"const": "default",
"markdownDescription": "This permission set configures which\nbarcode scanning features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all barcode related features.\n\n\n#### This default permission set includes:\n\n- `allow-cancel`\n- `allow-check-permissions`\n- `allow-open-app-settings`\n- `allow-request-permissions`\n- `allow-scan`\n- `allow-vibrate`"
} }
] ]
} }
-8
View File
@@ -1,13 +1,5 @@
# Changelog # Changelog
## \[2.3.2]
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
## \[2.3.1]
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
## \[2.3.0] ## \[2.3.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6 - [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+3 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-biometric" name = "tauri-plugin-biometric"
version = "2.3.2" version = "2.3.0"
description = "Prompt the user for biometric authentication on Android and iOS." description = "Prompt the user for biometric authentication on Android and iOS."
edition = { workspace = true } edition = { workspace = true }
authors = { workspace = true } authors = { workspace = true }
@@ -9,6 +9,8 @@ repository = { workspace = true }
links = "tauri-plugin-biometric" links = "tauri-plugin-biometric"
[package.metadata.docs.rs] [package.metadata.docs.rs]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
targets = ["x86_64-linux-android"] targets = ["x86_64-linux-android"]
[package.metadata.platforms.support] [package.metadata.platforms.support]
+9
View File
@@ -33,6 +33,8 @@ tauri-plugin-biometric = { git = "https://github.com/tauri-apps/plugins-workspac
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
<!-- Add the branch for installations using git! --> <!-- Add the branch for installations using git! -->
```sh ```sh
@@ -41,6 +43,13 @@ pnpm add @tauri-apps/plugin-biometric
npm add @tauri-apps/plugin-biometric npm add @tauri-apps/plugin-biometric
# or # or
yarn add @tauri-apps/plugin-biometric yarn add @tauri-apps/plugin-biometric
# alternatively with Git:
pnpm add https://github.com/tauri-apps/tauri-plugin-biometric#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-biometric#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-biometric#v2
``` ```
## Usage ## Usage
+1 -1
View File
@@ -5,7 +5,7 @@ plugins {
android { android {
namespace = "app.tauri.biometric" namespace = "app.tauri.biometric"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-biometric", "name": "@tauri-apps/plugin-biometric",
"version": "2.3.2", "version": "2.3.0",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
"Tauri Programme within The Commons Conservancy" "Tauri Programme within The Commons Conservancy"
@@ -25,6 +25,6 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.10.1" "@tauri-apps/api": "^2.6.0"
} }
} }
@@ -24,17 +24,20 @@
}, },
"permission": { "permission": {
"description": "A list of inlined permissions", "description": "A list of inlined permissions",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/Permission" "$ref": "#/definitions/Permission"
}, }
"default": []
} }
}, },
"definitions": { "definitions": {
"DefaultPermission": { "DefaultPermission": {
"description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
"type": "object", "type": "object",
"required": [
"permissions"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -43,10 +46,10 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -59,14 +62,16 @@
"type": "string" "type": "string"
} }
} }
}, }
"required": [
"permissions"
]
}, },
"PermissionSet": { "PermissionSet": {
"description": "A set of direct permissions grouped together under a new name.", "description": "A set of direct permissions grouped together under a new name.",
"type": "object", "type": "object",
"required": [
"description",
"identifier",
"permissions"
],
"properties": { "properties": {
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
@@ -80,19 +85,17 @@
"description": "All permissions this set contains.", "description": "All permissions this set contains.",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "$ref": "#/definitions/PermissionKind"
}
} }
} }
},
"required": [
"identifier",
"description",
"permissions"
]
}, },
"Permission": { "Permission": {
"description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
"type": "object", "type": "object",
"required": [
"identifier"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -101,14 +104,14 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
"type": "string" "type": "string"
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri internal convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -144,10 +147,7 @@
"$ref": "#/definitions/Target" "$ref": "#/definitions/Target"
} }
} }
}, }
"required": [
"identifier"
]
}, },
"Commands": { "Commands": {
"description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.",
@@ -155,24 +155,24 @@
"properties": { "properties": {
"allow": { "allow": {
"description": "Allowed command.", "description": "Allowed command.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
}, },
"deny": { "deny": {
"description": "Denied command, which takes priority.", "description": "Denied command, which takes priority.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
} }
} }
}, },
"Scopes": { "Scopes": {
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\nThe configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json\n{\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n}\n```", "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object", "type": "object",
"properties": { "properties": {
"allow": { "allow": {
@@ -257,27 +257,72 @@
{ {
"description": "MacOS.", "description": "MacOS.",
"type": "string", "type": "string",
"const": "macOS" "enum": [
"macOS"
]
}, },
{ {
"description": "Windows.", "description": "Windows.",
"type": "string", "type": "string",
"const": "windows" "enum": [
"windows"
]
}, },
{ {
"description": "Linux.", "description": "Linux.",
"type": "string", "type": "string",
"const": "linux" "enum": [
"linux"
]
}, },
{ {
"description": "Android.", "description": "Android.",
"type": "string", "type": "string",
"const": "android" "enum": [
"android"
]
}, },
{ {
"description": "iOS.", "description": "iOS.",
"type": "string", "type": "string",
"const": "iOS" "enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "Enables the authenticate command without any pre-configured scope.",
"type": "string",
"const": "allow-authenticate",
"markdownDescription": "Enables the authenticate command without any pre-configured scope."
},
{
"description": "Denies the authenticate command without any pre-configured scope.",
"type": "string",
"const": "deny-authenticate",
"markdownDescription": "Denies the authenticate command without any pre-configured scope."
},
{
"description": "Enables the status command without any pre-configured scope.",
"type": "string",
"const": "allow-status",
"markdownDescription": "Enables the status command without any pre-configured scope."
},
{
"description": "Denies the status command without any pre-configured scope.",
"type": "string",
"const": "deny-status",
"markdownDescription": "Denies the status command without any pre-configured scope."
},
{
"description": "This permission set configures which\nbiometric features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all biometric commands.\n\n\n#### This default permission set includes:\n\n- `allow-authenticate`\n- `allow-status`",
"type": "string",
"const": "default",
"markdownDescription": "This permission set configures which\nbiometric features are by default exposed.\n\n#### Granted Permissions\n\nIt allows acccess to all biometric commands.\n\n\n#### This default permission set includes:\n\n- `allow-authenticate`\n- `allow-status`"
} }
] ]
} }
-4
View File
@@ -1,9 +1,5 @@
# Changelog # Changelog
## \[2.4.1]
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
## \[2.4.0] ## \[2.4.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6 - [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+5 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-cli" name = "tauri-plugin-cli"
version = "2.4.1" version = "2.4.0"
description = "Parse arguments from your Tauri application's command line interface." description = "Parse arguments from your Tauri application's command line interface."
edition = { workspace = true } edition = { workspace = true }
authors = { workspace = true } authors = { workspace = true }
@@ -9,6 +9,10 @@ rust-version = { workspace = true }
repository = { workspace = true } repository = { workspace = true }
links = "tauri-plugin-cli" links = "tauri-plugin-cli"
[package.metadata.docs.rs]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.platforms.support] [package.metadata.platforms.support]
windows = { level = "full", notes = "" } windows = { level = "full", notes = "" }
linux = { level = "full", notes = "" } linux = { level = "full", notes = "" }
+9
View File
@@ -34,12 +34,21 @@ tauri-plugin-cli = { git = "https://github.com/tauri-apps/plugins-workspace", br
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
```sh ```sh
pnpm add @tauri-apps/plugin-cli pnpm add @tauri-apps/plugin-cli
# or # or
npm add @tauri-apps/plugin-cli npm add @tauri-apps/plugin-cli
# or # or
yarn add @tauri-apps/plugin-cli yarn add @tauri-apps/plugin-cli
# alternatively with Git:
pnpm add https://github.com/tauri-apps/tauri-plugin-cli#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-cli#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-cli#v2
``` ```
## Usage ## Usage
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-cli", "name": "@tauri-apps/plugin-cli",
"version": "2.4.1", "version": "2.4.0",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
"Tauri Programme within The Commons Conservancy" "Tauri Programme within The Commons Conservancy"
@@ -24,6 +24,6 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.10.1" "@tauri-apps/api": "^2.6.0"
} }
} }
+64 -31
View File
@@ -24,17 +24,20 @@
}, },
"permission": { "permission": {
"description": "A list of inlined permissions", "description": "A list of inlined permissions",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/Permission" "$ref": "#/definitions/Permission"
}, }
"default": []
} }
}, },
"definitions": { "definitions": {
"DefaultPermission": { "DefaultPermission": {
"description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
"type": "object", "type": "object",
"required": [
"permissions"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -43,10 +46,10 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -59,14 +62,16 @@
"type": "string" "type": "string"
} }
} }
}, }
"required": [
"permissions"
]
}, },
"PermissionSet": { "PermissionSet": {
"description": "A set of direct permissions grouped together under a new name.", "description": "A set of direct permissions grouped together under a new name.",
"type": "object", "type": "object",
"required": [
"description",
"identifier",
"permissions"
],
"properties": { "properties": {
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
@@ -80,19 +85,17 @@
"description": "All permissions this set contains.", "description": "All permissions this set contains.",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "$ref": "#/definitions/PermissionKind"
}
} }
} }
},
"required": [
"identifier",
"description",
"permissions"
]
}, },
"Permission": { "Permission": {
"description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
"type": "object", "type": "object",
"required": [
"identifier"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -101,14 +104,14 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
"type": "string" "type": "string"
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri internal convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -144,10 +147,7 @@
"$ref": "#/definitions/Target" "$ref": "#/definitions/Target"
} }
} }
}, }
"required": [
"identifier"
]
}, },
"Commands": { "Commands": {
"description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.",
@@ -155,24 +155,24 @@
"properties": { "properties": {
"allow": { "allow": {
"description": "Allowed command.", "description": "Allowed command.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
}, },
"deny": { "deny": {
"description": "Denied command, which takes priority.", "description": "Denied command, which takes priority.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
} }
} }
}, },
"Scopes": { "Scopes": {
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\nThe configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json\n{\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n}\n```", "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object", "type": "object",
"properties": { "properties": {
"allow": { "allow": {
@@ -257,27 +257,60 @@
{ {
"description": "MacOS.", "description": "MacOS.",
"type": "string", "type": "string",
"const": "macOS" "enum": [
"macOS"
]
}, },
{ {
"description": "Windows.", "description": "Windows.",
"type": "string", "type": "string",
"const": "windows" "enum": [
"windows"
]
}, },
{ {
"description": "Linux.", "description": "Linux.",
"type": "string", "type": "string",
"const": "linux" "enum": [
"linux"
]
}, },
{ {
"description": "Android.", "description": "Android.",
"type": "string", "type": "string",
"const": "android" "enum": [
"android"
]
}, },
{ {
"description": "iOS.", "description": "iOS.",
"type": "string", "type": "string",
"const": "iOS" "enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "Enables the cli_matches command without any pre-configured scope.",
"type": "string",
"const": "allow-cli-matches",
"markdownDescription": "Enables the cli_matches command without any pre-configured scope."
},
{
"description": "Denies the cli_matches command without any pre-configured scope.",
"type": "string",
"const": "deny-cli-matches",
"markdownDescription": "Denies the cli_matches command without any pre-configured scope."
},
{
"description": "Allows reading the CLI matches\n#### This default permission set includes:\n\n- `allow-cli-matches`",
"type": "string",
"const": "default",
"markdownDescription": "Allows reading the CLI matches\n#### This default permission set includes:\n\n- `allow-cli-matches`"
} }
] ]
} }
-8
View File
@@ -1,13 +1,5 @@
# Changelog # Changelog
## \[2.3.2]
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
## \[2.3.1]
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
## \[2.3.0] ## \[2.3.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6 - [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+4 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-clipboard-manager" name = "tauri-plugin-clipboard-manager"
version = "2.3.2" version = "2.3.0"
description = "Read and write to the system clipboard." description = "Read and write to the system clipboard."
edition = { workspace = true } edition = { workspace = true }
authors = { workspace = true } authors = { workspace = true }
@@ -10,7 +10,8 @@ repository = { workspace = true }
links = "tauri-plugin-clipboard-manager" links = "tauri-plugin-clipboard-manager"
[package.metadata.docs.rs] [package.metadata.docs.rs]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"] targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
[package.metadata.platforms.support] [package.metadata.platforms.support]
@@ -32,7 +33,7 @@ log = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
[target.'cfg(target_os = "ios")'.dependencies] [target.'cfg(target_os = "ios")'.dependencies]
tauri = { workspace = true } tauri = { workspace = true, features = ["wry"] }
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
arboard = { version = "3", features = ["wayland-data-control"] } arboard = { version = "3", features = ["wayland-data-control"] }
+9
View File
@@ -33,12 +33,21 @@ tauri-plugin-clipboard-manager = { git = "https://github.com/tauri-apps/plugins-
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
```sh ```sh
pnpm add @tauri-apps/plugin-clipboard-manager pnpm add @tauri-apps/plugin-clipboard-manager
# or # or
npm add @tauri-apps/plugin-clipboard-manager npm add @tauri-apps/plugin-clipboard-manager
# or # or
yarn add @tauri-apps/plugin-clipboard-manager yarn add @tauri-apps/plugin-clipboard-manager
# alternatively with Git:
pnpm add https://github.com/tauri-apps/tauri-plugin-clipboard-manager#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-clipboard-manager#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-clipboard-manager#v2
``` ```
## Usage ## Usage
@@ -5,7 +5,7 @@ plugins {
android { android {
namespace = "app.tauri.clipboard" namespace = "app.tauri.clipboard"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-clipboard-manager", "name": "@tauri-apps/plugin-clipboard-manager",
"version": "2.3.2", "version": "2.3.0",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
"Tauri Programme within The Commons Conservancy" "Tauri Programme within The Commons Conservancy"
@@ -24,6 +24,6 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.10.1" "@tauri-apps/api": "^2.6.0"
} }
} }
@@ -24,17 +24,20 @@
}, },
"permission": { "permission": {
"description": "A list of inlined permissions", "description": "A list of inlined permissions",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/Permission" "$ref": "#/definitions/Permission"
}, }
"default": []
} }
}, },
"definitions": { "definitions": {
"DefaultPermission": { "DefaultPermission": {
"description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
"type": "object", "type": "object",
"required": [
"permissions"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -43,10 +46,10 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -59,14 +62,16 @@
"type": "string" "type": "string"
} }
} }
}, }
"required": [
"permissions"
]
}, },
"PermissionSet": { "PermissionSet": {
"description": "A set of direct permissions grouped together under a new name.", "description": "A set of direct permissions grouped together under a new name.",
"type": "object", "type": "object",
"required": [
"description",
"identifier",
"permissions"
],
"properties": { "properties": {
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
@@ -80,19 +85,17 @@
"description": "All permissions this set contains.", "description": "All permissions this set contains.",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "$ref": "#/definitions/PermissionKind"
}
} }
} }
},
"required": [
"identifier",
"description",
"permissions"
]
}, },
"Permission": { "Permission": {
"description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
"type": "object", "type": "object",
"required": [
"identifier"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -101,14 +104,14 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
"type": "string" "type": "string"
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri internal convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -144,10 +147,7 @@
"$ref": "#/definitions/Target" "$ref": "#/definitions/Target"
} }
} }
}, }
"required": [
"identifier"
]
}, },
"Commands": { "Commands": {
"description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.",
@@ -155,24 +155,24 @@
"properties": { "properties": {
"allow": { "allow": {
"description": "Allowed command.", "description": "Allowed command.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
}, },
"deny": { "deny": {
"description": "Denied command, which takes priority.", "description": "Denied command, which takes priority.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
} }
} }
}, },
"Scopes": { "Scopes": {
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\nThe configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json\n{\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n}\n```", "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object", "type": "object",
"properties": { "properties": {
"allow": { "allow": {
@@ -257,27 +257,120 @@
{ {
"description": "MacOS.", "description": "MacOS.",
"type": "string", "type": "string",
"const": "macOS" "enum": [
"macOS"
]
}, },
{ {
"description": "Windows.", "description": "Windows.",
"type": "string", "type": "string",
"const": "windows" "enum": [
"windows"
]
}, },
{ {
"description": "Linux.", "description": "Linux.",
"type": "string", "type": "string",
"const": "linux" "enum": [
"linux"
]
}, },
{ {
"description": "Android.", "description": "Android.",
"type": "string", "type": "string",
"const": "android" "enum": [
"android"
]
}, },
{ {
"description": "iOS.", "description": "iOS.",
"type": "string", "type": "string",
"const": "iOS" "enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "Enables the clear command without any pre-configured scope.",
"type": "string",
"const": "allow-clear",
"markdownDescription": "Enables the clear command without any pre-configured scope."
},
{
"description": "Denies the clear command without any pre-configured scope.",
"type": "string",
"const": "deny-clear",
"markdownDescription": "Denies the clear command without any pre-configured scope."
},
{
"description": "Enables the read_image command without any pre-configured scope.",
"type": "string",
"const": "allow-read-image",
"markdownDescription": "Enables the read_image command without any pre-configured scope."
},
{
"description": "Denies the read_image command without any pre-configured scope.",
"type": "string",
"const": "deny-read-image",
"markdownDescription": "Denies the read_image command without any pre-configured scope."
},
{
"description": "Enables the read_text command without any pre-configured scope.",
"type": "string",
"const": "allow-read-text",
"markdownDescription": "Enables the read_text command without any pre-configured scope."
},
{
"description": "Denies the read_text command without any pre-configured scope.",
"type": "string",
"const": "deny-read-text",
"markdownDescription": "Denies the read_text command without any pre-configured scope."
},
{
"description": "Enables the write_html command without any pre-configured scope.",
"type": "string",
"const": "allow-write-html",
"markdownDescription": "Enables the write_html command without any pre-configured scope."
},
{
"description": "Denies the write_html command without any pre-configured scope.",
"type": "string",
"const": "deny-write-html",
"markdownDescription": "Denies the write_html command without any pre-configured scope."
},
{
"description": "Enables the write_image command without any pre-configured scope.",
"type": "string",
"const": "allow-write-image",
"markdownDescription": "Enables the write_image command without any pre-configured scope."
},
{
"description": "Denies the write_image command without any pre-configured scope.",
"type": "string",
"const": "deny-write-image",
"markdownDescription": "Denies the write_image command without any pre-configured scope."
},
{
"description": "Enables the write_text command without any pre-configured scope.",
"type": "string",
"const": "allow-write-text",
"markdownDescription": "Enables the write_text command without any pre-configured scope."
},
{
"description": "Denies the write_text command without any pre-configured scope.",
"type": "string",
"const": "deny-write-text",
"markdownDescription": "Denies the write_text command without any pre-configured scope."
},
{
"description": "No features are enabled by default, as we believe\nthe clipboard can be inherently dangerous and it is \napplication specific if read and/or write access is needed.\n\nClipboard interaction needs to be explicitly enabled.\n",
"type": "string",
"const": "default",
"markdownDescription": "No features are enabled by default, as we believe\nthe clipboard can be inherently dangerous and it is \napplication specific if read and/or write access is needed.\n\nClipboard interaction needs to be explicitly enabled.\n"
} }
] ]
} }
-25
View File
@@ -1,30 +1,5 @@
# Changelog # Changelog
## \[2.4.7]
- [`8374e997`](https://github.com/tauri-apps/plugins-workspace/commit/8374e997b82c95516fc0c1f6d665d9fc3b52edf8) ([#3258](https://github.com/tauri-apps/plugins-workspace/pull/3258) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Fix runtime deep link registration failing on Linux when the app path has spaces.
## \[2.4.6]
- [`28048039`](https://github.com/tauri-apps/plugins-workspace/commit/28048039496e84b46847c008416d341f1349e30e) ([#3143](https://github.com/tauri-apps/plugins-workspace/pull/3143) by [@Tunglies](https://github.com/tauri-apps/plugins-workspace/../../Tunglies)) Fix clippy warnings. No user facing changes.
## \[2.4.5]
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
## \[2.4.4]
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
- [`e25a9339`](https://github.com/tauri-apps/plugins-workspace/commit/e25a9339f46268f70dc9afd0c5ab3decbf79b330) ([#3019](https://github.com/tauri-apps/plugins-workspace/pull/3019) by [@kevinschoonover](https://github.com/tauri-apps/plugins-workspace/../../kevinschoonover)) Fix Exec= field in desktop handler if executable path changes
## \[2.4.3]
- [`2522b71f`](https://github.com/tauri-apps/plugins-workspace/commit/2522b71f6bcae65c03b24415eb9295c9e7c84ffc) ([#2970](https://github.com/tauri-apps/plugins-workspace/pull/2970) by [@WSH032](https://github.com/tauri-apps/plugins-workspace/../../WSH032)) Revert the breaking change introduced by [#2928](https://github.com/tauri-apps/plugins-workspace/pull/2928).
## \[2.4.2]
- [`21d721a0`](https://github.com/tauri-apps/plugins-workspace/commit/21d721a0c2731fc201872f5b99ea8bbdc61b0b60) ([#2928](https://github.com/tauri-apps/plugins-workspace/pull/2928) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Linux, improved error messages when OS commands fail.
## \[2.4.1] ## \[2.4.1]
- [`d4f8299b`](https://github.com/tauri-apps/plugins-workspace/commit/d4f8299b12f107718c70692840a63768d65baaf9) ([#2844](https://github.com/tauri-apps/plugins-workspace/pull/2844) by [@yobson1](https://github.com/tauri-apps/plugins-workspace/../../yobson1)) Fix deep link protocol handler not set as default on linux - [`d4f8299b`](https://github.com/tauri-apps/plugins-workspace/commit/d4f8299b12f107718c70692840a63768d65baaf9) ([#2844](https://github.com/tauri-apps/plugins-workspace/pull/2844) by [@yobson1](https://github.com/tauri-apps/plugins-workspace/../../yobson1)) Fix deep link protocol handler not set as default on linux
+3 -4
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-deep-link" name = "tauri-plugin-deep-link"
version = "2.4.7" version = "2.4.1"
description = "Set your Tauri application as the default handler for an URL" description = "Set your Tauri application as the default handler for an URL"
authors = { workspace = true } authors = { workspace = true }
license = { workspace = true } license = { workspace = true }
@@ -10,6 +10,8 @@ repository = { workspace = true }
links = "tauri-plugin-deep-link" links = "tauri-plugin-deep-link"
[package.metadata.docs.rs] [package.metadata.docs.rs]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
targets = ["x86_64-linux-android"] targets = ["x86_64-linux-android"]
[package.metadata.platforms.support] [package.metadata.platforms.support]
@@ -25,9 +27,6 @@ serde_json = { workspace = true }
tauri-utils = { workspace = true } tauri-utils = { workspace = true }
tauri-plugin = { workspace = true, features = ["build"] } tauri-plugin = { workspace = true, features = ["build"] }
[target."cfg(target_os = \"macos\")".build-dependencies]
plist = "1"
[dependencies] [dependencies]
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
+9
View File
@@ -33,12 +33,21 @@ tauri-plugin-deep-link = { git = "https://github.com/tauri-apps/plugins-workspac
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
```sh ```sh
pnpm add @tauri-apps/plugin-deep-link pnpm add @tauri-apps/plugin-deep-link
# or # or
npm add @tauri-apps/plugin-deep-link npm add @tauri-apps/plugin-deep-link
# or # or
yarn add @tauri-apps/plugin-deep-link yarn add @tauri-apps/plugin-deep-link
# alternatively with Git:
pnpm add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
``` ```
## Setting up ## Setting up
+1 -1
View File
@@ -5,7 +5,7 @@ plugins {
android { android {
namespace = "app.tauri.deep_link" namespace = "app.tauri.deep_link"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
@@ -6,8 +6,9 @@ package app.tauri.deep_link
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.PatternMatcher import android.os.Bundle
import android.webkit.WebView import android.webkit.WebView
import app.tauri.Logger
import app.tauri.annotation.InvokeArg import app.tauri.annotation.InvokeArg
import app.tauri.annotation.Command import app.tauri.annotation.Command
import app.tauri.annotation.TauriPlugin import app.tauri.annotation.TauriPlugin
@@ -15,35 +16,18 @@ import app.tauri.plugin.Channel
import app.tauri.plugin.JSObject import app.tauri.plugin.JSObject
import app.tauri.plugin.Plugin import app.tauri.plugin.Plugin
import app.tauri.plugin.Invoke import app.tauri.plugin.Invoke
import androidx.core.net.toUri
@InvokeArg @InvokeArg
class SetEventHandlerArgs { class SetEventHandlerArgs {
lateinit var handler: Channel lateinit var handler: Channel
} }
@InvokeArg
class AssociatedDomain {
var scheme: List<String> = listOf("https", "http")
var host: String? = null
var path: List<String> = listOf()
var pathPattern: List<String> = listOf()
var pathPrefix: List<String> = listOf()
var pathSuffix: List<String> = listOf()
}
@InvokeArg
class PluginConfig {
var mobile: List<AssociatedDomain> = listOf()
}
@TauriPlugin @TauriPlugin
class DeepLinkPlugin(private val activity: Activity): Plugin(activity) { class DeepLinkPlugin(private val activity: Activity): Plugin(activity) {
//private val implementation = Example() //private val implementation = Example()
private var webView: WebView? = null private var webView: WebView? = null
private var currentUrl: String? = null private var currentUrl: String? = null
private var channel: Channel? = null private var channel: Channel? = null
private var config: PluginConfig? = null
companion object { companion object {
var instance: DeepLinkPlugin? = null var instance: DeepLinkPlugin? = null
@@ -67,105 +51,27 @@ class DeepLinkPlugin(private val activity: Activity): Plugin(activity) {
override fun load(webView: WebView) { override fun load(webView: WebView) {
instance = this instance = this
config = getConfig(PluginConfig::class.java)
super.load(webView)
this.webView = webView
val intent = activity.intent val intent = activity.intent
if (intent.action == Intent.ACTION_VIEW && intent.data != null) { if (intent.action == Intent.ACTION_VIEW) {
val url = intent.data.toString()
if (isDeepLink(url)) {
// TODO: check if it makes sense to split up init url and last url // TODO: check if it makes sense to split up init url and last url
this.currentUrl = url this.currentUrl = intent.data.toString()
val event = JSObject() val event = JSObject()
event.put("url", this.currentUrl) event.put("url", this.currentUrl)
this.channel?.send(event) this.channel?.send(event)
} }
}
super.load(webView)
this.webView = webView
} }
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
if (intent.action == Intent.ACTION_VIEW && intent.data != null) { if (intent.action == Intent.ACTION_VIEW) {
val url = intent.data.toString() this.currentUrl = intent.data.toString()
if (isDeepLink(url)) {
this.currentUrl = url
val event = JSObject() val event = JSObject()
event.put("url", this.currentUrl) event.put("url", this.currentUrl)
this.channel?.send(event) this.channel?.send(event)
} }
} }
} }
private fun isDeepLink(url: String): Boolean {
val config = this.config ?: return false
if (config.mobile.isEmpty()) {
return false
}
val uri = try {
url.toUri()
} catch (_: Exception) {
// not a URL
return false
}
val scheme = uri.scheme ?: return false
val host = uri.host
val path = uri.path ?: ""
// Check if URL matches any configured mobile deep link
for (domain in config.mobile) {
// Check scheme
if (!domain.scheme.any { it.equals(scheme, ignoreCase = true) }) {
continue
}
// Check host (if configured)
if (domain.host != null) {
if (!host.equals(domain.host, ignoreCase = true)) {
continue
}
}
// Check path constraints
// According to Android docs:
// - path: exact match, must begin with /
// - pathPrefix: matches initial part of path
// - pathSuffix: matches ending part, doesn't need to begin with /
// - pathPattern: simple glob pattern (., *, .*)
val pathMatches = when {
// Exact path match (must begin with /)
domain.path.isNotEmpty() && domain.path.any { it == path } -> true
// Path pattern match (simple glob: ., *, .*)
domain.pathPattern.isNotEmpty() && domain.pathPattern.any { pattern ->
try {
PatternMatcher(pattern, PatternMatcher.PATTERN_SIMPLE_GLOB).match(path)
} catch (e: Exception) {
false
}
} -> true
// Path prefix match
domain.pathPrefix.isNotEmpty() && domain.pathPrefix.any { prefix ->
path.startsWith(prefix)
} -> true
// Path suffix match
domain.pathSuffix.isNotEmpty() && domain.pathSuffix.any { suffix ->
path.endsWith(suffix)
} -> true
// If no path constraints, any path is allowed
domain.path.isEmpty() && domain.pathPattern.isEmpty() &&
domain.pathPrefix.isEmpty() && domain.pathSuffix.isEmpty() -> true
else -> false
}
if (pathMatches) {
return true
}
}
return false
}
}
+16 -103
View File
@@ -10,64 +10,50 @@ const COMMANDS: &[&str] = &["get_current", "register", "unregister", "is_registe
// TODO: Consider using activity-alias in case users may have multiple activities in their app. // TODO: Consider using activity-alias in case users may have multiple activities in their app.
fn intent_filter(domain: &AssociatedDomain) -> String { fn intent_filter(domain: &AssociatedDomain) -> String {
let host = domain
.host
.as_ref()
.map(|h| format!(r#"<data android:host="{h}" />"#))
.unwrap_or_default();
let auto_verify = if domain.is_app_link() {
r#"android:autoVerify="true" "#.to_string()
} else {
String::new()
};
format!( format!(
r#"<intent-filter {auto_verify}> r#"<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
{schemes} {}
{host} <data android:host="{}" />
{domains} {}
{path_patterns} {}
{path_prefixes} {}
{path_suffixes} {}
</intent-filter>"#, </intent-filter>"#,
schemes = domain domain
.scheme .scheme
.iter() .iter()
.map(|scheme| format!(r#"<data android:scheme="{scheme}" />"#)) .map(|scheme| format!(r#"<data android:scheme="{scheme}" />"#))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n "), .join("\n "),
host = host, domain.host,
domains = domain domain
.path .path
.iter() .iter()
.map(|path| format!(r#"<data android:path="{path}" />"#)) .map(|path| format!(r#"<data android:path="{path}" />"#))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n "), .join("\n "),
path_patterns = domain domain
.path_pattern .path_pattern
.iter() .iter()
.map(|pattern| format!(r#"<data android:pathPattern="{pattern}" />"#)) .map(|pattern| format!(r#"<data android:pathPattern="{pattern}" />"#))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n "), .join("\n "),
path_prefixes = domain domain
.path_prefix .path_prefix
.iter() .iter()
.map(|prefix| format!(r#"<data android:pathPrefix="{prefix}" />"#)) .map(|prefix| format!(r#"<data android:pathPrefix="{prefix}" />"#))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n "), .join("\n "),
path_suffixes = domain domain
.path_suffix .path_suffix
.iter() .iter()
.map(|suffix| format!(r#"<data android:pathSuffix="{suffix}" />"#)) .map(|suffix| format!(r#"<data android:pathSuffix="{suffix}" />"#))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n "), .join("\n "),
) )
.trim()
.to_string()
} }
fn main() { fn main() {
@@ -82,16 +68,6 @@ fn main() {
} }
if let Some(config) = tauri_plugin::plugin_config::<Config>("deep-link") { if let Some(config) = tauri_plugin::plugin_config::<Config>("deep-link") {
let errors: Vec<String> = config
.mobile
.iter()
.filter_map(|d| d.validate().err())
.collect();
if !errors.is_empty() {
panic!("Deep link config validation failed:\n{}", errors.join("\n"));
}
tauri_plugin::mobile::update_android_manifest( tauri_plugin::mobile::update_android_manifest(
"DEEP LINK PLUGIN", "DEEP LINK PLUGIN",
"activity", "activity",
@@ -104,83 +80,20 @@ fn main() {
) )
.expect("failed to rewrite AndroidManifest.xml"); .expect("failed to rewrite AndroidManifest.xml");
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(target_os = "macos")]
{ {
// we need to ensure that the entitlements are only
// generated for explicit app links and not
// other deep links because then they
// are just going to complain and not be built or signed
let has_app_links = config.mobile.iter().any(|d| d.is_app_link());
if !has_app_links {
tauri_plugin::mobile::update_entitlements(|entitlements| {
entitlements.remove("com.apple.developer.associated-domains");
})
.expect("failed to update entitlements");
} else {
tauri_plugin::mobile::update_entitlements(|entitlements| { tauri_plugin::mobile::update_entitlements(|entitlements| {
entitlements.insert( entitlements.insert(
"com.apple.developer.associated-domains".into(), "com.apple.developer.associated-domains".into(),
config config
.mobile .mobile
.iter() .into_iter()
.filter(|d| d.is_app_link()) .map(|d| format!("applinks:{}", d.host).into())
.filter_map(|d| d.host.as_ref())
.map(|host| format!("applinks:{}", host).into())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into(), .into(),
); );
}) })
.expect("failed to update entitlements"); .expect("failed to update entitlements");
} }
let deep_link_domains = config
.mobile
.iter()
.filter(|domain| domain.is_app_link())
.collect::<Vec<_>>();
if deep_link_domains.is_empty() {
tauri_plugin::mobile::update_info_plist(|info_plist| {
info_plist.remove("CFBundleURLTypes");
})
.expect("failed to update Info.plist");
} else {
tauri_plugin::mobile::update_info_plist(|info_plist| {
info_plist.insert(
"CFBundleURLTypes".into(),
deep_link_domains
.iter()
.map(|domain| {
let schemes = domain
.scheme
.iter()
.filter(|scheme| {
scheme.as_str() != "https" && scheme.as_str() != "http"
})
.collect::<Vec<_>>();
let mut dict = plist::Dictionary::new();
dict.insert(
"CFBundleURLSchemes".into(),
schemes
.iter()
.map(|s| s.to_string().into())
.collect::<Vec<_>>()
.into(),
);
dict.insert(
"CFBundleURLName".into(),
domain.scheme[0].clone().into(),
);
plist::Value::Dictionary(dict)
})
.collect::<Vec<_>>()
.into(),
);
})
.expect("failed to update Info.plist");
}
}
} }
} }
@@ -1,41 +1,5 @@
# Changelog # Changelog
## \[2.2.10]
### Dependencies
- Upgraded to `deep-link-js@2.4.7`
## \[2.2.9]
### Dependencies
- Upgraded to `deep-link-js@2.4.6`
## \[2.2.8]
### Dependencies
- Upgraded to `deep-link-js@2.4.5`
## \[2.2.7]
### Dependencies
- Upgraded to `deep-link-js@2.4.4`
## \[2.2.6]
### Dependencies
- Upgraded to `deep-link-js@2.4.3`
## \[2.2.5]
### Dependencies
- Upgraded to `deep-link-js@2.4.2`
## \[2.2.4] ## \[2.2.4]
### Dependencies ### Dependencies
+5 -5
View File
@@ -1,7 +1,7 @@
{ {
"name": "deep-link-example", "name": "deep-link-example",
"private": true, "private": true,
"version": "2.2.10", "version": "2.2.4",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -10,12 +10,12 @@
"tauri": "tauri" "tauri": "tauri"
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.10.1", "@tauri-apps/api": "2.7.0",
"@tauri-apps/plugin-deep-link": "2.4.7" "@tauri-apps/plugin-deep-link": "2.4.1"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "2.10.1", "@tauri-apps/cli": "2.7.1",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"vite": "^7.3.1" "vite": "^7.0.4"
} }
} }
@@ -19,9 +19,7 @@ tauri-build = { workspace = true }
[dependencies] [dependencies]
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
tauri = { workspace = true } tauri = { workspace = true, features = ["wry", "common-controls-v6", "x11"] }
tauri-runtime-wry = { workspace = true, optional = true }
tauri-runtime-cef = { workspace = true, optional = true }
tauri-plugin-deep-link = { path = "../../../" } tauri-plugin-deep-link = { path = "../../../" }
tauri-plugin-log = { path = "../../../../log" } tauri-plugin-log = { path = "../../../../log" }
tauri-plugin-single-instance = { path = "../../../../single-instance", features = [ tauri-plugin-single-instance = { path = "../../../../single-instance", features = [
@@ -30,9 +28,6 @@ tauri-plugin-single-instance = { path = "../../../../single-instance", features
log = "0.4" log = "0.4"
[features] [features]
default = ["wry"]
wry = ["dep:tauri-runtime-wry"]
cef = ["dep:tauri-runtime-cef"]
# this feature is used for production builds or when `devUrl` points to the filesystem and the built-in dev server is disabled. # this feature is used for production builds or when `devUrl` points to the filesystem and the built-in dev server is disabled.
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes. # If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
# DO NOT REMOVE!! # DO NOT REMOVE!!
@@ -14,13 +14,13 @@ val tauriProperties = Properties().apply {
} }
android { android {
compileSdk = 36 compileSdk = 34
namespace = "com.tauri.deep_link_example" namespace = "com.tauri.deep_link_example"
defaultConfig { defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false" manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.tauri.deep_link_example" applicationId = "com.tauri.deep_link_example"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 34
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
} }
@@ -58,10 +58,9 @@ rust {
} }
dependencies { dependencies {
implementation("androidx.webkit:webkit:1.14.0") implementation("androidx.webkit:webkit:1.6.1")
implementation("androidx.appcompat:appcompat:1.7.1") implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.activity:activity-ktx:1.10.1") implementation("com.google.android.material:material:1.8.0")
implementation("com.google.android.material:material:1.12.0")
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4") androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
@@ -27,36 +27,19 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:scheme="http" /> <data android:scheme="http" />
<data android:scheme="https" />
<data android:host="fabianlars.de" /> <data android:host="fabianlars.de" />
<data android:pathPrefix="/intent" /> <data android:pathPrefix="/intent" />
</intent-filter> </intent-filter>
<intent-filter android:autoVerify="true"> <intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:scheme="http" /> <data android:scheme="http" />
<data android:scheme="https" />
<data android:host="tauri.app" /> <data android:host="tauri.app" />
</intent-filter>
<intent-filter >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="taurideeplink" />
</intent-filter> </intent-filter>
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. --> <!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
</activity> </activity>
@@ -1,11 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package com.tauri.deep_link_example package com.tauri.deep_link_example
import android.os.Bundle class MainActivity : TauriActivity()
import androidx.activity.enableEdgeToEdge
class MainActivity : TauriActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
}
}
@@ -4,7 +4,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:8.11.0") classpath("com.android.tools.build:gradle:8.5.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
} }
} }
@@ -18,6 +18,6 @@ repositories {
dependencies { dependencies {
compileOnly(gradleApi()) compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:8.11.0") implementation("com.android.tools.build:gradle:8.5.1")
} }
@@ -1,6 +1,6 @@
#Tue May 10 19:22:52 CST 2022 #Tue May 10 19:22:52 CST 2022
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17150" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17150" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17122"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17122"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
@@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 63; objectVersion = 56;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@@ -167,8 +167,6 @@
dependencies = ( dependencies = (
); );
name = "deep-link-example_iOS"; name = "deep-link-example_iOS";
packageProductDependencies = (
);
productName = "deep-link-example_iOS"; productName = "deep-link-example_iOS";
productReference = 1CAAFA750FD735A285DC1238 /* deep-link-example.app */; productReference = 1CAAFA750FD735A285DC1238 /* deep-link-example.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
@@ -191,7 +189,6 @@
en, en,
); );
mainGroup = 1DC58B1705AA3ECC6B887FE7; mainGroup = 1DC58B1705AA3ECC6B887FE7;
minimizedProjectReferenceProxies = 1;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
@@ -230,6 +227,7 @@
outputPaths = ( outputPaths = (
"$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a", "$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a",
"$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a", "$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a",
"$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
@@ -316,13 +314,18 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ARCHS = arm64; ARCHS = (
arm64,
"arm64-sim",
);
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements"; CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = "Q93MBH6S2F"; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = Q93MBH6S2F;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; "EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"\".\"", "\".\"",
@@ -332,6 +335,13 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = (
"$(inherited)",
"$(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION)",
"$(SDKROOT)/usr/lib/swift",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
"LIBRARY_SEARCH_PATHS[arch=arm64]" = ( "LIBRARY_SEARCH_PATHS[arch=arm64]" = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)", "$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
@@ -350,7 +360,7 @@
PRODUCT_NAME = "deep-link-example"; PRODUCT_NAME = "deep-link-example";
SDKROOT = iphoneos; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALID_ARCHS = arm64; VALID_ARCHS = "arm64 arm64-sim";
}; };
name = debug; name = debug;
}; };
@@ -414,13 +424,18 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ARCHS = arm64; ARCHS = (
arm64,
"arm64-sim",
);
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements"; CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = "Q93MBH6S2F"; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = Q93MBH6S2F;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; "EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"\".\"", "\".\"",
@@ -430,6 +445,13 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = (
"$(inherited)",
"$(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION)",
"$(SDKROOT)/usr/lib/swift",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
"LIBRARY_SEARCH_PATHS[arch=arm64]" = ( "LIBRARY_SEARCH_PATHS[arch=arm64]" = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)", "$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
@@ -448,7 +470,7 @@
PRODUCT_NAME = "deep-link-example"; PRODUCT_NAME = "deep-link-example";
SDKROOT = iphoneos; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALID_ARCHS = arm64; VALID_ARCHS = "arm64 arm64-sim";
}; };
name = release; name = release;
}; };
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.1.0</string> <string>0.0.0</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.1.0</string> <string>0.1.0</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
@@ -40,16 +40,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>taurideeplink</string>
</array>
<key>CFBundleURLName</key>
<string>taurideeplink</string>
</dict>
</array>
</dict> </dict>
</plist> </plist>
@@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: deep-link-example name: deep-link-example
options: options:
bundleIdPrefix: com.tauri.deep-link-example bundleIdPrefix: com.tauri.deep-link-example
@@ -12,6 +16,7 @@ settingGroups:
base: base:
PRODUCT_NAME: deep-link-example PRODUCT_NAME: deep-link-example
PRODUCT_BUNDLE_IDENTIFIER: com.tauri.deep-link-example PRODUCT_BUNDLE_IDENTIFIER: com.tauri.deep-link-example
DEVELOPMENT_TEAM: Q93MBH6S2F
targetTemplates: targetTemplates:
app: app:
type: application type: application
@@ -51,8 +56,8 @@ targets:
- UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationLandscapeRight
CFBundleShortVersionString: 0.1.0 CFBundleShortVersionString: 0.0.0
CFBundleVersion: '0.1.0' CFBundleVersion: 0.0.0
entitlements: entitlements:
path: deep-link-example_iOS/deep-link-example_iOS.entitlements path: deep-link-example_iOS/deep-link-example_iOS.entitlements
scheme: scheme:
@@ -62,12 +67,14 @@ targets:
settings: settings:
base: base:
ENABLE_BITCODE: false ENABLE_BITCODE: false
ARCHS: [arm64] ARCHS: [arm64, arm64-sim]
VALID_ARCHS: arm64 VALID_ARCHS: arm64 arm64-sim
LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
LIBRARY_SEARCH_PATHS[arch=arm64-sim]: $(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true
EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64 EXCLUDED_ARCHS[sdk=iphonesimulator*]: arm64
EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64
groups: [app] groups: [app]
dependencies: dependencies:
- framework: libapp.a - framework: libapp.a
@@ -86,3 +93,4 @@ targets:
outputFiles: outputFiles:
- $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a - $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a
- $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a - $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a
- $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a
@@ -2,11 +2,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#[cfg(feature = "cef")]
type TauriRuntime = tauri_runtime_cef::CefRuntime<tauri::EventLoopMessage>;
#[cfg(feature = "wry")]
type TauriRuntime = tauri_runtime_wry::Wry<tauri::EventLoopMessage>;
use tauri_plugin_deep_link::DeepLinkExt; use tauri_plugin_deep_link::DeepLinkExt;
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
@@ -18,7 +13,7 @@ fn greet(name: &str) -> String {
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut builder = tauri::Builder::<TauriRuntime>::new(); let mut builder = tauri::Builder::default();
#[cfg(desktop)] #[cfg(desktop)]
{ {
@@ -35,9 +35,6 @@
}, },
{ {
"host": "tauri.app" "host": "tauri.app"
},
{
"scheme": ["taurideeplink"]
} }
], ],
"desktop": { "desktop": {
+2 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-deep-link", "name": "@tauri-apps/plugin-deep-link",
"version": "2.4.7", "version": "2.4.1",
"description": "Set your Tauri application as the default handler for an URL", "description": "Set your Tauri application as the default handler for an URL",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
@@ -25,9 +25,6 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.10.1" "@tauri-apps/api": "^2.6.0"
},
"devDependencies": {
"@tauri-apps/cli": "2.10.1"
} }
} }
+100 -31
View File
@@ -24,17 +24,20 @@
}, },
"permission": { "permission": {
"description": "A list of inlined permissions", "description": "A list of inlined permissions",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/Permission" "$ref": "#/definitions/Permission"
}, }
"default": []
} }
}, },
"definitions": { "definitions": {
"DefaultPermission": { "DefaultPermission": {
"description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
"type": "object", "type": "object",
"required": [
"permissions"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -43,10 +46,10 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -59,14 +62,16 @@
"type": "string" "type": "string"
} }
} }
}, }
"required": [
"permissions"
]
}, },
"PermissionSet": { "PermissionSet": {
"description": "A set of direct permissions grouped together under a new name.", "description": "A set of direct permissions grouped together under a new name.",
"type": "object", "type": "object",
"required": [
"description",
"identifier",
"permissions"
],
"properties": { "properties": {
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
@@ -80,19 +85,17 @@
"description": "All permissions this set contains.", "description": "All permissions this set contains.",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "$ref": "#/definitions/PermissionKind"
}
} }
} }
},
"required": [
"identifier",
"description",
"permissions"
]
}, },
"Permission": { "Permission": {
"description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
"type": "object", "type": "object",
"required": [
"identifier"
],
"properties": { "properties": {
"version": { "version": {
"description": "The version of the permission.", "description": "The version of the permission.",
@@ -101,14 +104,14 @@
"null" "null"
], ],
"format": "uint64", "format": "uint64",
"minimum": 1 "minimum": 1.0
}, },
"identifier": { "identifier": {
"description": "A unique identifier for the permission.", "description": "A unique identifier for the permission.",
"type": "string" "type": "string"
}, },
"description": { "description": {
"description": "Human-readable description of what the permission does.\nTauri internal convention is to use `<h4>` headings in markdown content\nfor Tauri documentation generation purposes.", "description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -144,10 +147,7 @@
"$ref": "#/definitions/Target" "$ref": "#/definitions/Target"
} }
} }
}, }
"required": [
"identifier"
]
}, },
"Commands": { "Commands": {
"description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.",
@@ -155,24 +155,24 @@
"properties": { "properties": {
"allow": { "allow": {
"description": "Allowed command.", "description": "Allowed command.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
}, },
"deny": { "deny": {
"description": "Denied command, which takes priority.", "description": "Denied command, which takes priority.",
"default": [],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
}, }
"default": []
} }
} }
}, },
"Scopes": { "Scopes": {
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\nThe configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json\n{\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n}\n```", "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
"type": "object", "type": "object",
"properties": { "properties": {
"allow": { "allow": {
@@ -257,27 +257,96 @@
{ {
"description": "MacOS.", "description": "MacOS.",
"type": "string", "type": "string",
"const": "macOS" "enum": [
"macOS"
]
}, },
{ {
"description": "Windows.", "description": "Windows.",
"type": "string", "type": "string",
"const": "windows" "enum": [
"windows"
]
}, },
{ {
"description": "Linux.", "description": "Linux.",
"type": "string", "type": "string",
"const": "linux" "enum": [
"linux"
]
}, },
{ {
"description": "Android.", "description": "Android.",
"type": "string", "type": "string",
"const": "android" "enum": [
"android"
]
}, },
{ {
"description": "iOS.", "description": "iOS.",
"type": "string", "type": "string",
"const": "iOS" "enum": [
"iOS"
]
}
]
},
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "Enables the get_current command without any pre-configured scope.",
"type": "string",
"const": "allow-get-current",
"markdownDescription": "Enables the get_current command without any pre-configured scope."
},
{
"description": "Denies the get_current command without any pre-configured scope.",
"type": "string",
"const": "deny-get-current",
"markdownDescription": "Denies the get_current command without any pre-configured scope."
},
{
"description": "Enables the is_registered command without any pre-configured scope.",
"type": "string",
"const": "allow-is-registered",
"markdownDescription": "Enables the is_registered command without any pre-configured scope."
},
{
"description": "Denies the is_registered command without any pre-configured scope.",
"type": "string",
"const": "deny-is-registered",
"markdownDescription": "Denies the is_registered command without any pre-configured scope."
},
{
"description": "Enables the register command without any pre-configured scope.",
"type": "string",
"const": "allow-register",
"markdownDescription": "Enables the register command without any pre-configured scope."
},
{
"description": "Denies the register command without any pre-configured scope.",
"type": "string",
"const": "deny-register",
"markdownDescription": "Denies the register command without any pre-configured scope."
},
{
"description": "Enables the unregister command without any pre-configured scope.",
"type": "string",
"const": "allow-unregister",
"markdownDescription": "Enables the unregister command without any pre-configured scope."
},
{
"description": "Denies the unregister command without any pre-configured scope.",
"type": "string",
"const": "deny-unregister",
"markdownDescription": "Denies the unregister command without any pre-configured scope."
},
{
"description": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`",
"type": "string",
"const": "default",
"markdownDescription": "Allows reading the opened deep link via the get_current command\n#### This default permission set includes:\n\n- `allow-get-current`"
} }
] ]
} }
+11 -45
View File
@@ -11,8 +11,10 @@ use tauri_utils::config::DeepLinkProtocol;
pub struct AssociatedDomain { pub struct AssociatedDomain {
#[serde(default = "default_schemes")] #[serde(default = "default_schemes")]
pub scheme: Vec<String>, pub scheme: Vec<String>,
#[serde(default, deserialize_with = "deserialize_associated_host")]
pub host: Option<String>, // Optional custom uri schemes dont NEED a host (may have one still), but required for https/http schemes #[serde(deserialize_with = "deserialize_associated_host")]
pub host: String,
#[serde(default)] #[serde(default)]
pub path: Vec<String>, pub path: Vec<String>,
#[serde(default, alias = "path-pattern", rename = "pathPattern")] #[serde(default, alias = "path-pattern", rename = "pathPattern")]
@@ -21,41 +23,6 @@ pub struct AssociatedDomain {
pub path_prefix: Vec<String>, pub path_prefix: Vec<String>,
#[serde(default, alias = "path-suffix", rename = "pathSuffix")] #[serde(default, alias = "path-suffix", rename = "pathSuffix")]
pub path_suffix: Vec<String>, pub path_suffix: Vec<String>,
#[serde(default, alias = "app-link", rename = "appLink")]
pub app_link: Option<bool>,
}
impl AssociatedDomain {
/// Returns true if the domain uses http or https scheme.
pub fn is_web_link(&self) -> bool {
self.scheme.iter().any(|s| s == "https" || s == "http")
}
/// Returns true if the domain uses http or https scheme and has proper host configuration.
pub fn is_app_link(&self) -> bool {
self.app_link
.unwrap_or_else(|| self.is_web_link() && self.host.is_some())
}
pub fn validate(&self) -> Result<(), String> {
// Rule 1: All web links require a host.
if self.is_web_link() && self.host.is_none() {
return Err("Web link requires a host".into());
}
// Rule 2: If it's an App Link, ensure http(s) and host.
if self.is_app_link() {
if !self.is_web_link() {
return Err("AppLink must be a valid web link (https/http + host)".into());
}
if self.scheme.iter().any(|s| s == "http") && !self.scheme.iter().any(|s| s == "https")
{
eprintln!("Warning: AppLink uses only 'http' — allowed on Android but not secure for production.");
}
}
Ok(())
}
} }
// TODO: Consider removing this in v3 // TODO: Consider removing this in v3
@@ -63,20 +30,19 @@ fn default_schemes() -> Vec<String> {
vec!["https".to_string(), "http".to_string()] vec!["https".to_string(), "http".to_string()]
} }
fn deserialize_associated_host<'de, D>(deserializer: D) -> Result<Option<String>, D::Error> fn deserialize_associated_host<'de, D>(deserializer: D) -> Result<String, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let opt = Option::<String>::deserialize(deserializer)?; let host = String::deserialize(deserializer)?;
if let Some(ref host) = opt { if let Some((scheme, _host)) = host.split_once("://") {
if let Some((scheme, _)) = host.split_once("://") { Err(serde::de::Error::custom(format!(
return Err(serde::de::Error::custom(format!(
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix" "host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
))); )))
} else {
Ok(host)
} }
} }
Ok(opt)
}
#[derive(Deserialize, Clone)] #[derive(Deserialize, Clone)]
pub struct Config { pub struct Config {
-10
View File
@@ -28,16 +28,6 @@ pub enum Error {
PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError), PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
} }
// TODO(v3): change this into an error in v3,
// see <https://github.com/tauri-apps/plugins-workspace/pull/2970#issuecomment-3244660138>.
#[inline]
#[cfg(target_os = "linux")]
pub(crate) fn inspect_command_error<'a>(command: &'a str) -> impl Fn(&std::io::Error) + 'a {
move |e| {
tracing::error!("Failed to run OS command `{command}`: {e}");
}
}
impl Serialize for Error { impl Serialize for Error {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where where
+7 -31
View File
@@ -254,7 +254,6 @@ mod imp {
/// ///
/// ## Platform-specific: /// ## Platform-specific:
/// ///
/// - **Linux**: Needs the `xdg-mime` and `update-desktop-database` commands available on the system.
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`). /// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn register<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<()> { pub fn register<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<()> {
#[cfg(windows)] #[cfg(windows)]
@@ -293,7 +292,6 @@ mod imp {
.unwrap_or_else(|| bin.into_os_string()) .unwrap_or_else(|| bin.into_os_string())
.to_string_lossy() .to_string_lossy()
.to_string(); .to_string();
let qualified_exec = format!("\"{}\" %u", exec);
let target = self.app.path().data_dir()?.join("applications"); let target = self.app.path().data_dir()?.join("applications");
@@ -305,28 +303,12 @@ mod imp {
if let Ok(mut desktop_file) = ini::Ini::load_from_file(&target_file) { if let Ok(mut desktop_file) = ini::Ini::load_from_file(&target_file) {
if let Some(section) = desktop_file.section_mut(Some("Desktop Entry")) { if let Some(section) = desktop_file.section_mut(Some("Desktop Entry")) {
// it's ok to remove it - we only write to the file if it's missing
// and in that case we include old_mimes
let old_mimes = section.remove("MimeType").unwrap_or_default(); let old_mimes = section.remove("MimeType").unwrap_or_default();
let mut change = false;
// if the mime type is not present, append it to the list
if !old_mimes.split(';').any(|mime| mime == mime_type) { if !old_mimes.split(';').any(|mime| mime == mime_type) {
section.append("MimeType", format!("{mime_type};{old_mimes}")); section.append("MimeType", format!("{mime_type};{old_mimes}"));
change = true;
} else {
section.insert("MimeType".to_string(), old_mimes);
}
// if the exec command doesnt match, update to the new one
let old_exec = section.remove("Exec").unwrap_or_default();
if old_exec != qualified_exec {
section.append("Exec", qualified_exec);
change = true;
} else {
section.insert("Exec".to_string(), old_exec.to_string());
}
// if any property has changed, rewrite the .desktop file
if change {
desktop_file.write_to_file(&target_file)?; desktop_file.write_to_file(&target_file)?;
} }
} }
@@ -341,7 +323,7 @@ mod imp {
.product_name .product_name
.clone() .clone()
.unwrap_or_else(|| file_name.clone()), .unwrap_or_else(|| file_name.clone()),
qualified_exec = qualified_exec, exec = exec,
mime_type = mime_type mime_type = mime_type
) )
.as_bytes(), .as_bytes(),
@@ -350,15 +332,11 @@ mod imp {
Command::new("update-desktop-database") Command::new("update-desktop-database")
.arg(target) .arg(target)
.status() .status()?;
.inspect_err(crate::error::inspect_command_error(
"update-desktop-database",
))?;
Command::new("xdg-mime") Command::new("xdg-mime")
.args(["default", &file_name, mime_type.as_str()]) .args(["default", &file_name, mime_type.as_str()])
.status() .status()?;
.inspect_err(crate::error::inspect_command_error("xdg-mime"))?;
Ok(()) Ok(())
} }
@@ -427,7 +405,6 @@ mod imp {
/// ///
/// ## Platform-specific: /// ## Platform-specific:
/// ///
/// - **Linux**: Needs the `xdg-mime` command available on the system.
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`). /// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
pub fn is_registered<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<bool> { pub fn is_registered<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<bool> {
#[cfg(windows)] #[cfg(windows)]
@@ -462,8 +439,7 @@ mod imp {
"default", "default",
&format!("x-scheme-handler/{}", _protocol.as_ref()), &format!("x-scheme-handler/{}", _protocol.as_ref()),
]) ])
.output() .output()?;
.inspect_err(crate::error::inspect_command_error("xdg-mime"))?;
Ok(String::from_utf8_lossy(&output.stdout).contains(&file_name)) Ok(String::from_utf8_lossy(&output.stdout).contains(&file_name))
} }
@@ -540,7 +516,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> {
Ok(()) Ok(())
}) })
.on_event(|_app, _event| { .on_event(|_app, _event| {
#[cfg(desktop)] #[cfg(any(target_os = "macos", target_os = "ios"))]
if let tauri::RunEvent::Opened { urls } = _event { if let tauri::RunEvent::Opened { urls } = _event {
use tauri::Emitter; use tauri::Emitter;
+1 -1
View File
@@ -1,7 +1,7 @@
[Desktop Entry] [Desktop Entry]
Type=Application Type=Application
Name={name} Name={name}
Exec={qualified_exec} Exec={exec} %u
Terminal=false Terminal=false
MimeType={mime_type} MimeType={mime_type}
NoDisplay=true NoDisplay=true
-46
View File
@@ -1,51 +1,5 @@
# Changelog # Changelog
## \[2.6.0]
- [`d7a0bb32`](https://github.com/tauri-apps/plugins-workspace/commit/d7a0bb325dad919d6cc132eb3898c33540de77c4) ([#3136](https://github.com/tauri-apps/plugins-workspace/pull/3136) by [@onehumandev](https://github.com/tauri-apps/plugins-workspace/../../onehumandev)) Add `fileAccessMode` option to file picker.
## \[2.5.0]
- [`dff6fa98`](https://github.com/tauri-apps/plugins-workspace/commit/dff6fa986a9a05ba98b6ca660fea78ae97251fc2) ([#3034](https://github.com/tauri-apps/plugins-workspace/pull/3034) by [@onehumandev](https://github.com/tauri-apps/plugins-workspace/../../onehumandev)) Add `pickerMode` option to file picker (currently only used on iOS)
### Dependencies
- Upgraded to `fs-js@2.4.5`
### feat
- [`c23fa03f`](https://github.com/tauri-apps/plugins-workspace/commit/c23fa03f07d5c1c220bcf0bca482364513e3f754) ([#3098](https://github.com/tauri-apps/plugins-workspace/pull/3098) by [@Lepidopteran](https://github.com/tauri-apps/plugins-workspace/../../Lepidopteran)) Add `xdg-portal` as an optional feature for `rfd`
## \[2.4.2]
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
### Dependencies
- Upgraded to `fs-js@2.4.4`
## \[2.4.1]
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
### Dependencies
- Upgraded to `fs-js@2.4.3`
## \[2.4.0]
- [`509eba8d`](https://github.com/tauri-apps/plugins-workspace/commit/509eba8d441c4f6ecf0af77b572cb2afd69a752d) ([#2641](https://github.com/tauri-apps/plugins-workspace/pull/2641) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Add support for showing a message dialog with 3 buttons.
## \[2.3.3]
### Dependencies
- Upgraded to `fs-js@2.4.2`
## \[2.3.2]
- [`af08c66f`](https://github.com/tauri-apps/plugins-workspace/commit/af08c66faafe0dffc4b0a80aef030cd3f0f89a9c) ([#2871](https://github.com/tauri-apps/plugins-workspace/pull/2871) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused the file picker not to open on Android when extension filters were set.
## \[2.3.1] ## \[2.3.1]
### Dependencies ### Dependencies
+9 -11
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-dialog" name = "tauri-plugin-dialog"
version = "2.6.0" version = "2.3.1"
description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application." description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application."
edition = { workspace = true } edition = { workspace = true }
authors = { workspace = true } authors = { workspace = true }
@@ -9,12 +9,9 @@ rust-version = { workspace = true }
repository = { workspace = true } repository = { workspace = true }
links = "tauri-plugin-dialog" links = "tauri-plugin-dialog"
[features]
default = ["gtk3"]
xdg-portal = ["rfd/xdg-portal", "rfd/tokio", "rfd/wayland"]
gtk3 = ["rfd/gtk3"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]
targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"] targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
[package.metadata.platforms.support] [package.metadata.platforms.support]
@@ -28,7 +25,7 @@ ios = { level = "partial", notes = "Does not support folder picker" }
tauri-plugin = { workspace = true, features = ["build"] } tauri-plugin = { workspace = true, features = ["build"] }
[dev-dependencies] [dev-dependencies]
tauri = { workspace = true } tauri = { workspace = true, features = ["wry"] }
[dependencies] [dependencies]
serde = { workspace = true } serde = { workspace = true }
@@ -37,14 +34,15 @@ tauri = { workspace = true }
log = { workspace = true } log = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
url = { workspace = true } url = { workspace = true }
tauri-plugin-fs = { path = "../fs", version = "2.4.5" } tauri-plugin-fs = { path = "../fs", version = "2.4.1" }
[target.'cfg(target_os = "ios")'.dependencies] [target.'cfg(target_os = "ios")'.dependencies]
tauri = { workspace = true } tauri = { workspace = true, features = ["wry"] }
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
rfd = { version = "0.16", default-features = false, features = [ rfd = { version = "0.15", default-features = false, features = [
"tokio",
"gtk3",
"common-controls-v6", "common-controls-v6",
] } ] }
raw-window-handle = "0.6" raw-window-handle = "0.6"
+9 -18
View File
@@ -31,32 +31,23 @@ tauri-plugin-dialog = "2.0.0"
tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" } tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
### Linux XDG Desktop Portal Support
By default, this plugin uses gtk to show dialogs, however since `v2.5.0` you can switch to using [XDG Desktop Portal](https://flatpak.github.io/xdg-desktop-portal/) by adding the following to your `Cargo.toml` file:
```toml
[dependencies]
tauri-plugin-dialog = { version = "2.5.0", default-features = false, features = ["xdg-portal"] }
# alternatively with Git:
tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2", default-features = false, features = ["xdg-portal"] }
```
Do note if you use the `xdg-portal` feature, you need to ensure that [`zenity`](https://gitlab.gnome.org/GNOME/zenity) and an [XDG Desktop Portal backend](https://flatpak.github.io/xdg-desktop-portal#using-portals) is installed with your program.
For more information, see [XDG Desktop Portal documentation](https://flatpak.github.io/xdg-desktop-portal/) and [`rfd` documentation](https://docs.rs/rfd/latest/rfd#xdg-desktop-portal-backend).
### JavaScript
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
```sh ```sh
pnpm add @tauri-apps/plugin-dialog pnpm add @tauri-apps/plugin-dialog
# or # or
npm add @tauri-apps/plugin-dialog npm add @tauri-apps/plugin-dialog
# or # or
yarn add @tauri-apps/plugin-dialog yarn add @tauri-apps/plugin-dialog
# alternatively with Git:
pnpm add https://github.com/tauri-apps/tauri-plugin-dialog#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-dialog#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-dialog#v2
``` ```
## Usage ## Usage
+1 -1
View File
@@ -5,7 +5,7 @@ plugins {
android { android {
namespace = "app.tauri.dialog" namespace = "app.tauri.dialog"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24

Some files were not shown because too many files have changed in this diff Show More