Compare commits

..

2 Commits

Author SHA1 Message Date
FabianLars 15fc071773 add corenfc framework 2025-08-11 22:21:03 +02:00
FabianLars 73c6047b78 fix(nfc): use xcode project instead of swift package 2025-08-11 22:08:58 +02:00
275 changed files with 2797 additions and 5271 deletions
@@ -1,6 +0,0 @@
---
"dialog-js": minor:feat
"dialog": minor:feat
---
Add `xdg-portal` as an optional feature for `rfd`
@@ -1,6 +0,0 @@
---
"log": "minor"
"log-js": "minor"
---
Allow specifying a log formatter per target using the `format` method on `Target`.
-10
View File
@@ -78,7 +78,6 @@
"notification", "notification",
"os", "os",
"process", "process",
"secure-storage",
"shell", "shell",
"store", "store",
"updater", "updater",
@@ -105,7 +104,6 @@
"notification-js", "notification-js",
"os-js", "os-js",
"process-js", "process-js",
"secure-storage-js",
"shell-js", "shell-js",
"store-js", "store-js",
"updater-js" "updater-js"
@@ -284,14 +282,6 @@
"path": "./plugins/process", "path": "./plugins/process",
"manager": "javascript" "manager": "javascript"
}, },
"secure-storage": {
"path": "./plugins/secure-storage",
"manager": "rust"
},
"secure-storage-js": {
"path": "./plugins/secure-storage",
"manager": "javascript"
},
"shell": { "shell": {
"path": "./plugins/shell", "path": "./plugins/shell",
"manager": "rust" "manager": "rust"
-6
View File
@@ -1,6 +0,0 @@
---
stronghold: patch
stronghold-js: patch
---
The `stronghold` plugin is now deprecated and will be removed in v3. The `secure-storage` plugin should be a replacement for most use-cases.
-6
View File
@@ -1,6 +0,0 @@
---
"dialog": minor
"dialog-js": minor
---
Add `pickerMode` option to file picker (currently only used on iOS)
@@ -1,5 +0,0 @@
---
"localhost": patch
---
Disable caching on responses.
@@ -1,6 +0,0 @@
---
"barcode-scanner": patch
"barcode-scanner-js": patch
---
Fix the `cameraView` is not removed after scanning in iOS.
-6
View File
@@ -1,6 +0,0 @@
---
"log": patch
"log-js": patch
---
Fix log file rotation when exceeding `max_file_size`.
+6
View File
@@ -0,0 +1,6 @@
---
fs: patch
fs-js: patch
---
Fixed calling `writeFile` with `data: ReadableStream` throws `Invalid argument`
+6
View File
@@ -0,0 +1,6 @@
---
nfc: patch
nfc-js: patch
---
On iOS, the reader session will now get closed properly on errors, preventing dangling invalid sessions that could prevent subsequent write attempts.
-6
View File
@@ -1,6 +0,0 @@
---
"nfc": "patch"
"nfc-js": "patch"
---
Update return value of `isAvailable` to match TypeScript function signature
+6
View File
@@ -0,0 +1,6 @@
---
"opener": 'minor:enhance'
"opener-js": 'minor:enhance'
---
Allow reveal multiple items in the file explorer.
+6
View File
@@ -0,0 +1,6 @@
---
store: minor
store-js: minor
---
Allow setting defaults from the JavaScript API
+6
View File
@@ -0,0 +1,6 @@
---
store: minor
store-js: minor
---
Add an new option `overrideDefaults` for creating/loading and reloading the store that overrides the store with the on-disk state, ignoring defaults
-6
View File
@@ -1,6 +0,0 @@
---
"updater": minor
"updater-js": minor
---
Updater plugin now supports all bundle types: Deb, Rpm and AppImage for Linux; NSiS, MSI for Windows. This was added in https://github.com/tauri-apps/plugins-workspace/pull/2624
-6
View File
@@ -1,6 +0,0 @@
---
"upload": minor
"upload-js": minor
---
Upload plugin now supports specifying an HTTP method i.e. POST, PUT etc.
@@ -101,11 +101,6 @@ jobs:
- pnpm-lock.yaml - pnpm-lock.yaml
- plugins/process/guest-js/** - plugins/process/guest-js/**
- plugins/process/src/api-iife.js - plugins/process/src/api-iife.js
secure-storage:
- .github/workflows/check-generated-files.yml
- pnpm-lock.yaml
- plugins/secure-storage/guest-js/**
- plugins/secure-storage/src/api-iife.js
shell: shell:
- .github/workflows/check-generated-files.yml - .github/workflows/check-generated-files.yml
- pnpm-lock.yaml - pnpm-lock.yaml
@@ -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'
-4
View File
@@ -98,9 +98,6 @@ jobs:
tauri-plugin-process: tauri-plugin-process:
- .github/workflows/lint-rust.yml - .github/workflows/lint-rust.yml
- plugins/process/** - plugins/process/**
tauri-plugin-secure-storage:
- .github/workflows/lint-rust.yml
- plugins/secure-storage/**
tauri-plugin-shell: tauri-plugin-shell:
- .github/workflows/lint-rust.yml - .github/workflows/lint-rust.yml
- plugins/shell/** - plugins/shell/**
@@ -157,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
+4 -9
View File
@@ -137,11 +137,6 @@ jobs:
- Cargo.toml - Cargo.toml
- Cargo.lock - Cargo.lock
- plugins/process/** - plugins/process/**
tauri-plugin-secure-storage:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/secure-storage/**
tauri-plugin-shell: tauri-plugin-shell:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
@@ -224,7 +219,7 @@ jobs:
target: aarch64-linux-android, target: aarch64-linux-android,
os: ubuntu-latest, os: ubuntu-latest,
runner: 'cross', runner: 'cross',
command: 'build --verbose' command: 'build'
} }
runs-on: ${{ matrix.platform.os }} runs-on: ${{ matrix.platform.os }}
@@ -238,7 +233,7 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev
- uses: dtolnay/rust-toolchain@1.85 - uses: dtolnay/rust-toolchain@1.77.2
with: with:
targets: ${{ matrix.platform.target }} targets: ${{ matrix.platform.target }}
@@ -251,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-secure-storage' && 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 -1
View File
@@ -58,4 +58,4 @@ pids
.idea .idea
debug.log debug.log
TODO.md TODO.md
.aider.* .aider*
-1
View File
@@ -1,3 +1,2 @@
plugins/*/permissions/autogenerated/ plugins/*/permissions/autogenerated/
plugins/*/android/.tauri/tauri-api/build/ plugins/*/android/.tauri/tauri-api/build/
plugins/*/android/build/intermediates/
Generated
+109 -353
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -12,10 +12,10 @@ 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.8.2", default-features = false } tauri = { version = "2.6", default-features = false }
tauri-build = "2.4" tauri-build = "2.3"
tauri-plugin = "2.4" tauri-plugin = "2.3"
tauri-utils = "2.7" tauri-utils = "2.5"
serde_json = "1" serde_json = "1"
thiserror = "2" thiserror = "2"
url = "2" url = "2"
+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',
-67
View File
@@ -1,72 +1,5 @@
# Changelog # Changelog
## \[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] ## \[2.0.28]
### 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>
+19 -20
View File
@@ -1,7 +1,7 @@
{ {
"name": "api", "name": "api",
"private": true, "private": true,
"version": "2.0.34", "version": "2.0.28",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --clearScreen false", "dev": "vite --clearScreen false",
@@ -10,25 +10,24 @@
"tauri": "tauri" "tauri": "tauri"
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "2.9.0", "@tauri-apps/api": "2.7.0",
"@tauri-apps/plugin-barcode-scanner": "^2.4.2", "@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.4.2", "@tauri-apps/plugin-dialog": "^2.3.2",
"@tauri-apps/plugin-fs": "^2.4.4", "@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.4", "@tauri-apps/plugin-http": "^2.5.1",
"@tauri-apps/plugin-nfc": "^2.3.3", "@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.2", "@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-secure-storage": "file:../../plugins/secure-storage", "@tauri-apps/plugin-shell": "^2.3.0",
"@tauri-apps/plugin-shell": "^2.3.3", "@tauri-apps/plugin-store": "^2.3.0",
"@tauri-apps/plugin-store": "^2.4.1",
"@tauri-apps/plugin-updater": "^2.9.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"
@@ -37,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.9.4", "@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"
} }
} }
-71
View File
@@ -1,76 +1,5 @@
# Changelog # Changelog
## \[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] ## \[2.0.32]
### Dependencies ### Dependencies
+19 -20
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "api" name = "api"
publish = false publish = false
version = "2.0.38" version = "2.0.32"
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,25 +20,24 @@ 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.7.1" } tauri-plugin-log = { path = "../../../plugins/log", version = "2.6.0" }
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.4.4", 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.4.2" } tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.3.2" }
tauri-plugin-http = { path = "../../../plugins/http", features = [ tauri-plugin-http = { path = "../../../plugins/http", features = [
"multipart", "multipart",
"cookies", "cookies",
], version = "2.5.4" } ], 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.2" } tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.4.0" }
tauri-plugin-secure-storage = { path = "../../../plugins/secure-storage" } tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.0" }
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.3" } tauri-plugin-store = { path = "../../../plugins/store", version = "2.3.0" }
tauri-plugin-store = { path = "../../../plugins/store", version = "2.4.1" }
tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" } tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" }
[dependencies.tauri] [dependencies.tauri]
@@ -56,17 +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.9.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.2" } tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.0" }
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.3" } 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]
prod = ["tauri/custom-protocol"] prod = ["tauri/custom-protocol"]
+1 -11
View File
@@ -68,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",
@@ -78,9 +75,6 @@
{ {
"identifier": "fs:scope-appdata-recursive", "identifier": "fs:scope-appdata-recursive",
"allow": [ "allow": [
{
"path": "$APPDATA/db/"
},
{ {
"path": "$APPDATA/db/**" "path": "$APPDATA/db/**"
} }
@@ -102,10 +96,6 @@
"identifier": "opener:allow-open-path", "identifier": "opener:allow-open-path",
"allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }] "allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }]
}, },
"upload:default", "upload:default"
"secure-storage:allow-get-string",
"secure-storage:allow-set-string",
"secure-storage:allow-get-binary",
"secure-storage:allow-set-binary"
] ]
} }
@@ -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()
} }
-1
View File
@@ -38,7 +38,6 @@ pub fn run() {
.plugin(tauri_plugin_process::init()) .plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_secure_storage::init())
.plugin(tauri_plugin_store::Builder::default().build()) .plugin(tauri_plugin_store::Builder::default().build())
.plugin(tauri_plugin_upload::init()) .plugin(tauri_plugin_upload::init())
.setup(move |app| { .setup(move |app| {
+6 -12
View File
@@ -23,7 +23,6 @@
import Biometric from './views/Biometric.svelte' import Biometric from './views/Biometric.svelte'
import Geolocation from './views/Geolocation.svelte' import Geolocation from './views/Geolocation.svelte'
import Haptics from './views/Haptics.svelte' import Haptics from './views/Haptics.svelte'
import SecureStorage from './views/SecureStorage.svelte'
import { onMount, tick } from 'svelte' import { onMount, tick } from 'svelte'
import { ask } from '@tauri-apps/plugin-dialog' import { ask } from '@tauri-apps/plugin-dialog'
@@ -104,11 +103,6 @@
component: Store, component: Store,
icon: 'i-codicon-file-code' icon: 'i-codicon-file-code'
}, },
{
label: 'SecureStorage',
component: SecureStorage,
icon: 'i-codicon-file-code'
},
!isMobile && { !isMobile && {
label: 'Updater', label: 'Updater',
component: Updater, component: Updater,
@@ -219,9 +213,9 @@
...r, ...r,
{ {
html: html:
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` `<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` +
+ (typeof value === 'string' ? value : JSON.stringify(value, null, 1)) (typeof value === 'string' ? value : JSON.stringify(value, null, 1)) +
+ '</pre>' '</pre>'
} }
]) ])
await tick() await tick()
@@ -235,9 +229,9 @@
...r, ...r,
{ {
html: html:
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` `<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` +
+ html html +
+ '</pre>' '</pre>'
} }
]) ])
await tick() await tick()
+11 -35
View File
@@ -8,7 +8,6 @@
let filter = null; let filter = null;
let multiple = false; let multiple = false;
let directory = false; let directory = false;
let pickerMode = "";
function arrayBufferToBase64(buffer, callback) { function arrayBufferToBase64(buffer, callback) {
var blob = new Blob([buffer], { var blob = new Blob([buffer], {
@@ -45,13 +44,6 @@
await message("Tauri is awesome!"); await message("Tauri is awesome!");
} }
async function msgCustom(result) {
const buttons = { yes: "awesome", no: "amazing", cancel: "stunning" };
await message(`Tauri is: `, { buttons })
.then((res) => onMessage(`Tauri is ${res}`))
.catch(onMessage);
}
function openDialog() { function openDialog() {
open({ open({
title: "My wonderful open dialog", title: "My wonderful open dialog",
@@ -66,7 +58,6 @@
: [], : [],
multiple, multiple,
directory, directory,
pickerMode: pickerMode === "" ? undefined : pickerMode,
}) })
.then(function (res) { .then(function (res) {
if (Array.isArray(res)) { if (Array.isArray(res)) {
@@ -96,7 +87,7 @@
onMessage(res); onMessage(res);
} }
}) })
.catch(onMessage); .catch(onMessage(res));
} }
}) })
.catch(onMessage); .catch(onMessage);
@@ -114,7 +105,7 @@
}, },
] ]
: [], : [],
}) })
.then(onMessage) .then(onMessage)
.catch(onMessage); .catch(onMessage);
} }
@@ -144,28 +135,13 @@
<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>
<br /> <br />
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
<div class="flex flex-wrap flex-col md:flex-row gap-2 children:flex-shrink-0"> <button class="btn" id="save-dialog" on:click={saveDialog}
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button> >Open save dialog</button
<button class="btn" id="save-dialog" on:click={saveDialog} >
>Open save dialog</button <button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
> <button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button> >Prompt (custom)</button
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom} >
>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>
+2 -27
View File
@@ -1,9 +1,8 @@
<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, onMount } from 'svelte' import { onDestroy } from 'svelte'
const { onMessage, insecureRenderHtml } = $props() const { onMessage, insecureRenderHtml } = $props()
@@ -19,12 +18,6 @@
let baseDir = $state() let baseDir = $state()
let unwatchFn let unwatchFn
let unwatchPath = '' let unwatchPath = ''
let isMobile = $state(false)
onMount(() => {
let platform = os.platform()
isMobile = platform === 'android' || platform === 'ios'
})
const dirOptions = Object.keys(fs.BaseDirectory).filter((key) => const dirOptions = Object.keys(fs.BaseDirectory).filter((key) =>
isNaN(parseInt(key)) isNaN(parseInt(key))
@@ -45,7 +38,7 @@
} }
function mkdir() { function mkdir() {
fs.mkdir(path, { baseDir, recursive: true }) fs.mkdir(path, { baseDir })
.then(() => { .then(() => {
onMessage(`Created dir ${path}`) onMessage(`Created dir ${path}`)
}) })
@@ -80,16 +73,6 @@
.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()
@@ -197,13 +180,6 @@
</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" bind:value={baseDir}>
<option value={undefined} selected>None</option> <option value={undefined} selected>None</option>
@@ -231,7 +207,6 @@
</div> </div>
{#if file} {#if file}
<div> <div>
<button class="btn" onclick={write}>Write</button>
<button class="btn" onclick={truncate}>Truncate</button> <button class="btn" onclick={truncate}>Truncate</button>
<button class="btn" onclick={stat}>Stat</button> <button class="btn" onclick={stat}>Stat</button>
</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>
@@ -1,54 +0,0 @@
<script>
import { onMount } from 'svelte'
import { getString, setString } from '@tauri-apps/plugin-secure-storage'
export let onMessage
let key
let value
let output
async function read(key) {
try {
output = await getString(key)
} catch (error) {
onMessage(error)
}
}
async function write(key, value) {
try {
await setString(key, value)
} catch (error) {
onMessage(error)
}
}
function reset() {
output = ''
}
</script>
<div class="flex flex-col childre:grow gap-1">
<div class="flex flex-col flex-row-md gap-4">
<div class="flex items-center gap-1">
Key:
<input class="grow input" bind:value={key} />
</div>
<div class="flex items-center gap-1">
Value:
<input class="grow input" bind:value />
</div>
<div>
<button class="btn" on:click={() => write(key, value)}>Write</button>
<button class="btn" on:click={() => read(key)}>Read</button>
<button class="btn" on:click={() => reset()}>Reset Output</button>
</div>
</div>
<div>
Output: {output}
</div>
</div>
+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}
+8 -9
View File
@@ -11,21 +11,20 @@
"example:api:dev": "pnpm run --filter \"api\" tauri dev" "example:api:dev": "pnpm run --filter \"api\" tauri dev"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.39.1", "@eslint/js": "9.32.0",
"@rollup/plugin-node-resolve": "16.0.3", "@rollup/plugin-node-resolve": "16.0.1",
"@rollup/plugin-terser": "0.4.4", "@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-typescript": "12.3.0", "@rollup/plugin-typescript": "12.1.4",
"covector": "^0.12.4", "covector": "^0.12.4",
"eslint": "9.39.1", "eslint": "9.32.0",
"eslint-config-prettier": "10.1.8", "eslint-config-prettier": "10.1.8",
"eslint-plugin-security": "3.0.1", "eslint-plugin-security": "3.0.1",
"prettier": "3.6.2", "prettier": "3.6.2",
"rollup": "4.53.2", "rollup": "4.46.2",
"tslib": "2.8.1", "tslib": "2.8.1",
"typescript": "5.9.3", "typescript": "5.9.2",
"typescript-eslint": "8.47.0" "typescript-eslint": "8.39.0"
}, },
"minimumReleaseAge": 4320,
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"esbuild@<0.25.0": ">=0.25.0" "esbuild@<0.25.0": ">=0.25.0"
@@ -35,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 = "" }
+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.8.0" "@tauri-apps/api": "^2.6.0"
} }
} }
@@ -331,10 +331,10 @@
"markdownDescription": "Denies the is_enabled command without any pre-configured scope." "markdownDescription": "Denies the is_enabled command without any pre-configured scope."
}, },
{ {
"description": "This permission set configures if your\r\napplication can enable or disable auto\r\nstarting the application on boot.\r\n\r\n#### Granted Permissions\r\n\r\nIt allows all to check, enable and\r\ndisable the automatic start on boot.\r\n\r\n\n#### This default permission set includes:\n\n- `allow-enable`\n- `allow-disable`\n- `allow-is-enabled`", "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", "type": "string",
"const": "default", "const": "default",
"markdownDescription": "This permission set configures if your\r\napplication can enable or disable auto\r\nstarting the application on boot.\r\n\r\n#### Granted Permissions\r\n\r\nIt allows all to check, enable and\r\ndisable the automatic start on boot.\r\n\r\n\n#### This default permission set includes:\n\n- `allow-enable`\n- `allow-disable`\n- `allow-is-enabled`" "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`"
} }
] ]
} }
-9
View File
@@ -1,14 +1,5 @@
# Changelog # Changelog
## \[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+
+3 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-barcode-scanner" name = "tauri-plugin-barcode-scanner"
version = "2.4.2" 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]
@@ -5,10 +5,10 @@ plugins {
android { android {
namespace = "app.tauri.barcodescanner" namespace = "app.tauri.barcodescanner"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro") consumerProguardFiles("consumer-rules.pro")
@@ -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")
@@ -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
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-barcode-scanner", "name": "@tauri-apps/plugin-barcode-scanner",
"version": "2.4.2", "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.8.0" "@tauri-apps/api": "^2.6.0"
} }
} }
-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]
+2 -2
View File
@@ -5,10 +5,10 @@ plugins {
android { android {
namespace = "app.tauri.biometric" namespace = "app.tauri.biometric"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro") consumerProguardFiles("consumer-rules.pro")
+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.8.0" "@tauri-apps/api": "^2.6.0"
} }
} }
@@ -319,10 +319,10 @@
"markdownDescription": "Denies the status command without any pre-configured scope." "markdownDescription": "Denies the status command without any pre-configured scope."
}, },
{ {
"description": "This permission set configures which\r\nbiometric features are by default exposed.\r\n\r\n#### Granted Permissions\r\n\r\nIt allows acccess to all biometric commands.\r\n\r\n\n#### This default permission set includes:\n\n- `allow-authenticate`\n- `allow-status`", "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", "type": "string",
"const": "default", "const": "default",
"markdownDescription": "This permission set configures which\r\nbiometric features are by default exposed.\r\n\r\n#### Granted Permissions\r\n\r\nIt allows acccess to all biometric commands.\r\n\r\n\n#### This default permission set includes:\n\n- `allow-authenticate`\n- `allow-status`" "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 = "" }
+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.8.0" "@tauri-apps/api": "^2.6.0"
} }
} }
-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 -2
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]
@@ -5,10 +5,10 @@ plugins {
android { android {
namespace = "app.tauri.clipboard" namespace = "app.tauri.clipboard"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro") consumerProguardFiles("consumer-rules.pro")
+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.8.0" "@tauri-apps/api": "^2.6.0"
} }
} }
@@ -1,7 +1,7 @@
## Default Permission ## Default Permission
No features are enabled by default, as we believe No features are enabled by default, as we believe
the clipboard can be inherently dangerous and it is the clipboard can be inherently dangerous and it is
application specific if read and/or write access is needed. application specific if read and/or write access is needed.
Clipboard interaction needs to be explicitly enabled. Clipboard interaction needs to be explicitly enabled.
@@ -2,7 +2,7 @@
[default] [default]
description = """ description = """
No features are enabled by default, as we believe No features are enabled by default, as we believe
the clipboard can be inherently dangerous and it is the clipboard can be inherently dangerous and it is
application specific if read and/or write access is needed. application specific if read and/or write access is needed.
Clipboard interaction needs to be explicitly enabled. Clipboard interaction needs to be explicitly enabled.
@@ -367,10 +367,10 @@
"markdownDescription": "Denies the write_text command without any pre-configured scope." "markdownDescription": "Denies the write_text command without any pre-configured scope."
}, },
{ {
"description": "No features are enabled by default, as we believe\r\nthe clipboard can be inherently dangerous and it is\r\napplication specific if read and/or write access is needed.\r\n\r\nClipboard interaction needs to be explicitly enabled.\r\n", "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", "type": "string",
"const": "default", "const": "default",
"markdownDescription": "No features are enabled by default, as we believe\r\nthe clipboard can be inherently dangerous and it is\r\napplication specific if read and/or write access is needed.\r\n\r\nClipboard interaction needs to be explicitly enabled.\r\n" "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"
} }
] ]
} }
-17
View File
@@ -1,22 +1,5 @@
# Changelog # Changelog
## \[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.5" 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 }
+2 -2
View File
@@ -5,10 +5,10 @@ plugins {
android { android {
namespace = "app.tauri.deep_link" namespace = "app.tauri.deep_link"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro") consumerProguardFiles("consumer-rules.pro")
+26 -119
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,89 +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 tauri_plugin::mobile::update_entitlements(|entitlements| {
// generated for explicit app links and not entitlements.insert(
// other deep links because then they "com.apple.developer.associated-domains".into(),
// are just going to complain and not be built or signed config
let has_app_links = config.mobile.iter().any(|d| d.is_app_link()); .mobile
.into_iter()
if !has_app_links { .map(|d| format!("applinks:{}", d.host).into())
tauri_plugin::mobile::update_entitlements(|entitlements| { .collect::<Vec<_>>()
entitlements.remove("com.apple.developer.associated-domains"); .into(),
}) );
.expect("failed to update entitlements"); })
} else { .expect("failed to update entitlements");
tauri_plugin::mobile::update_entitlements(|entitlements| {
entitlements.insert(
"com.apple.developer.associated-domains".into(),
config
.mobile
.iter()
.filter(|d| d.is_app_link())
.filter_map(|d| d.host.as_ref())
.map(|host| format!("applinks:{}", host).into())
.collect::<Vec<_>>()
.into(),
);
})
.expect("failed to update entitlements");
}
let deep_link_domains = config
.mobile
.iter()
.filter_map(|domain| {
if domain.is_app_link() {
return None;
}
Some(domain)
})
.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(),
format!("{}", domain.scheme[0]).into(),
);
plist::Value::Dictionary(dict)
})
.collect::<Vec<_>>()
.into(),
);
})
.expect("failed to update Info.plist");
}
} }
} }
} }
@@ -1,29 +1,5 @@
# Changelog # Changelog
## \[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.8", "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.9.0", "@tauri-apps/api": "2.7.0",
"@tauri-apps/plugin-deep-link": "2.4.5" "@tauri-apps/plugin-deep-link": "2.4.1"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "2.9.4", "@tauri-apps/cli": "2.7.1",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"vite": "^7.0.7" "vite": "^7.0.4"
} }
} }
@@ -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")
@@ -23,40 +23,23 @@
<category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter> </intent-filter>
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. --> <!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
<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="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,116 +1,116 @@
{ {
"images" : [ "images": [
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-20x20@2x.png", "filename": "AppIcon-20x20@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-20x20@3x.png", "filename": "AppIcon-20x20@3x.png",
"scale" : "3x" "scale": "3x"
}, },
{ {
"size" : "29x29", "size": "29x29",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-29x29@2x-1.png", "filename": "AppIcon-29x29@2x-1.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "29x29", "size": "29x29",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-29x29@3x.png", "filename": "AppIcon-29x29@3x.png",
"scale" : "3x" "scale": "3x"
}, },
{ {
"size" : "40x40", "size": "40x40",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-40x40@2x.png", "filename": "AppIcon-40x40@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "40x40", "size": "40x40",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-40x40@3x.png", "filename": "AppIcon-40x40@3x.png",
"scale" : "3x" "scale": "3x"
}, },
{ {
"size" : "60x60", "size": "60x60",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-60x60@2x.png", "filename": "AppIcon-60x60@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "60x60", "size": "60x60",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-60x60@3x.png", "filename": "AppIcon-60x60@3x.png",
"scale" : "3x" "scale": "3x"
}, },
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-20x20@1x.png", "filename": "AppIcon-20x20@1x.png",
"scale" : "1x" "scale": "1x"
}, },
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-20x20@2x-1.png", "filename": "AppIcon-20x20@2x-1.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "29x29", "size": "29x29",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-29x29@1x.png", "filename": "AppIcon-29x29@1x.png",
"scale" : "1x" "scale": "1x"
}, },
{ {
"size" : "29x29", "size": "29x29",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-29x29@2x.png", "filename": "AppIcon-29x29@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "40x40", "size": "40x40",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-40x40@1x.png", "filename": "AppIcon-40x40@1x.png",
"scale" : "1x" "scale": "1x"
}, },
{ {
"size" : "40x40", "size": "40x40",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-40x40@2x-1.png", "filename": "AppIcon-40x40@2x-1.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "76x76", "size": "76x76",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-76x76@1x.png", "filename": "AppIcon-76x76@1x.png",
"scale" : "1x" "scale": "1x"
}, },
{ {
"size" : "76x76", "size": "76x76",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-76x76@2x.png", "filename": "AppIcon-76x76@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "83.5x83.5", "size": "83.5x83.5",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-83.5x83.5@2x.png", "filename": "AppIcon-83.5x83.5@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "1024x1024", "size": "1024x1024",
"idiom" : "ios-marketing", "idiom": "ios-marketing",
"filename" : "AppIcon-512@2x.png", "filename": "AppIcon-512@2x.png",
"scale" : "1x" "scale": "1x"
} }
], ],
"info" : { "info": {
"version" : 1, "version": 1,
"author" : "xcode" "author": "xcode"
} }
} }
@@ -1,6 +1,6 @@
{ {
"info" : { "info": {
"version" : 1, "version": 1,
"author" : "xcode" "author": "xcode"
} }
} }
@@ -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
@@ -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.5", "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.8.0" "@tauri-apps/api": "^2.6.0"
},
"devDependencies": {
"@tauri-apps/cli": "2.9.4"
} }
} }
+12 -46
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,19 +30,18 @@ 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)]
-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
+6 -30
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))
} }
+2 -2
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
-26
View File
@@ -1,31 +1,5 @@
# Changelog # Changelog
## \[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] ## \[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. - [`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.
+5 -8
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-dialog" name = "tauri-plugin-dialog"
version = "2.4.2" version = "2.3.2"
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"]
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]
@@ -37,7 +34,7 @@ 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.4" } tauri-plugin-fs = { path = "../fs", version = "2.4.1" }
[target.'cfg(target_os = "ios")'.dependencies] [target.'cfg(target_os = "ios")'.dependencies]
tauri = { workspace = true, features = ["wry"] } tauri = { workspace = true, features = ["wry"] }
@@ -45,7 +42,7 @@ 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.15", default-features = false, features = [ rfd = { version = "0.15", default-features = false, features = [
"tokio", "tokio",
"gtk3",
"common-controls-v6", "common-controls-v6",
] } ] }
raw-window-handle = "0.6" raw-window-handle = "0.6"
-18
View File
@@ -31,24 +31,6 @@ 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:
```sh ```sh
+2 -2
View File
@@ -5,10 +5,10 @@ plugins {
android { android {
namespace = "app.tauri.dialog" namespace = "app.tauri.dialog"
compileSdk = 36 compileSdk = 34
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro") consumerProguardFiles("consumer-rules.pro")
@@ -31,7 +31,6 @@ class Filter {
class FilePickerOptions { class FilePickerOptions {
lateinit var filters: Array<Filter> lateinit var filters: Array<Filter>
var multiple: Boolean? = null var multiple: Boolean? = null
var pickerMode: String? = null
} }
@InvokeArg @InvokeArg
@@ -39,7 +38,6 @@ class MessageOptions {
var title: String? = null var title: String? = null
lateinit var message: String lateinit var message: String
var okButtonLabel: String? = null var okButtonLabel: String? = null
var noButtonLabel: String? = null
var cancelButtonLabel: String? = null var cancelButtonLabel: String? = null
} }
@@ -62,19 +60,10 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
// TODO: ACTION_OPEN_DOCUMENT ?? // TODO: ACTION_OPEN_DOCUMENT ??
val intent = Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE) intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "*/*"
if (args.pickerMode == "image") { if (parsedTypes.isNotEmpty()) {
intent.type = "image/*"
} else if (args.pickerMode == "video") {
intent.type = "video/*"
} else if (args.pickerMode == "media") {
intent.type = "*/*"
intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("video/*", "image/*"))
} else if (parsedTypes.isNotEmpty()) {
intent.type = "*/*"
intent.putExtra(Intent.EXTRA_MIME_TYPES, parsedTypes) intent.putExtra(Intent.EXTRA_MIME_TYPES, parsedTypes)
} else {
intent.type = "*/*"
} }
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, args.multiple ?: false) intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, args.multiple ?: false)
@@ -150,8 +139,9 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
return return
} }
val handler = { value: String -> val handler = { cancelled: Boolean, value: Boolean ->
val ret = JSObject() val ret = JSObject()
ret.put("cancelled", cancelled)
ret.put("value", value) ret.put("value", value)
invoke.resolve(ret) invoke.resolve(ret)
} }
@@ -163,34 +153,24 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
if (args.title != null) { if (args.title != null) {
builder.setTitle(args.title) builder.setTitle(args.title)
} }
val okButtonLabel = args.okButtonLabel ?: "Ok"
builder builder
.setMessage(args.message) .setMessage(args.message)
.setPositiveButton(okButtonLabel) { dialog, _ -> .setPositiveButton(
args.okButtonLabel ?: "OK"
) { dialog, _ ->
dialog.dismiss() dialog.dismiss()
handler(okButtonLabel) handler(false, true)
} }
.setOnCancelListener { dialog -> .setOnCancelListener { dialog ->
dialog.dismiss() dialog.dismiss()
handler(args.cancelButtonLabel ?: "Cancel") handler(true, false)
} }
if (args.noButtonLabel != null) {
builder.setNeutralButton(args.noButtonLabel) { dialog, _ ->
dialog.dismiss()
handler(args.noButtonLabel!!)
}
}
if (args.cancelButtonLabel != null) { if (args.cancelButtonLabel != null) {
builder.setNegativeButton( args.cancelButtonLabel) { dialog, _ -> builder.setNegativeButton( args.cancelButtonLabel) { dialog, _ ->
dialog.dismiss() dialog.dismiss()
handler(args.cancelButtonLabel!!) handler(false, false)
} }
} }
val dialog = builder.create() val dialog = builder.create()
dialog.show() dialog.show()
} }
+1 -1
View File
@@ -1 +1 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}function e(t){if(void 0!==t)return"string"==typeof t?t:"ok"in t&&"cancel"in t?{OkCancelCustom:[t.ok,t.cancel]}:"yes"in t&&"no"in t&&"cancel"in t?{YesNoCancelCustom:[t.yes,t.no,t.cancel]}:"ok"in t?{OkCustom:t.ok}:void 0}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const o="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:o?.title?.toString(),kind:o?.kind,yesButtonLabel:o?.okLabel?.toString(),noButtonLabel:o?.cancelLabel?.toString()})},t.confirm=async function(t,e){const o="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:o?.title?.toString(),kind:o?.kind,okButtonLabel:o?.okLabel?.toString(),cancelButtonLabel:o?.cancelLabel?.toString()})},t.message=async function(t,o){const i="string"==typeof o?{title:o}:o;return n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),buttons:e(i?.buttons)})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})} if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,yesButtonLabel:i?.okLabel?.toString(),noButtonLabel:i?.cancelLabel?.toString()})},t.confirm=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),cancelButtonLabel:i?.cancelLabel?.toString()})},t.message=async function(t,e){const i="string"==typeof e?{title:e}:e;await n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString()})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})}
+5 -175
View File
@@ -14,16 +14,6 @@ interface DialogFilter {
name: string name: string
/** /**
* Extensions to filter, without a `.` prefix. * Extensions to filter, without a `.` prefix.
*
* **Note:** Mobile platforms have different APIs for filtering that may not support extensions.
* iOS: Extensions are supported in the document picker, but not in the media picker.
* Android: Extensions are not supported.
*
* For these platforms, MIME types are the primary way to filter files, as opposed to extensions.
* This means the string values here labeled as `extensions` may also be a MIME type.
* This property name of `extensions` is being kept for backwards compatibility, but this may be revisited to
* specify the difference between extension or MIME type filtering.
*
* @example * @example
* ```typescript * ```typescript
* extensions: ['svg', 'png'] * extensions: ['svg', 'png']
@@ -40,14 +30,7 @@ interface DialogFilter {
interface OpenDialogOptions { interface OpenDialogOptions {
/** The title of the dialog window (desktop only). */ /** The title of the dialog window (desktop only). */
title?: string title?: string
/** /** The filters of the dialog. */
* The filters of the dialog.
* On mobile platforms, if either:
* A) the {@linkcode pickerMode} is set to `media`, `image`, or `video`
* -- or --
* B) the filters include **only** either image or video mime types, the media picker will be displayed.
* Otherwise, the document picker will be displayed.
*/
filters?: DialogFilter[] filters?: DialogFilter[]
/** /**
* Initial directory or file path. * Initial directory or file path.
@@ -69,13 +52,6 @@ interface OpenDialogOptions {
recursive?: boolean recursive?: boolean
/** Whether to allow creating directories in the dialog. Enabled by default. **macOS Only** */ /** Whether to allow creating directories in the dialog. Enabled by default. **macOS Only** */
canCreateDirectories?: boolean canCreateDirectories?: boolean
/**
* The preferred mode of the dialog.
* This is meant for mobile platforms (iOS and Android) which have distinct file and media pickers.
* If not provided, the dialog will automatically choose the best mode based on the MIME types or extensions of the {@linkcode filters}.
* On desktop, this option is ignored.
*/
pickerMode?: PickerMode
} }
/** /**
@@ -101,90 +77,6 @@ interface SaveDialogOptions {
canCreateDirectories?: boolean canCreateDirectories?: boolean
} }
/**
* The preferred mode of the dialog.
* This is meant for mobile platforms (iOS and Android) which have distinct file and media pickers.
* On desktop, this option is ignored.
* If not provided, the dialog will automatically choose the best mode based on the MIME types or extensions of the {@linkcode filters}.
*
* **Note:** This option is only supported on iOS 14 and above. This parameter is ignored on iOS 13 and below.
*/
export type PickerMode = 'document' | 'media' | 'image' | 'video'
/**
* Default buttons for a message dialog.
*
* @since 2.4.0
*/
export type MessageDialogDefaultButtons =
| 'Ok'
| 'OkCancel'
| 'YesNo'
| 'YesNoCancel'
/** All possible button keys. */
type ButtonKey = 'ok' | 'cancel' | 'yes' | 'no'
/** Ban everything except a set of keys. */
type BanExcept<Allowed extends ButtonKey> = Partial<
Record<Exclude<ButtonKey, Allowed>, never>
>
/**
* The Yes, No and Cancel buttons of a message dialog.
*
* @since 2.4.0
*/
export type MessageDialogButtonsYesNoCancel = {
/** The Yes button. */
yes: string
/** The No button. */
no: string
/** The Cancel button. */
cancel: string
} & BanExcept<'yes' | 'no' | 'cancel'>
/**
* The Ok and Cancel buttons of a message dialog.
*
* @since 2.4.0
*/
export type MessageDialogButtonsOkCancel = {
/** The Ok button. */
ok: string
/** The Cancel button. */
cancel: string
} & BanExcept<'ok' | 'cancel'>
/**
* The Ok button of a message dialog.
*
* @since 2.4.0
*/
export type MessageDialogButtonsOk = {
/** The Ok button. */
ok: string
} & BanExcept<'ok'>
/**
* Custom buttons for a message dialog.
*
* @since 2.4.0
*/
export type MessageDialogCustomButtons =
| MessageDialogButtonsYesNoCancel
| MessageDialogButtonsOkCancel
| MessageDialogButtonsOk
/**
* The buttons of a message dialog.
*
* @since 2.4.0
*/
export type MessageDialogButtons =
| MessageDialogDefaultButtons
| MessageDialogCustomButtons
/** /**
* @since 2.0.0 * @since 2.0.0
*/ */
@@ -193,58 +85,8 @@ interface MessageDialogOptions {
title?: string title?: string
/** The kind of the dialog. Defaults to `info`. */ /** The kind of the dialog. Defaults to `info`. */
kind?: 'info' | 'warning' | 'error' kind?: 'info' | 'warning' | 'error'
/** /** The label of the confirm button. */
* The label of the Ok button.
*
* @deprecated Use {@linkcode MessageDialogOptions.buttons} instead.
*/
okLabel?: string okLabel?: string
/**
* The buttons of the dialog.
*
* @example
*
* ```ts
* // Use system default buttons texts
* await message('Hello World!', { buttons: 'Ok' })
* await message('Hello World!', { buttons: 'OkCancel' })
*
* // Or with custom button texts
* await message('Hello World!', { buttons: { ok: 'Yes!' } })
* await message('Take on the task?', {
* buttons: { ok: 'Accept', cancel: 'Cancel' }
* })
* await message('Show the file content?', {
* buttons: { yes: 'Show content', no: 'Show in folder', cancel: 'Cancel' }
* })
* ```
*
* @since 2.4.0
*/
buttons?: MessageDialogButtons
}
/**
* Internal function to convert the buttons to the Rust type.
*/
function buttonsToRust(buttons: MessageDialogButtons | undefined) {
if (buttons === undefined) {
return undefined
}
if (typeof buttons === 'string') {
return buttons
} else if ('ok' in buttons && 'cancel' in buttons) {
return { OkCancelCustom: [buttons.ok, buttons.cancel] }
} else if ('yes' in buttons && 'no' in buttons && 'cancel' in buttons) {
return {
YesNoCancelCustom: [buttons.yes, buttons.no, buttons.cancel]
}
} else if ('ok' in buttons) {
return { OkCustom: buttons.ok }
}
return undefined
} }
interface ConfirmDialogOptions { interface ConfirmDialogOptions {
@@ -360,16 +202,6 @@ async function save(options: SaveDialogOptions = {}): Promise<string | null> {
return await invoke('plugin:dialog|save', { options }) return await invoke('plugin:dialog|save', { options })
} }
/**
* The result of a message dialog.
*
* The result is a string if the dialog has custom buttons,
* otherwise it is one of the default buttons.
*
* @since 2.4.0
*/
export type MessageDialogResult = 'Yes' | 'No' | 'Ok' | 'Cancel' | (string & {})
/** /**
* Shows a message dialog with an `Ok` button. * Shows a message dialog with an `Ok` button.
* @example * @example
@@ -390,15 +222,13 @@ export type MessageDialogResult = 'Yes' | 'No' | 'Ok' | 'Cancel' | (string & {})
async function message( async function message(
message: string, message: string,
options?: string | MessageDialogOptions options?: string | MessageDialogOptions
): Promise<MessageDialogResult> { ): Promise<void> {
const opts = typeof options === 'string' ? { title: options } : options const opts = typeof options === 'string' ? { title: options } : options
await invoke('plugin:dialog|message', {
return invoke<MessageDialogResult>('plugin:dialog|message', {
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
kind: opts?.kind, kind: opts?.kind,
okButtonLabel: opts?.okLabel?.toString(), okButtonLabel: opts?.okLabel?.toString()
buttons: buttonsToRust(opts?.buttons)
}) })
} }
+70 -129
View File
@@ -8,7 +8,6 @@ import PhotosUI
import SwiftRs import SwiftRs
import Tauri import Tauri
import UIKit import UIKit
import UniformTypeIdentifiers
import WebKit import WebKit
enum FilePickerEvent { enum FilePickerEvent {
@@ -21,7 +20,6 @@ struct MessageDialogOptions: Decodable {
var title: String? var title: String?
let message: String let message: String
var okButtonLabel: String? var okButtonLabel: String?
var noButtonLabel: String?
var cancelButtonLabel: String? var cancelButtonLabel: String?
} }
@@ -33,7 +31,6 @@ struct FilePickerOptions: Decodable {
var multiple: Bool? var multiple: Bool?
var filters: [Filter]? var filters: [Filter]?
var defaultPath: String? var defaultPath: String?
var pickerMode: PickerMode?
} }
struct SaveFileDialogOptions: Decodable { struct SaveFileDialogOptions: Decodable {
@@ -41,13 +38,6 @@ struct SaveFileDialogOptions: Decodable {
var defaultPath: String? var defaultPath: String?
} }
enum PickerMode: String, Decodable {
case document
case media
case image
case video
}
class DialogPlugin: Plugin { class DialogPlugin: Plugin {
var filePickerController: FilePickerController! var filePickerController: FilePickerController!
@@ -61,6 +51,26 @@ class DialogPlugin: Plugin {
@objc public func showFilePicker(_ invoke: Invoke) throws { @objc public func showFilePicker(_ invoke: Invoke) throws {
let args = try invoke.parseArgs(FilePickerOptions.self) let args = try invoke.parseArgs(FilePickerOptions.self)
let parsedTypes = parseFiltersOption(args.filters ?? [])
var isMedia = !parsedTypes.isEmpty
var uniqueMimeType: Bool? = nil
var mimeKind: String? = nil
if !parsedTypes.isEmpty {
uniqueMimeType = true
for mime in parsedTypes {
let kind = mime.components(separatedBy: "/")[0]
if kind != "image" && kind != "video" {
isMedia = false
}
if mimeKind == nil {
mimeKind = kind
} else if mimeKind != kind {
uniqueMimeType = false
}
}
}
onFilePickerResult = { (event: FilePickerEvent) -> Void in onFilePickerResult = { (event: FilePickerEvent) -> Void in
switch event { switch event {
case .selected(let urls): case .selected(let urls):
@@ -70,57 +80,51 @@ class DialogPlugin: Plugin {
case .error(let error): case .error(let error):
invoke.reject(error) invoke.reject(error)
} }
} }
if #available(iOS 14, *) { if uniqueMimeType == true || isMedia {
let parsedTypes = parseFiltersOption(args.filters ?? []) DispatchQueue.main.async {
if #available(iOS 14, *) {
let mimeKinds = Set(parsedTypes.compactMap { $0.preferredMIMEType?.components(separatedBy: "/")[0] })
let filtersIncludeImage = mimeKinds.contains("image")
let filtersIncludeVideo = mimeKinds.contains("video")
let filtersIncludeNonMedia = mimeKinds.contains(where: { $0 != "image" && $0 != "video" })
// If the picker mode is media, images, or videos, we always want to show the media picker regardless of what's in the filters.
// Otherwise, if the filters A) do not include non-media types and B) include either image or video, we want to show the media picker.
if args.pickerMode == .media
|| args.pickerMode == .image
|| args.pickerMode == .video
|| (!filtersIncludeNonMedia && (filtersIncludeImage || filtersIncludeVideo)) {
DispatchQueue.main.async {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared()) var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.selectionLimit = (args.multiple ?? false) ? 0 : 1 configuration.selectionLimit = (args.multiple ?? false) ? 0 : 1
// If the filters include image or video, use the appropriate filter. if uniqueMimeType == true {
// If both are true, don't define a filter, which means we will display all media. if mimeKind == "image" {
if args.pickerMode == .image || (filtersIncludeImage && !filtersIncludeVideo) { configuration.filter = .images
configuration.filter = .images } else if mimeKind == "video" {
} else if args.pickerMode == .video || (filtersIncludeVideo && !filtersIncludeImage) { configuration.filter = .videos
configuration.filter = .videos }
} }
let picker = PHPickerViewController(configuration: configuration) let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self.filePickerController picker.delegate = self.filePickerController
picker.modalPresentationStyle = .fullScreen picker.modalPresentationStyle = .fullScreen
self.presentViewController(picker) self.presentViewController(picker)
} } else {
} else { let picker = UIImagePickerController()
DispatchQueue.main.async { picker.delegate = self.filePickerController
// The UTType.item is the catch-all, allowing for any file type to be selected.
let contentTypes = parsedTypes.isEmpty ? [UTType.item] : parsedTypes if uniqueMimeType == true && mimeKind == "image" {
let picker: UIDocumentPickerViewController = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true) picker.sourceType = .photoLibrary
if let defaultPath = args.defaultPath {
picker.directoryURL = URL(string: defaultPath)
} }
picker.delegate = self.filePickerController picker.sourceType = .photoLibrary
picker.allowsMultipleSelection = args.multiple ?? false
picker.modalPresentationStyle = .fullScreen picker.modalPresentationStyle = .fullScreen
self.presentViewController(picker) self.presentViewController(picker)
} }
} }
} else { } else {
showFilePickerLegacy(args: args) let documentTypes = parsedTypes.isEmpty ? ["public.data"] : parsedTypes
DispatchQueue.main.async {
let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
if let defaultPath = args.defaultPath {
picker.directoryURL = URL(string: defaultPath)
}
picker.delegate = self.filePickerController
picker.allowsMultipleSelection = args.multiple ?? false
picker.modalPresentationStyle = .fullScreen
self.presentViewController(picker)
}
} }
} }
@@ -168,80 +172,19 @@ class DialogPlugin: Plugin {
self.manager.viewController?.present(viewControllerToPresent, animated: true, completion: nil) self.manager.viewController?.present(viewControllerToPresent, animated: true, completion: nil)
} }
@available(iOS 14, *) private func parseFiltersOption(_ filters: [Filter]) -> [String] {
private func parseFiltersOption(_ filters: [Filter]) -> [UTType] {
var parsedTypes: [UTType] = []
for filter in filters {
for ext in filter.extensions ?? [] {
// We need to support extensions as well as MIME types.
if let utType = UTType(mimeType: ext) {
parsedTypes.append(utType)
} else if let utType = UTType(filenameExtension: ext) {
parsedTypes.append(utType)
}
}
}
return parsedTypes
}
/// This function is only used for iOS < 14, and should be removed if/when the deployment target is raised to 14.
private func showFilePickerLegacy(args: FilePickerOptions) {
let parsedTypes = parseFiltersOptionLegacy(args.filters ?? [])
var filtersIncludeImage: Bool = false
var filtersIncludeVideo: Bool = false
var filtersIncludeNonMedia: Bool = false
if !parsedTypes.isEmpty {
let mimeKinds = Set(parsedTypes.map { $0.components(separatedBy: "/")[0] })
filtersIncludeImage = mimeKinds.contains("image")
filtersIncludeVideo = mimeKinds.contains("video")
filtersIncludeNonMedia = mimeKinds.contains(where: { $0 != "image" && $0 != "video" })
}
if !filtersIncludeNonMedia && (filtersIncludeImage || filtersIncludeVideo) {
DispatchQueue.main.async {
let picker = UIImagePickerController()
picker.delegate = self.filePickerController
if filtersIncludeImage && !filtersIncludeVideo {
picker.sourceType = .photoLibrary
}
picker.modalPresentationStyle = .fullScreen
self.presentViewController(picker)
}
} else {
let documentTypes = parsedTypes.isEmpty ? ["public.data"] : parsedTypes
DispatchQueue.main.async {
let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
if let defaultPath = args.defaultPath {
picker.directoryURL = URL(string: defaultPath)
}
picker.delegate = self.filePickerController
picker.allowsMultipleSelection = args.multiple ?? false
picker.modalPresentationStyle = .fullScreen
self.presentViewController(picker)
}
}
}
/// This function is only used for iOS < 14, and should be removed if/when the deployment target is raised to 14.
private func parseFiltersOptionLegacy(_ filters: [Filter]) -> [String] {
var parsedTypes: [String] = [] var parsedTypes: [String] = []
for filter in filters { for filter in filters {
for ext in filter.extensions ?? [] { for ext in filter.extensions ?? [] {
guard guard
let utType: String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, ext as CFString, nil)?.takeRetainedValue() as String? let utType: String = UTTypeCreatePreferredIdentifierForTag(
kUTTagClassMIMEType, ext as CFString, nil)?.takeRetainedValue() as String?
else { else {
continue continue
} }
parsedTypes.append(utType) parsedTypes.append(utType)
} }
} }
return parsedTypes return parsedTypes
} }
@@ -257,37 +200,35 @@ class DialogPlugin: Plugin {
let alert = UIAlertController( let alert = UIAlertController(
title: args.title, message: args.message, preferredStyle: UIAlertController.Style.alert) title: args.title, message: args.message, preferredStyle: UIAlertController.Style.alert)
if let cancelButtonLabel = args.cancelButtonLabel { let cancelButtonLabel = args.cancelButtonLabel ?? ""
if !cancelButtonLabel.isEmpty {
alert.addAction( alert.addAction(
UIAlertAction( UIAlertAction(
title: cancelButtonLabel, style: UIAlertAction.Style.default, title: cancelButtonLabel, style: UIAlertAction.Style.default,
handler: { (_) -> Void in handler: { (_) -> Void in
invoke.resolve(["value": cancelButtonLabel]) Logger.error("cancel")
}
) invoke.resolve([
) "value": false,
"cancelled": false,
])
}))
} }
if let noButtonLabel = args.noButtonLabel { let okButtonLabel = args.okButtonLabel ?? (cancelButtonLabel.isEmpty ? "OK" : "")
if !okButtonLabel.isEmpty {
alert.addAction( alert.addAction(
UIAlertAction( UIAlertAction(
title: noButtonLabel, style: UIAlertAction.Style.default, title: okButtonLabel, style: UIAlertAction.Style.default,
handler: { (_) -> Void in handler: { (_) -> Void in
invoke.resolve(["value": noButtonLabel]) Logger.error("ok")
}
)
)
}
let okButtonLabel = args.okButtonLabel ?? "Ok" invoke.resolve([
alert.addAction( "value": true,
UIAlertAction( "cancelled": false,
title: okButtonLabel, style: UIAlertAction.Style.default, ])
handler: { (_) -> Void in }))
invoke.resolve(["value": okButtonLabel]) }
}
)
)
manager.viewController?.present(alert, animated: true, completion: nil) manager.viewController?.present(alert, animated: true, completion: nil)
} }

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