diff --git a/Cargo.lock b/Cargo.lock index cc576e529c..308b37e542 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6562,6 +6562,7 @@ name = "tauri-plugin-deep-link" version = "2.4.1" dependencies = [ "dunce", + "plist", "rust-ini", "serde", "serde_json", diff --git a/plugins/deep-link/Cargo.toml b/plugins/deep-link/Cargo.toml index 7c8524bfcb..2b0cd5c522 100644 --- a/plugins/deep-link/Cargo.toml +++ b/plugins/deep-link/Cargo.toml @@ -27,6 +27,9 @@ serde_json = { workspace = true } tauri-utils = { workspace = true } tauri-plugin = { workspace = true, features = ["build"] } +[target."cfg(target_os = \"macos\")".build-dependencies] +plist = "1" + [dependencies] serde = { workspace = true } serde_json = { workspace = true } diff --git a/plugins/deep-link/build.rs b/plugins/deep-link/build.rs index 418746b234..16d2a96e57 100644 --- a/plugins/deep-link/build.rs +++ b/plugins/deep-link/build.rs @@ -10,50 +10,64 @@ const COMMANDS: &[&str] = &["get_current", "register", "unregister", "is_registe // TODO: Consider using activity-alias in case users may have multiple activities in their app. fn intent_filter(domain: &AssociatedDomain) -> String { + let host = domain + .host + .as_ref() + .map(|h| format!(r#""#)) + .unwrap_or_default(); + + let auto_verify = if domain.is_app_link() { + r#"android:autoVerify="true" "#.to_string() + } else { + String::new() + }; + format!( - r#" + r#" - {} - - {} - {} - {} - {} + {schemes} + {host} + {domains} + {path_patterns} + {path_prefixes} + {path_suffixes} "#, - domain + schemes = domain .scheme .iter() .map(|scheme| format!(r#""#)) .collect::>() .join("\n "), - domain.host, - domain + host = host, + domains = domain .path .iter() .map(|path| format!(r#""#)) .collect::>() .join("\n "), - domain + path_patterns = domain .path_pattern .iter() .map(|pattern| format!(r#""#)) .collect::>() .join("\n "), - domain + path_prefixes = domain .path_prefix .iter() .map(|prefix| format!(r#""#)) .collect::>() .join("\n "), - domain + path_suffixes = domain .path_suffix .iter() .map(|suffix| format!(r#""#)) .collect::>() .join("\n "), ) + .trim() + .to_string() } fn main() { @@ -68,6 +82,16 @@ fn main() { } if let Some(config) = tauri_plugin::plugin_config::("deep-link") { + let errors: Vec = 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( "DEEP LINK PLUGIN", "activity", @@ -80,20 +104,89 @@ fn main() { ) .expect("failed to rewrite AndroidManifest.xml"); - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] { - tauri_plugin::mobile::update_entitlements(|entitlements| { - entitlements.insert( - "com.apple.developer.associated-domains".into(), - config - .mobile - .into_iter() - .map(|d| format!("applinks:{}", d.host).into()) - .collect::>() - .into(), - ); - }) - .expect("failed to update entitlements"); + // we need to ensure that the entitlements are only + // generated for explicit app links and not + // other deep links because then they + // are just going to complain and not be built or signed + let has_app_links = config.mobile.iter().any(|d| d.is_app_link()); + + if !has_app_links { + tauri_plugin::mobile::update_entitlements(|entitlements| { + entitlements.remove("com.apple.developer.associated-domains"); + }) + .expect("failed to update entitlements"); + } else { + tauri_plugin::mobile::update_entitlements(|entitlements| { + 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::>() + .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::>(); + + 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::>(); + + let mut dict = plist::Dictionary::new(); + dict.insert( + "CFBundleURLSchemes".into(), + schemes + .iter() + .map(|s| s.to_string().into()) + .collect::>() + .into(), + ); + dict.insert( + "CFBundleURLName".into(), + format!("{}", domain.scheme[0]).into(), + ); + plist::Value::Dictionary(dict) + }) + .collect::>() + .into(), + ); + }) + .expect("failed to update Info.plist"); + } } } } diff --git a/plugins/deep-link/examples/app/package.json b/plugins/deep-link/examples/app/package.json index c18b68dcbc..d983985581 100644 --- a/plugins/deep-link/examples/app/package.json +++ b/plugins/deep-link/examples/app/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@tauri-apps/api": "2.8.0", - "@tauri-apps/plugin-deep-link": "2.4.1" + "@tauri-apps/plugin-deep-link": "link:../.." }, "devDependencies": { "@tauri-apps/cli": "2.8.0", diff --git a/plugins/deep-link/examples/app/src-tauri/gen/android/app/build.gradle.kts b/plugins/deep-link/examples/app/src-tauri/gen/android/app/build.gradle.kts index f434bbfb0d..13ec1ffd66 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/android/app/build.gradle.kts +++ b/plugins/deep-link/examples/app/src-tauri/gen/android/app/build.gradle.kts @@ -14,13 +14,13 @@ val tauriProperties = Properties().apply { } android { - compileSdk = 34 + compileSdk = 36 namespace = "com.tauri.deep_link_example" defaultConfig { manifestPlaceholders["usesCleartextTraffic"] = "false" applicationId = "com.tauri.deep_link_example" minSdk = 24 - targetSdk = 34 + targetSdk = 36 versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") } @@ -58,9 +58,10 @@ rust { } dependencies { - implementation("androidx.webkit:webkit:1.6.1") - implementation("androidx.appcompat:appcompat:1.6.1") - implementation("com.google.android.material:material:1.8.0") + implementation("androidx.webkit:webkit:1.14.0") + implementation("androidx.appcompat:appcompat:1.7.1") + implementation("androidx.activity:activity-ktx:1.10.1") + implementation("com.google.android.material:material:1.12.0") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.4") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") diff --git a/plugins/deep-link/examples/app/src-tauri/gen/android/app/src/main/AndroidManifest.xml b/plugins/deep-link/examples/app/src-tauri/gen/android/app/src/main/AndroidManifest.xml index 05265e325f..591f3c61e3 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/android/app/src/main/AndroidManifest.xml +++ b/plugins/deep-link/examples/app/src-tauri/gen/android/app/src/main/AndroidManifest.xml @@ -23,23 +23,40 @@ - + - + + + + - + - + + + + + + + + + + + + + + + diff --git a/plugins/deep-link/examples/app/src-tauri/gen/android/app/src/main/java/com/tauri/deep_link_example/MainActivity.kt b/plugins/deep-link/examples/app/src-tauri/gen/android/app/src/main/java/com/tauri/deep_link_example/MainActivity.kt index e13fb99560..313161c226 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/android/app/src/main/java/com/tauri/deep_link_example/MainActivity.kt +++ b/plugins/deep-link/examples/app/src-tauri/gen/android/app/src/main/java/com/tauri/deep_link_example/MainActivity.kt @@ -1,7 +1,11 @@ -// 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 -class MainActivity : TauriActivity() +import android.os.Bundle +import androidx.activity.enableEdgeToEdge + +class MainActivity : TauriActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + enableEdgeToEdge() + super.onCreate(savedInstanceState) + } +} diff --git a/plugins/deep-link/examples/app/src-tauri/gen/android/build.gradle.kts b/plugins/deep-link/examples/app/src-tauri/gen/android/build.gradle.kts index c5ef452a67..607240bc8f 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/android/build.gradle.kts +++ b/plugins/deep-link/examples/app/src-tauri/gen/android/build.gradle.kts @@ -4,7 +4,7 @@ buildscript { mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:8.5.1") + classpath("com.android.tools.build:gradle:8.11.0") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") } } diff --git a/plugins/deep-link/examples/app/src-tauri/gen/android/buildSrc/build.gradle.kts b/plugins/deep-link/examples/app/src-tauri/gen/android/buildSrc/build.gradle.kts index 39e90b0543..5c55bba71c 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/android/buildSrc/build.gradle.kts +++ b/plugins/deep-link/examples/app/src-tauri/gen/android/buildSrc/build.gradle.kts @@ -18,6 +18,6 @@ repositories { dependencies { compileOnly(gradleApi()) - implementation("com.android.tools.build:gradle:8.5.1") + implementation("com.android.tools.build:gradle:8.11.0") } diff --git a/plugins/deep-link/examples/app/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties b/plugins/deep-link/examples/app/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties index 0df10d556c..c5f9a53c27 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties +++ b/plugins/deep-link/examples/app/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue May 10 19:22:52 CST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/plugins/deep-link/examples/app/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json b/plugins/deep-link/examples/app/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json index dd3b8bcc55..90eea7ec7e 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/plugins/deep-link/examples/app/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,116 +1,116 @@ { - "images": [ + "images" : [ { - "size": "20x20", - "idiom": "iphone", - "filename": "AppIcon-20x20@2x.png", - "scale": "2x" + "size" : "20x20", + "idiom" : "iphone", + "filename" : "AppIcon-20x20@2x.png", + "scale" : "2x" }, { - "size": "20x20", - "idiom": "iphone", - "filename": "AppIcon-20x20@3x.png", - "scale": "3x" + "size" : "20x20", + "idiom" : "iphone", + "filename" : "AppIcon-20x20@3x.png", + "scale" : "3x" }, { - "size": "29x29", - "idiom": "iphone", - "filename": "AppIcon-29x29@2x-1.png", - "scale": "2x" + "size" : "29x29", + "idiom" : "iphone", + "filename" : "AppIcon-29x29@2x-1.png", + "scale" : "2x" }, { - "size": "29x29", - "idiom": "iphone", - "filename": "AppIcon-29x29@3x.png", - "scale": "3x" + "size" : "29x29", + "idiom" : "iphone", + "filename" : "AppIcon-29x29@3x.png", + "scale" : "3x" }, { - "size": "40x40", - "idiom": "iphone", - "filename": "AppIcon-40x40@2x.png", - "scale": "2x" + "size" : "40x40", + "idiom" : "iphone", + "filename" : "AppIcon-40x40@2x.png", + "scale" : "2x" }, { - "size": "40x40", - "idiom": "iphone", - "filename": "AppIcon-40x40@3x.png", - "scale": "3x" + "size" : "40x40", + "idiom" : "iphone", + "filename" : "AppIcon-40x40@3x.png", + "scale" : "3x" }, { - "size": "60x60", - "idiom": "iphone", - "filename": "AppIcon-60x60@2x.png", - "scale": "2x" + "size" : "60x60", + "idiom" : "iphone", + "filename" : "AppIcon-60x60@2x.png", + "scale" : "2x" }, { - "size": "60x60", - "idiom": "iphone", - "filename": "AppIcon-60x60@3x.png", - "scale": "3x" + "size" : "60x60", + "idiom" : "iphone", + "filename" : "AppIcon-60x60@3x.png", + "scale" : "3x" }, { - "size": "20x20", - "idiom": "ipad", - "filename": "AppIcon-20x20@1x.png", - "scale": "1x" + "size" : "20x20", + "idiom" : "ipad", + "filename" : "AppIcon-20x20@1x.png", + "scale" : "1x" }, { - "size": "20x20", - "idiom": "ipad", - "filename": "AppIcon-20x20@2x-1.png", - "scale": "2x" + "size" : "20x20", + "idiom" : "ipad", + "filename" : "AppIcon-20x20@2x-1.png", + "scale" : "2x" }, { - "size": "29x29", - "idiom": "ipad", - "filename": "AppIcon-29x29@1x.png", - "scale": "1x" + "size" : "29x29", + "idiom" : "ipad", + "filename" : "AppIcon-29x29@1x.png", + "scale" : "1x" }, { - "size": "29x29", - "idiom": "ipad", - "filename": "AppIcon-29x29@2x.png", - "scale": "2x" + "size" : "29x29", + "idiom" : "ipad", + "filename" : "AppIcon-29x29@2x.png", + "scale" : "2x" }, { - "size": "40x40", - "idiom": "ipad", - "filename": "AppIcon-40x40@1x.png", - "scale": "1x" + "size" : "40x40", + "idiom" : "ipad", + "filename" : "AppIcon-40x40@1x.png", + "scale" : "1x" }, { - "size": "40x40", - "idiom": "ipad", - "filename": "AppIcon-40x40@2x-1.png", - "scale": "2x" + "size" : "40x40", + "idiom" : "ipad", + "filename" : "AppIcon-40x40@2x-1.png", + "scale" : "2x" }, { - "size": "76x76", - "idiom": "ipad", - "filename": "AppIcon-76x76@1x.png", - "scale": "1x" + "size" : "76x76", + "idiom" : "ipad", + "filename" : "AppIcon-76x76@1x.png", + "scale" : "1x" }, { - "size": "76x76", - "idiom": "ipad", - "filename": "AppIcon-76x76@2x.png", - "scale": "2x" + "size" : "76x76", + "idiom" : "ipad", + "filename" : "AppIcon-76x76@2x.png", + "scale" : "2x" }, { - "size": "83.5x83.5", - "idiom": "ipad", - "filename": "AppIcon-83.5x83.5@2x.png", - "scale": "2x" + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "AppIcon-83.5x83.5@2x.png", + "scale" : "2x" }, { - "size": "1024x1024", - "idiom": "ios-marketing", - "filename": "AppIcon-512@2x.png", - "scale": "1x" + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "AppIcon-512@2x.png", + "scale" : "1x" } ], - "info": { - "version": 1, - "author": "xcode" + "info" : { + "version" : 1, + "author" : "xcode" } -} +} \ No newline at end of file diff --git a/plugins/deep-link/examples/app/src-tauri/gen/apple/Assets.xcassets/Contents.json b/plugins/deep-link/examples/app/src-tauri/gen/apple/Assets.xcassets/Contents.json index 97a8662ebd..da4a164c91 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/apple/Assets.xcassets/Contents.json +++ b/plugins/deep-link/examples/app/src-tauri/gen/apple/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { - "info": { - "version": 1, - "author": "xcode" + "info" : { + "version" : 1, + "author" : "xcode" } -} +} \ No newline at end of file diff --git a/plugins/deep-link/examples/app/src-tauri/gen/apple/LaunchScreen.storyboard b/plugins/deep-link/examples/app/src-tauri/gen/apple/LaunchScreen.storyboard index dd79351ec8..81b5f90e2f 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/apple/LaunchScreen.storyboard +++ b/plugins/deep-link/examples/app/src-tauri/gen/apple/LaunchScreen.storyboard @@ -1,5 +1,5 @@ - + diff --git a/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example.xcodeproj/project.pbxproj b/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example.xcodeproj/project.pbxproj index 450bd84706..4c01a958a8 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example.xcodeproj/project.pbxproj +++ b/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 56; + objectVersion = 63; objects = { /* Begin PBXBuildFile section */ @@ -167,6 +167,8 @@ dependencies = ( ); name = "deep-link-example_iOS"; + packageProductDependencies = ( + ); productName = "deep-link-example_iOS"; productReference = 1CAAFA750FD735A285DC1238 /* deep-link-example.app */; productType = "com.apple.product-type.application"; @@ -189,6 +191,7 @@ en, ); mainGroup = 1DC58B1705AA3ECC6B887FE7; + minimizedProjectReferenceProxies = 1; projectDirPath = ""; projectRoot = ""; targets = ( @@ -227,7 +230,6 @@ outputPaths = ( "$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a", "$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a", - "$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -314,18 +316,13 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ARCHS = ( - arm64, - "arm64-sim", - ); + ARCHS = arm64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = Q93MBH6S2F; + DEVELOPMENT_TEAM = "Q93MBH6S2F"; ENABLE_BITCODE = NO; - "EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64"; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "\".\"", @@ -335,13 +332,6 @@ "$(inherited)", "@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]" = ( "$(inherited)", "$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)", @@ -360,7 +350,7 @@ PRODUCT_NAME = "deep-link-example"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = "arm64 arm64-sim"; + VALID_ARCHS = arm64; }; name = debug; }; @@ -424,18 +414,13 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ARCHS = ( - arm64, - "arm64-sim", - ); + ARCHS = arm64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = Q93MBH6S2F; + DEVELOPMENT_TEAM = "Q93MBH6S2F"; ENABLE_BITCODE = NO; - "EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64"; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "\".\"", @@ -445,13 +430,6 @@ "$(inherited)", "@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]" = ( "$(inherited)", "$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)", @@ -470,7 +448,7 @@ PRODUCT_NAME = "deep-link-example"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = "arm64 arm64-sim"; + VALID_ARCHS = arm64; }; name = release; }; diff --git a/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example_iOS/Info.plist b/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example_iOS/Info.plist index 7ce8661409..bc74b01bc2 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example_iOS/Info.plist +++ b/plugins/deep-link/examples/app/src-tauri/gen/apple/deep-link-example_iOS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.0.0 + 0.1.0 CFBundleVersion 0.1.0 LSRequiresIPhoneOS @@ -40,5 +40,16 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + CFBundleURLTypes + + + CFBundleURLSchemes + + taurideeplink + + CFBundleURLName + taurideeplink + + \ No newline at end of file diff --git a/plugins/deep-link/examples/app/src-tauri/gen/apple/project.yml b/plugins/deep-link/examples/app/src-tauri/gen/apple/project.yml index c924ca77bd..74d0ab4919 100644 --- a/plugins/deep-link/examples/app/src-tauri/gen/apple/project.yml +++ b/plugins/deep-link/examples/app/src-tauri/gen/apple/project.yml @@ -1,7 +1,3 @@ -# Copyright 2019-2023 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - name: deep-link-example options: bundleIdPrefix: com.tauri.deep-link-example @@ -16,7 +12,6 @@ settingGroups: base: PRODUCT_NAME: deep-link-example PRODUCT_BUNDLE_IDENTIFIER: com.tauri.deep-link-example - DEVELOPMENT_TEAM: Q93MBH6S2F targetTemplates: app: type: application @@ -56,8 +51,8 @@ targets: - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - CFBundleShortVersionString: 0.0.0 - CFBundleVersion: 0.0.0 + CFBundleShortVersionString: 0.1.0 + CFBundleVersion: '0.1.0' entitlements: path: deep-link-example_iOS/deep-link-example_iOS.entitlements scheme: @@ -67,14 +62,12 @@ targets: settings: base: ENABLE_BITCODE: false - ARCHS: [arm64, arm64-sim] - VALID_ARCHS: arm64 arm64-sim + ARCHS: [arm64] + VALID_ARCHS: arm64 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-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 - EXCLUDED_ARCHS[sdk=iphonesimulator*]: arm64 - EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64 + EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64 groups: [app] dependencies: - framework: libapp.a @@ -93,4 +86,3 @@ targets: outputFiles: - $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a - $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a - - $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a diff --git a/plugins/deep-link/examples/app/src-tauri/tauri.conf.json b/plugins/deep-link/examples/app/src-tauri/tauri.conf.json index ac1c292b46..61f7394df6 100644 --- a/plugins/deep-link/examples/app/src-tauri/tauri.conf.json +++ b/plugins/deep-link/examples/app/src-tauri/tauri.conf.json @@ -35,6 +35,9 @@ }, { "host": "tauri.app" + }, + { + "scheme": ["taurideeplink"] } ], "desktop": { diff --git a/plugins/deep-link/package.json b/plugins/deep-link/package.json index d3f474e774..bceab87b6b 100644 --- a/plugins/deep-link/package.json +++ b/plugins/deep-link/package.json @@ -26,5 +26,8 @@ ], "dependencies": { "@tauri-apps/api": "^2.8.0" + }, + "devDependencies": { + "@tauri-apps/cli": "2.8.0" } } diff --git a/plugins/deep-link/src/config.rs b/plugins/deep-link/src/config.rs index 88222a2461..49de68e3de 100644 --- a/plugins/deep-link/src/config.rs +++ b/plugins/deep-link/src/config.rs @@ -11,10 +11,8 @@ use tauri_utils::config::DeepLinkProtocol; pub struct AssociatedDomain { #[serde(default = "default_schemes")] pub scheme: Vec, - - #[serde(deserialize_with = "deserialize_associated_host")] - pub host: String, - + #[serde(default, deserialize_with = "deserialize_associated_host")] + pub host: Option, // Optional custom uri schemes dont NEED a host (may have one still), but required for https/http schemes #[serde(default)] pub path: Vec, #[serde(default, alias = "path-pattern", rename = "pathPattern")] @@ -23,6 +21,41 @@ pub struct AssociatedDomain { pub path_prefix: Vec, #[serde(default, alias = "path-suffix", rename = "pathSuffix")] pub path_suffix: Vec, + #[serde(default, alias = "app-link", rename = "appLink")] + pub app_link: Option, +} + +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 @@ -30,18 +63,19 @@ fn default_schemes() -> Vec { vec!["https".to_string(), "http".to_string()] } -fn deserialize_associated_host<'de, D>(deserializer: D) -> Result +fn deserialize_associated_host<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { - let host = String::deserialize(deserializer)?; - if let Some((scheme, _host)) = host.split_once("://") { - Err(serde::de::Error::custom(format!( - "host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix" - ))) - } else { - Ok(host) + let opt = Option::::deserialize(deserializer)?; + if let Some(ref host) = opt { + if let Some((scheme, _)) = host.split_once("://") { + return Err(serde::de::Error::custom(format!( + "host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix" + ))); + } } + Ok(opt) } #[derive(Deserialize, Clone)] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 222d1e3fda..65ca12f0d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -177,6 +177,10 @@ importers: '@tauri-apps/api': specifier: ^2.8.0 version: 2.8.0 + devDependencies: + '@tauri-apps/cli': + specifier: 2.8.0 + version: 2.8.0 plugins/deep-link/examples/app: dependencies: @@ -184,7 +188,7 @@ importers: specifier: 2.8.0 version: 2.8.0 '@tauri-apps/plugin-deep-link': - specifier: 2.4.1 + specifier: link:../.. version: link:../.. devDependencies: '@tauri-apps/cli':