From e5b30d75abc3139cd4dcc1cb677488e3e92e3413 Mon Sep 17 00:00:00 2001 From: Lucas Nogueira Date: Tue, 27 Aug 2024 19:34:36 -0300 Subject: [PATCH] feat(cli): synchronize Tauri config and lib name with iOS Xcode project - the Xcode project now uses a fixed output library name, which means changes to the Cargo.toml lib name won't affect it (backwards compatible change, we're checking if this new format is being used or not by reading the project.pbxproj) - sync config identifier with the pbxproj - sync development team config with the pbxproj the sync runs both on dev and on build --- .../synchronize-config-and-xcode-project.md | 6 +++ Cargo.lock | 4 +- crates/tauri-cli/Cargo.toml | 2 +- crates/tauri-cli/src/helpers/pbxproj.rs | 12 +++--- crates/tauri-cli/src/mobile/ios/build.rs | 7 ++-- crates/tauri-cli/src/mobile/ios/dev.rs | 23 ++++++++++- crates/tauri-cli/src/mobile/ios/mod.rs | 38 ++++++++++++++++--- crates/tauri-cli/src/mobile/ios/project.rs | 3 ++ .../tauri-cli/src/mobile/ios/xcode_script.rs | 27 +++++++++++-- crates/tauri-cli/src/mobile/mod.rs | 19 +++++----- .../templates/mobile/ios/project.yml | 8 ++-- 11 files changed, 112 insertions(+), 37 deletions(-) create mode 100644 .changes/synchronize-config-and-xcode-project.md diff --git a/.changes/synchronize-config-and-xcode-project.md b/.changes/synchronize-config-and-xcode-project.md new file mode 100644 index 000000000000..2c7f2d11ecff --- /dev/null +++ b/.changes/synchronize-config-and-xcode-project.md @@ -0,0 +1,6 @@ +--- +"tauri-cli": patch:enhance +"@tauri-apps/cli": patch:enhance +--- + +Synchronize identifier, development team and lib name with the iOS Xcode project. diff --git a/Cargo.lock b/Cargo.lock index 22aeb514bdbf..9e05f1913478 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -747,9 +747,9 @@ dependencies = [ [[package]] name = "cargo-mobile2" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b1baf430f92ddf6e492c9186e4e97dc3051366345b8aa7ffdc0e0f952c9a35b" +checksum = "d0b8132519bea2d46174e777bd36d480d93afbe1df31c27cacfb411ff152bba1" dependencies = [ "colored", "core-foundation 0.10.0", diff --git a/crates/tauri-cli/Cargo.toml b/crates/tauri-cli/Cargo.toml index 8aff39ecfeca..7de08d9a1899 100644 --- a/crates/tauri-cli/Cargo.toml +++ b/crates/tauri-cli/Cargo.toml @@ -36,7 +36,7 @@ name = "cargo-tauri" path = "src/main.rs" [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"windows\", target_os = \"macos\"))".dependencies] -cargo-mobile2 = { version = "0.15", default-features = false } +cargo-mobile2 = { version = "0.15.1", default-features = false } [dependencies] jsonrpsee = { version = "0.24", features = ["server"] } diff --git a/crates/tauri-cli/src/helpers/pbxproj.rs b/crates/tauri-cli/src/helpers/pbxproj.rs index 081f035f47be..f449a089dc2a 100644 --- a/crates/tauri-cli/src/helpers/pbxproj.rs +++ b/crates/tauri-cli/src/helpers/pbxproj.rs @@ -230,12 +230,14 @@ impl Pbxproj { .iter_mut() .find(|s| s.key == key) { - let Some(line) = self.raw_lines.get_mut(build_setting.line_number) else { - return; - }; + if build_setting.value != value { + let Some(line) = self.raw_lines.get_mut(build_setting.line_number) else { + return; + }; - *line = format!("{}{key} = {value};", build_setting.identation); - self.has_changes = true; + *line = format!("{}{key} = {value};", build_setting.identation); + self.has_changes = true; + } } else { let Some(last_build_setting) = build_configuration.build_settings.last().cloned() else { return; diff --git a/crates/tauri-cli/src/mobile/ios/build.rs b/crates/tauri-cli/src/mobile/ios/build.rs index 28c750b9cae4..fdcbc0f83e9a 100644 --- a/crates/tauri-cli/src/mobile/ios/build.rs +++ b/crates/tauri-cli/src/mobile/ios/build.rs @@ -146,7 +146,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { tauri_utils::platform::Target::Ios, options.config.as_ref().map(|c| &c.0), )?; - let (interface, app, mut config) = { + let (interface, mut config) = { let tauri_config_guard = tauri_config.lock().unwrap(); let tauri_config_ = tauri_config_guard.as_ref().unwrap(); @@ -160,7 +160,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { build_options.features.as_ref(), &Default::default(), ); - (interface, app, config) + (interface, config) }; let tauri_path = tauri_dir(); @@ -198,7 +198,8 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { // synchronize pbxproj and exportoptions synchronize_project_config( - &app, + &config, + &tauri_config, &mut pbxproj, &mut export_options_plist, &project_config, diff --git a/crates/tauri-cli/src/mobile/ios/dev.rs b/crates/tauri-cli/src/mobile/ios/dev.rs index a2ffeacac113..1814f499f56d 100644 --- a/crates/tauri-cli/src/mobile/ios/dev.rs +++ b/crates/tauri-cli/src/mobile/ios/dev.rs @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MIT use super::{ - device_prompt, ensure_init, env, get_app, get_config, inject_resources, merge_plist, - open_and_wait, MobileTarget, + device_prompt, ensure_init, env, get_app, get_config, inject_resources, load_pbxproj, + merge_plist, open_and_wait, synchronize_project_config, MobileTarget, ProjectConfig, }; use crate::{ dev::Options as DevOptions, @@ -191,6 +191,25 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { ])?; merged_info_plist.to_file_xml(&info_plist_path)?; + let mut pbxproj = load_pbxproj(&config)?; + + // synchronize pbxproj + synchronize_project_config( + &config, + &tauri_config, + &mut pbxproj, + &mut plist::Dictionary::new(), + &ProjectConfig { + code_sign_identity: None, + team_id: None, + provisioning_profile_uuid: None, + }, + !options.release_mode, + )?; + if pbxproj.has_changes() { + pbxproj.save()?; + } + run_dev( interface, options, diff --git a/crates/tauri-cli/src/mobile/ios/mod.rs b/crates/tauri-cli/src/mobile/ios/mod.rs index d3e1e33037c4..3d2a329bbfb8 100644 --- a/crates/tauri-cli/src/mobile/ios/mod.rs +++ b/crates/tauri-cli/src/mobile/ios/mod.rs @@ -29,7 +29,7 @@ use super::{ use crate::{ helpers::{ app_paths::tauri_dir, - config::{BundleResources, Config as TauriConfig}, + config::{BundleResources, Config as TauriConfig, ConfigHandle}, pbxproj, }, Result, @@ -49,6 +49,7 @@ pub(crate) mod project; mod xcode_script; pub const APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME: &str = "APPLE_DEVELOPMENT_TEAM"; +pub const LIB_OUTPUT_FILE_NAME: &str = "libapp.a"; #[derive(Parser)] #[clap( @@ -131,7 +132,7 @@ pub fn get_config( log::warn!("No code signing certificates found. You must add one and set the certificate development team ID on the `bundle > iOS > developmentTeam` config value or the `{APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME}` environment variable. To list the available certificates, run `tauri info`."); None } - 1 => Some(teams.first().unwrap().id.clone()), + 1 =>None, _ => { log::warn!("You must set the code signing certificate development team ID on the `bundle > iOS > developmentTeam` config value or the `{APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME}` environment variable. Available certificates: {}", teams.iter().map(|t| format!("{} (ID: {})", t.name, t.id)).collect::>().join(", ")); None @@ -421,12 +422,21 @@ pub fn load_pbxproj(config: &AppleConfig) -> Result { } pub fn synchronize_project_config( - app: &App, + config: &AppleConfig, + tauri_config: &ConfigHandle, pbxproj: &mut pbxproj::Pbxproj, export_options_list: &mut plist::Dictionary, project_config: &ProjectConfig, debug: bool, ) -> Result<()> { + let identifier = tauri_config + .lock() + .unwrap() + .as_ref() + .unwrap() + .identifier + .clone(); + let manual_signing = project_config.code_sign_identity.is_some() || project_config.provisioning_profile_uuid.is_some(); @@ -437,10 +447,26 @@ pub fn synchronize_project_config( .find(|l| l.comment.contains("_iOS")) { for build_configuration_ref in xc_configuration_list.build_configurations { - if manual_signing { - pbxproj.set_build_settings(&build_configuration_ref.id, "CODE_SIGN_STYLE", "Manual"); + pbxproj.set_build_settings( + &build_configuration_ref.id, + "CODE_SIGN_STYLE", + if manual_signing { + "Manual" + } else { + "Automatic" + }, + ); + + if let Some(team) = config.development_team() { + pbxproj.set_build_settings(&build_configuration_ref.id, "DEVELOPMENT_TEAM", team); } + pbxproj.set_build_settings( + &build_configuration_ref.id, + "PRODUCT_BUNDLE_IDENTIFIER", + &identifier, + ); + if let Some(identity) = &project_config.code_sign_identity { let identity = format!("\"{identity}\""); pbxproj.set_build_settings(&build_configuration_ref.id, "CODE_SIGN_IDENTITY", &identity); @@ -536,7 +562,7 @@ pub fn synchronize_project_config( }); if let Some(profile_uuid) = profile_uuid { let mut provisioning_profiles = plist::Dictionary::new(); - provisioning_profiles.insert(app.identifier().to_string(), profile_uuid.into()); + provisioning_profiles.insert(config.app().identifier().to_string(), profile_uuid.into()); export_options_list.insert( "provisioningProfiles".to_string(), provisioning_profiles.into(), diff --git a/crates/tauri-cli/src/mobile/ios/project.rs b/crates/tauri-cli/src/mobile/ios/project.rs index fcf5af924b6d..f87b5ce02d42 100644 --- a/crates/tauri-cli/src/mobile/ios/project.rs +++ b/crates/tauri-cli/src/mobile/ios/project.rs @@ -4,6 +4,7 @@ use crate::{ helpers::{config::Config as TauriConfig, template}, + mobile::ios::LIB_OUTPUT_FILE_NAME, Result, }; use anyhow::Context; @@ -76,6 +77,8 @@ pub fn gen( #[cfg(not(target_arch = "aarch64"))] let default_archs = ["arm64", "x86_64"]; + map.insert("lib-output-file-name", LIB_OUTPUT_FILE_NAME); + map.insert("file-groups", &source_dirs); map.insert("ios-frameworks", metadata.ios().frameworks()); map.insert("ios-valid-archs", default_archs); diff --git a/crates/tauri-cli/src/mobile/ios/xcode_script.rs b/crates/tauri-cli/src/mobile/ios/xcode_script.rs index 49b2851d8a8a..4bff5fa0dff6 100644 --- a/crates/tauri-cli/src/mobile/ios/xcode_script.rs +++ b/crates/tauri-cli/src/mobile/ios/xcode_script.rs @@ -6,9 +6,11 @@ use super::{ensure_init, env, get_app, get_config, read_options, MobileTarget}; use crate::{ helpers::config::get as get_tauri_config, interface::{AppInterface, AppSettings, Interface, Options as InterfaceOptions}, + mobile::ios::LIB_OUTPUT_FILE_NAME, Result, }; +use anyhow::Context; use cargo_mobile2::{apple::target::Target, opts::Profile}; use clap::Parser; @@ -16,6 +18,7 @@ use std::{ collections::HashMap, env::{current_dir, set_current_dir, var, var_os}, ffi::OsStr, + fs::read_to_string, path::{Path, PathBuf}, process::Command, }; @@ -233,10 +236,26 @@ pub fn command(options: Options) -> Result<()> { let project_dir = config.project_dir(); let externals_lib_dir = project_dir.join(format!("Externals/{arch}/{}", profile.as_str())); std::fs::create_dir_all(&externals_lib_dir)?; - std::fs::copy( - lib_path, - externals_lib_dir.join(format!("lib{}.a", config.app().lib_name())), - )?; + + // backwards compatible lib output file name + let uses_new_lib_output_file_name = { + let pbxproj_contents = read_to_string( + project_dir + .join(format!("{}.xcodeproj", config.app().name())) + .join("project.pbxproj"), + ) + .context("missing project.pbxproj file in the Xcode project")?; + + pbxproj_contents.contains(LIB_OUTPUT_FILE_NAME) + }; + + let lib_output_file_name = if uses_new_lib_output_file_name { + LIB_OUTPUT_FILE_NAME.to_string() + } else { + format!("lib{}.a", config.app().lib_name()) + }; + + std::fs::copy(lib_path, externals_lib_dir.join(lib_output_file_name))?; } Ok(()) } diff --git a/crates/tauri-cli/src/mobile/mod.rs b/crates/tauri-cli/src/mobile/mod.rs index d38e87faeec9..b4292a285bd2 100644 --- a/crates/tauri-cli/src/mobile/mod.rs +++ b/crates/tauri-cli/src/mobile/mod.rs @@ -329,17 +329,16 @@ fn ensure_init( } #[cfg(target_os = "macos")] Target::Ios => { - let project_yml = read_to_string(project_dir.join("project.yml")) - .context("missing project.yml file in the Xcode project directory")?; - if !project_yml.contains(&format!( - "PRODUCT_BUNDLE_IDENTIFIER: {}", - tauri_config_.identifier.replace('_', "-") - )) { - project_outdated_reasons - .push("you have modified your \"identifier\" in the Tauri configuration"); - } + let pbxproj_contents = read_to_string( + project_dir + .join(format!("{}.xcodeproj", app.name())) + .join("project.pbxproj"), + ) + .context("missing project.yml file in the Xcode project directory")?; - if !project_yml.contains(&format!("framework: lib{}.a", app.lib_name())) { + if !(pbxproj_contents.contains(ios::LIB_OUTPUT_FILE_NAME) + || pbxproj_contents.contains(&format!("lib{}.a", app.lib_name()))) + { project_outdated_reasons .push("you have modified your [lib.name] or [package.name] in the Cargo.toml file"); } diff --git a/crates/tauri-cli/templates/mobile/ios/project.yml b/crates/tauri-cli/templates/mobile/ios/project.yml index 0f8d5d5f6cc9..1a4712bae9c7 100644 --- a/crates/tauri-cli/templates/mobile/ios/project.yml +++ b/crates/tauri-cli/templates/mobile/ios/project.yml @@ -86,7 +86,7 @@ targets: EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64 groups: [app] dependencies: - - framework: lib{{app.lib-name}}.a + - framework: {{ lib-output-file-name }} embed: false {{~#each ios-libraries}} - framework: {{this}} @@ -125,9 +125,9 @@ targets: name: Build Rust Code basedOnDependencyAnalysis: false outputFiles: - - $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/lib{{app.lib-name}}.a - - $(SRCROOT)/Externals/arm64/${CONFIGURATION}/lib{{app.lib-name}}.a - - $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/lib{{app.lib-name}}.a + - $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/{{ lib-output-file-name }} + - $(SRCROOT)/Externals/arm64/${CONFIGURATION}/{{ lib-output-file-name }} + - $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/{{ lib-output-file-name }} {{~#if ios-post-compile-scripts}} postCompileScripts: {{~#each ios-post-compile-scripts}}{{#if this.path}}