From 7d24a47c2265e26ae1476fc27ac2d6746941a95a Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 30 Jun 2025 19:14:17 -0700 Subject: [PATCH] fix ios codesign on device (#4339) * fix ios codesign on device * switch to tmpfile --- packages/cli/src/build/builder.rs | 86 ++++++++++++++----------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/packages/cli/src/build/builder.rs b/packages/cli/src/build/builder.rs index 2d3f7be67..b7a97f539 100644 --- a/packages/cli/src/build/builder.rs +++ b/packages/cli/src/build/builder.rs @@ -513,7 +513,14 @@ impl AppBuilder { } } - Platform::Ios => self.open_ios_sim(envs).await?, + Platform::Ios => { + if self.build.device { + self.codesign_ios().await?; + self.open_ios_device().await? + } else { + self.open_ios_sim(envs).await? + } + } Platform::Android => { self.open_android_sim(false, devserver_ip, envs).await?; @@ -853,54 +860,35 @@ impl AppBuilder { /// /// Converting these commands shouldn't be too hard, but device support would imply we need /// better support for codesigning and entitlements. - #[allow(unused)] async fn open_ios_device(&self) -> Result<()> { use serde_json::Value; - let app_path = self.build.root_dir(); - install_app(&app_path).await?; - - // 2. Determine which device the app was installed to + // 1. Find an active device let device_uuid = get_device_uuid().await?; - // 3. Get the installation URL of the app - let installation_url = get_installation_url(&device_uuid, &app_path).await?; + // 2. Get the installation URL of the app + let installation_url = get_installation_url(&device_uuid, &self.build.root_dir()).await?; - // 4. Launch the app into the background, paused + // 3. Launch the app into the background, paused launch_app_paused(&device_uuid, &installation_url).await?; - // 5. Pick up the paused app and resume it - resume_app(&device_uuid).await?; - - async fn install_app(app_path: &PathBuf) -> Result<()> { - let output = Command::new("xcrun") - .args(["simctl", "install", "booted"]) - .arg(app_path) - .output() - .await?; - - if !output.status.success() { - return Err(format!("Failed to install app: {:?}", output).into()); - } - - Ok(()) - } - async fn get_device_uuid() -> Result { - let output = Command::new("xcrun") + let tmpfile = tempfile::NamedTempFile::new() + .context("Failed to create temporary file for device list")?; + + Command::new("xcrun") .args([ - "devicectl", - "list", - "devices", - "--json-output", - "target/deviceid.json", + "devicectl".to_string(), + "list".to_string(), + "devices".to_string(), + "--json-output".to_string(), + tmpfile.path().to_str().unwrap().to_string(), ]) .output() .await?; - let json: Value = - serde_json::from_str(&std::fs::read_to_string("target/deviceid.json")?) - .context("Failed to parse xcrun output")?; + let json: Value = serde_json::from_str(&std::fs::read_to_string(tmpfile.path())?) + .context("Failed to parse xcrun output")?; let device_uuid = json["result"]["devices"][0]["identifier"] .as_str() .ok_or("Failed to extract device UUID")? @@ -910,6 +898,9 @@ impl AppBuilder { } async fn get_installation_url(device_uuid: &str, app_path: &Path) -> Result { + let tmpfile = tempfile::NamedTempFile::new() + .context("Failed to create temporary file for device list")?; + // xcrun devicectl device install app --device --path --json-output let output = Command::new("xcrun") .args([ @@ -921,8 +912,8 @@ impl AppBuilder { device_uuid, &app_path.display().to_string(), "--json-output", - "target/xcrun.json", ]) + .arg(tmpfile.path()) .output() .await?; @@ -930,7 +921,7 @@ impl AppBuilder { return Err(format!("Failed to install app: {:?}", output).into()); } - let json: Value = serde_json::from_str(&std::fs::read_to_string("target/xcrun.json")?) + let json: Value = serde_json::from_str(&std::fs::read_to_string(tmpfile.path())?) .context("Failed to parse xcrun output")?; let installation_url = json["result"]["installedApplications"][0]["installationURL"] .as_str() @@ -941,6 +932,9 @@ impl AppBuilder { } async fn launch_app_paused(device_uuid: &str, installation_url: &str) -> Result<()> { + let tmpfile = tempfile::NamedTempFile::new() + .context("Failed to create temporary file for device list")?; + let output = Command::new("xcrun") .args([ "devicectl", @@ -953,8 +947,8 @@ impl AppBuilder { device_uuid, installation_url, "--json-output", - "target/launch.json", ]) + .arg(tmpfile.path()) .output() .await?; @@ -962,11 +956,7 @@ impl AppBuilder { return Err(format!("Failed to launch app: {:?}", output).into()); } - Ok(()) - } - - async fn resume_app(device_uuid: &str) -> Result<()> { - let json: Value = serde_json::from_str(&std::fs::read_to_string("target/launch.json")?) + let json: Value = serde_json::from_str(&std::fs::read_to_string(tmpfile.path())?) .context("Failed to parse xcrun output")?; let status_pid = json["result"]["process"]["processIdentifier"] @@ -994,10 +984,9 @@ impl AppBuilder { Ok(()) } - unimplemented!("dioxus-cli doesn't support ios devices yet.") + Ok(()) } - #[allow(unused)] async fn codesign_ios(&self) -> Result<()> { const CODESIGN_ERROR: &str = r#"This is likely because you haven't - Created a provisioning profile before @@ -1011,7 +1000,7 @@ https://developer.apple.com/documentation/xcode/sharing-your-teams-signing-certi let profiles_folder = dirs::home_dir() .context("Your machine has no home-dir")? - .join("Library/MobileDevice/Provisioning Profiles"); + .join("Library/Developer/Xcode/UserData/Provisioning Profiles"); if !profiles_folder.exists() || profiles_folder.read_dir()?.next().is_none() { tracing::error!( @@ -1080,10 +1069,11 @@ We checked the folder: {} struct ProvisioningProfile { #[serde(rename = "TeamIdentifier")] team_identifier: Vec, - #[serde(rename = "ApplicationIdentifierPrefix")] - application_identifier_prefix: Vec, #[serde(rename = "Entitlements")] entitlements: Entitlements, + #[allow(dead_code)] + #[serde(rename = "ApplicationIdentifierPrefix")] + application_identifier_prefix: Vec, } #[derive(serde::Deserialize, Debug)]