diff --git a/.changes/install-ios-platform.md b/.changes/install-ios-platform.md new file mode 100644 index 000000000000..907f411e5da9 --- /dev/null +++ b/.changes/install-ios-platform.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/cli": minor:enhance +"tauri-cli": minor:enhance +--- + +Prompt to install the iOS platform if it isn't installed yet. diff --git a/crates/tauri-cli/src/mobile/ios/build.rs b/crates/tauri-cli/src/mobile/ios/build.rs index 7145a8ebe93b..4f0de4f37757 100644 --- a/crates/tauri-cli/src/mobile/ios/build.rs +++ b/crates/tauri-cli/src/mobile/ios/build.rs @@ -15,7 +15,7 @@ use crate::{ flock, }, interface::{AppInterface, Interface, Options as InterfaceOptions}, - mobile::{write_options, CliOptions}, + mobile::{ios::ensure_ios_runtime_installed, write_options, CliOptions}, ConfigValue, Result, }; use clap::{ArgAction, Parser, ValueEnum}; @@ -224,6 +224,10 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { let mut env = env()?; + if !options.open { + ensure_ios_runtime_installed()?; + } + let mut export_options_plist = plist::Dictionary::new(); if let Some(method) = options.export_method { let xcode_version = diff --git a/crates/tauri-cli/src/mobile/ios/dev.rs b/crates/tauri-cli/src/mobile/ios/dev.rs index 67608a84de35..5b48e710176b 100644 --- a/crates/tauri-cli/src/mobile/ios/dev.rs +++ b/crates/tauri-cli/src/mobile/ios/dev.rs @@ -15,7 +15,8 @@ use crate::{ }, interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions}, mobile::{ - use_network_address_for_dev_url, write_options, CliOptions, DevChild, DevHost, DevProcess, + ios::ensure_ios_runtime_installed, use_network_address_for_dev_url, write_options, CliOptions, + DevChild, DevHost, DevProcess, }, ConfigValue, Result, }; @@ -166,6 +167,10 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { } }; + if device.is_some() { + ensure_ios_runtime_installed()?; + } + let mut dev_options: DevOptions = options.clone().into(); let target_triple = device .as_ref() diff --git a/crates/tauri-cli/src/mobile/ios/mod.rs b/crates/tauri-cli/src/mobile/ios/mod.rs index 93e2a8edec3e..ea55d9862d59 100644 --- a/crates/tauri-cli/src/mobile/ios/mod.rs +++ b/crates/tauri-cli/src/mobile/ios/mod.rs @@ -19,6 +19,7 @@ use cargo_mobile2::{ util::{prompt, relativize_path}, }; use clap::{Parser, Subcommand}; +use serde::Deserialize; use sublime_fuzzy::best_match; use tauri_utils::resources::ResourcePaths; @@ -325,12 +326,23 @@ fn connected_device_prompt<'a>(env: &'_ Env, target: Option<&str>) -> Result, +} + +#[derive(Deserialize)] +struct InstalledRuntime { + name: String, +} + fn simulator_prompt(env: &'_ Env, target: Option<&str>) -> Result { let simulator_list = device::list_simulators(env).map_err(|cause| { anyhow::anyhow!("Failed to detect connected iOS Simulator devices: {cause}") @@ -367,6 +379,19 @@ fn simulator_prompt(env: &'_ Env, target: Option<&str>) -> Result(env: &'_ Env, target: Option<&str>) -> Result> { } } +fn ensure_ios_runtime_installed() -> Result<()> { + let installed_platforms_json = + duct::cmd("xcrun", ["simctl", "list", "runtimes", "--json"]).read()?; + let installed_platforms: InstalledRuntimesList = + serde_json::from_str(&installed_platforms_json).unwrap_or_default(); + if !installed_platforms + .runtimes + .iter() + .any(|r| r.name.starts_with("iOS")) + { + log::warn!("iOS platform not installed"); + let install_ios = crate::helpers::prompts::confirm( + "Would you like to install the latest iOS runtime?", + Some(false), + ) + .unwrap_or_default(); + if install_ios { + duct::cmd("xcodebuild", ["-downloadPlatform", "iOS"]) + .stdout_file(os_pipe::dup_stdout().unwrap()) + .stderr_file(os_pipe::dup_stderr().unwrap()) + .run()?; + } else { + anyhow::bail!("iOS platform not installed"); + } + } + Ok(()) +} + fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> { device_prompt(env, None).map(|device| device.target()).ok() }