feat(cli): synchronize Tauri config and lib name with iOS Xcode project (#10802)

- 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

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
This commit is contained in:
Lucas Fernandes Nogueira 2024-08-28 12:11:50 -03:00 committed by GitHub
parent 431208207b
commit f67a9eb6de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 112 additions and 37 deletions

View File

@ -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.

4
Cargo.lock generated
View File

@ -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",

View File

@ -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"] }

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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::<Vec<String>>().join(", "));
None
@ -421,12 +422,21 @@ pub fn load_pbxproj(config: &AppleConfig) -> Result<pbxproj::Pbxproj> {
}
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(),

View File

@ -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);

View File

@ -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(())
}

View File

@ -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");
}

View File

@ -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}}