Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/support-raw-entitlements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri-bundler": minor:feat
---

Support providing `plist::Value` as macOS entitlements.
7 changes: 7 additions & 0 deletions .changes/universal-app-links-macos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"tauri-cli": minor:feat
"@tauri-apps/cli": minor:feat
"tauri-utils": minor:feat
---

Added support to universal app links on macOS with the `plugins > deep-link > desktop > domains` configuration.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@ opt-level = "s"
schemars_derive = { git = 'https://github.com/tauri-apps/schemars.git', branch = 'feat/preserve-description-newlines' }
tauri = { path = "./crates/tauri" }
tauri-plugin = { path = "./crates/tauri-plugin" }
tauri-utils = { path = "./crates/tauri-utils" }
1 change: 1 addition & 0 deletions crates/tauri-bundler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ regex = "1"
goblin = "0.9"
plist = "1"


[target."cfg(target_os = \"windows\")".dependencies]
bitness = "0.4"
windows-registry = "0.5"
Expand Down
4 changes: 2 additions & 2 deletions crates/tauri-bundler/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ pub use self::{
category::AppCategory,
settings::{
AppImageSettings, BundleBinary, BundleSettings, CustomSignCommandSettings, DebianSettings,
DmgSettings, IosSettings, MacOsSettings, PackageSettings, PackageType, PlistKind, Position,
RpmSettings, Settings, SettingsBuilder, Size, UpdaterSettings,
DmgSettings, Entitlements, IosSettings, MacOsSettings, PackageSettings, PackageType, PlistKind,
Position, RpmSettings, Settings, SettingsBuilder, Size, UpdaterSettings,
},
};
pub use settings::{NsisSettings, WindowsSettings, WixLanguage, WixLanguageConfig, WixSettings};
Expand Down
1 change: 1 addition & 0 deletions crates/tauri-bundler/src/bundle/macos/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ fn create_info_plist(
plist::Value::Array(
protocols
.iter()
.filter(|p| !p.schemes.is_empty())
.map(|protocol| {
let mut dict = plist::Dictionary::new();
dict.insert(
Expand Down
19 changes: 12 additions & 7 deletions crates/tauri-bundler/src/bundle/macos/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
use std::{
env::{var, var_os},
ffi::OsString,
path::{Path, PathBuf},
path::PathBuf,
};

use crate::{error::NotarizeAuthError, Settings};
use crate::{error::NotarizeAuthError, Entitlements, Settings};

pub struct SignTarget {
pub path: PathBuf,
Expand Down Expand Up @@ -51,15 +51,20 @@ pub fn sign(
log::info!(action = "Signing"; "with identity \"{}\"", keychain.signing_identity());

for target in targets {
let entitlements_path = if target.is_an_executable {
settings.macos().entitlements.as_ref().map(Path::new)
} else {
None
let (entitlements_path, _temp_file) = match settings.macos().entitlements.as_ref() {
Some(Entitlements::Path(path)) => (Some(path.to_owned()), None),
Some(Entitlements::Plist(plist)) => {
let mut temp_file = tempfile::NamedTempFile::new()?;
plist::to_writer_xml(temp_file.as_file_mut(), &plist)?;
(Some(temp_file.path().to_path_buf()), Some(temp_file))
}
None => (None, None),
};

keychain
.sign(
&target.path,
entitlements_path,
entitlements_path.as_deref(),
target.is_an_executable && settings.macos().hardened_runtime,
)
.map_err(Box::new)?;
Expand Down
13 changes: 11 additions & 2 deletions crates/tauri-bundler/src/bundle/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,12 +360,21 @@ pub struct MacOsSettings {
pub hardened_runtime: bool,
/// Provider short name for notarization.
pub provider_short_name: Option<String>,
/// Path to the entitlements.plist file.
pub entitlements: Option<String>,
/// Path or contents of the entitlements.plist file.
pub entitlements: Option<Entitlements>,
/// Path to the Info.plist file or raw plist value to merge with the bundle Info.plist.
pub info_plist: Option<PlistKind>,
}

/// Entitlements for macOS code signing.
#[derive(Debug, Clone)]
pub enum Entitlements {
/// Path to the entitlements.plist file.
Path(PathBuf),
/// Raw plist::Value.
Plist(plist::Value),
}

/// Plist format.
#[derive(Debug, Clone)]
pub enum PlistKind {
Expand Down
4 changes: 3 additions & 1 deletion crates/tauri-bundler/src/bundle/windows/msi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,9 @@ pub fn build_wix_app_installer(
.iter()
.flat_map(|p| &p.schemes)
.collect::<Vec<_>>();
data.insert("deep_link_protocols", to_json(schemes));
if !schemes.is_empty() {
data.insert("deep_link_protocols", to_json(schemes));
}
}

if let Some(path) = custom_template_path {
Expand Down
4 changes: 3 additions & 1 deletion crates/tauri-bundler/src/bundle/windows/nsis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,9 @@ fn build_nsis_app_installer(
.iter()
.flat_map(|p| &p.schemes)
.collect::<Vec<_>>();
data.insert("deep_link_protocols", to_json(schemes));
if !schemes.is_empty() {
data.insert("deep_link_protocols", to_json(schemes));
}
}

let silent_webview2_install = if let WebviewInstallMode::DownloadBootstrapper { silent }
Expand Down
59 changes: 55 additions & 4 deletions crates/tauri-cli/src/interface/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ impl AppSettings for RustAppSettings {
let mut settings = tauri_config_to_bundle_settings(
self,
features,
config.identifier.clone(),
config,
config.bundle.clone(),
updater_settings,
arch64bits,
Expand Down Expand Up @@ -1263,7 +1263,7 @@ pub fn get_profile_dir(options: &Options) -> &str {
fn tauri_config_to_bundle_settings(
settings: &RustAppSettings,
features: &[String],
identifier: String,
tauri_config: &Config,
config: crate::helpers::config::BundleConfig,
updater_config: Option<UpdaterSettings>,
arch64bits: bool,
Expand Down Expand Up @@ -1386,8 +1386,59 @@ fn tauri_config_to_bundle_settings(
BundleResources::Map(map) => (None, Some(map)),
};

#[cfg(target_os = "macos")]
let entitlements = if let Some(plugin_config) = tauri_config
.plugins
.0
.get("deep-link")
.and_then(|c| c.get("desktop").cloned())
{
let protocols: DesktopDeepLinks =
serde_json::from_value(plugin_config).context("failed to parse deep link plugin config")?;
let domains = match protocols {
DesktopDeepLinks::One(protocol) => protocol.domains,
DesktopDeepLinks::List(protocols) => protocols.into_iter().flat_map(|p| p.domains).collect(),
};

if domains.is_empty() {
config
.macos
.entitlements
.map(PathBuf::from)
.map(tauri_bundler::bundle::Entitlements::Path)
} else {
let mut app_links_entitlements = plist::Dictionary::new();
app_links_entitlements.insert(
"com.apple.developer.associated-domains".to_string(),
domains
.into_iter()
.map(|domain| format!("applinks:{domain}").into())
.collect::<Vec<_>>()
.into(),
);
let entitlements = if let Some(user_provided_entitlements) = config.macos.entitlements {
crate::helpers::plist::merge_plist(vec![
PathBuf::from(user_provided_entitlements).into(),
plist::Value::Dictionary(app_links_entitlements).into(),
])?
} else {
app_links_entitlements.into()
};

Some(tauri_bundler::bundle::Entitlements::Plist(entitlements))
}
} else {
config
.macos
.entitlements
.map(PathBuf::from)
.map(tauri_bundler::bundle::Entitlements::Path)
};
#[cfg(not(target_os = "macos"))]
let entitlements = None;

Ok(BundleSettings {
identifier: Some(identifier),
identifier: Some(tauri_config.identifier.clone()),
publisher: config.publisher,
homepage: config.homepage,
icon: Some(config.icon),
Expand Down Expand Up @@ -1487,7 +1538,7 @@ fn tauri_config_to_bundle_settings(
skip_stapling: false,
hardened_runtime: config.macos.hardened_runtime,
provider_short_name,
entitlements: config.macos.entitlements,
entitlements,
#[cfg(not(target_os = "macos"))]
info_plist: None,
#[cfg(target_os = "macos")]
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri-runtime-wry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ wry = { version = "0.53.2", default-features = false, features = [
"os-webview",
"linux-body",
] }
tao = { version = "0.34.1", default-features = false, features = ["rwh_06"] }
tao = { version = "0.34.2", default-features = false, features = ["rwh_06"] }
tauri-runtime = { version = "2.8.0", path = "../tauri-runtime" }
tauri-utils = { version = "2.7.0", path = "../tauri-utils" }
raw-window-handle = "0.6"
Expand Down
10 changes: 10 additions & 0 deletions crates/tauri-utils/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,17 @@ pub struct FileAssociation {
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct DeepLinkProtocol {
/// URL schemes to associate with this app without `://`. For example `my-app`
#[serde(default)]
pub schemes: Vec<String>,
/// Domains to associate with this app. For example `example.com`.
/// Currently only supported on macOS, translating to an [universal app link].
///
/// Note that universal app links require signed apps with a provisioning profile to work.
/// You can accomplish that by including the `embedded.provisionprofile` file in the `macOS > files` option.
///
/// [universal app link]: https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app
#[serde(default)]
pub domains: Vec<String>,
/// The protocol name. **macOS-only** and maps to `CFBundleTypeName`. Defaults to `<bundle-id>.<schemes[0]>`
pub name: Option<String>,
/// The app's role for these schemes. **macOS-only** and maps to `CFBundleTypeRole`.
Expand Down
Loading