diff --git a/.changes/map-export-method-deprecated.md b/.changes/map-export-method-deprecated.md new file mode 100644 index 000000000..6369d1209 --- /dev/null +++ b/.changes/map-export-method-deprecated.md @@ -0,0 +1,6 @@ +--- +"tauri-cli": patch:bug +"@tauri-apps/cli": patch:bug +--- + +Use the correct export method on Xcode < 15.4. diff --git a/crates/tauri-cli/src/info/env_system.rs b/crates/tauri-cli/src/info/env_system.rs index 88083b5b2..797594820 100644 --- a/crates/tauri-cli/src/info/env_system.rs +++ b/crates/tauri-cli/src/info/env_system.rs @@ -175,6 +175,22 @@ fn is_xcode_command_line_tools_installed() -> bool { .map(|o| o.status.success()) .unwrap_or(false) } + +#[cfg(target_os = "macos")] +pub fn xcode_version() -> Option { + Command::new("xcodebuild") + .arg("-version") + .output() + .ok() + .map(|o| String::from_utf8_lossy(&o.stdout).into_owned()) + .and_then(|s| { + s.split('\n') + .filter_map(|line| line.strip_prefix("Xcode ")) + .next() + .map(ToString::to_string) + }) +} + fn de_and_session() -> String { #[cfg(any( target_os = "linux", @@ -319,5 +335,11 @@ pub fn items() -> Vec { }.into() }, ), + #[cfg(target_os = "macos")] + SectionItem::new().action(|| { + xcode_version().map(|v| (format!("Xcode: {v}"), Status::Success)).unwrap_or_else(|| { + (format!("Xcode: {}", "not installed!".red()), Status::Error) + }).into() + }), ] } diff --git a/crates/tauri-cli/src/info/mod.rs b/crates/tauri-cli/src/info/mod.rs index 1084ba4e3..2a774da2d 100644 --- a/crates/tauri-cli/src/info/mod.rs +++ b/crates/tauri-cli/src/info/mod.rs @@ -15,7 +15,7 @@ use std::fmt::{self, Display, Formatter}; mod app; mod env_nodejs; mod env_rust; -mod env_system; +pub mod env_system; #[cfg(target_os = "macos")] mod ios; mod packages_nodejs; diff --git a/crates/tauri-cli/src/mobile/ios/build.rs b/crates/tauri-cli/src/mobile/ios/build.rs index 177155dc2..7145a8ebe 100644 --- a/crates/tauri-cli/src/mobile/ios/build.rs +++ b/crates/tauri-cli/src/mobile/ios/build.rs @@ -102,6 +102,17 @@ pub enum ExportMethod { Debugging, } +impl ExportMethod { + /// Xcode 15.4 deprecated these names (in this case we should use the Display impl). + pub fn pre_xcode_15_4_name(&self) -> String { + match self { + Self::AppStoreConnect => "app-store".to_string(), + Self::ReleaseTesting => "ad-hoc".to_string(), + Self::Debugging => "development".to_string(), + } + } +} + impl std::fmt::Display for ExportMethod { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -215,7 +226,27 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { let mut export_options_plist = plist::Dictionary::new(); if let Some(method) = options.export_method { - export_options_plist.insert("method".to_string(), method.to_string().into()); + let xcode_version = + crate::info::env_system::xcode_version().context("failed to determine Xcode version")?; + let mut iter = xcode_version.split('.'); + let major = iter.next().context(format!( + "failed to parse Xcode version `{xcode_version}` as semver" + ))?; + let minor = iter.next().context(format!( + "failed to parse Xcode version `{xcode_version}` as semver" + ))?; + let major = major.parse::().context(format!( + "failed to parse Xcode version `{xcode_version}` as semver: major is not a number" + ))?; + let minor = minor.parse::().context(format!( + "failed to parse Xcode version `{xcode_version}` as semver: minor is not a number" + ))?; + + if major < 15 || (major == 15 && minor < 4) { + export_options_plist.insert("method".to_string(), method.pre_xcode_15_4_name().into()); + } else { + export_options_plist.insert("method".to_string(), method.to_string().into()); + } } let (keychain, provisioning_profile) = super::signing_from_env()?;