Prechádzať zdrojové kódy

refactor(cli): synchronize pbxproj and export options, handle cert on build (#10669)

Lucas Fernandes Nogueira 11 mesiacov pred
rodič
commit
da8c9a7d30

+ 6 - 0
.changes/ios-codesign-on-build.md

@@ -0,0 +1,6 @@
+---
+"tauri-cli": patch:breaking
+"@tauri-apps/cli": patch:breaking
+---
+
+The `IOS_CERTIFICATE`, `IOS_CERTIFICATE_PASSWORD` and `IOS_MOBILE_PROVISION` environment variables are now read by the `ios build` command instead of `ios init`.

+ 6 - 0
.changes/synchronize-pbxproj-export-options.md

@@ -0,0 +1,6 @@
+---
+"tauri-cli": patch:bug
+"@tauri-apps/cli": patch:bug
+---
+
+Synchronize Xcode project changes with the ExportOptions.plist file so `ios build` calls can work with code signing changes made in Xcode.

+ 6 - 0
.changes/update-pbxproj-codesign.md

@@ -0,0 +1,6 @@
+---
+"tauri-cli": patch:enhance
+"@tauri-apps/cli": patch:enhance
+---
+
+Modify both ExportOptions.plist and project.pbxproj to reflect changes for the `IOS_CERTIFICATE`, `IOS_CERTIFICATE_PASSWORD` and `IOS_MOBILE_PROVISION` environment variables.

+ 55 - 27
tooling/cli/Cargo.lock

@@ -557,12 +557,12 @@ dependencies = [
 
 [[package]]
 name = "cargo-mobile2"
-version = "0.13.3"
+version = "0.13.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b933d7440e2fd78462ae586f959883710837c6145ddcd501e8adcf4cb57b2cb"
+checksum = "b8dd9a8451eeeb998885ec3acb08b9bd32353ccd119b18db5ae6ddc41814fc03"
 dependencies = [
  "colored",
- "core-foundation",
+ "core-foundation 0.10.0",
  "deunicode",
  "duct",
  "dunce",
@@ -831,11 +831,21 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "core-foundation"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.6"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "core_maths"
@@ -2295,6 +2305,18 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "insta"
+version = "1.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5"
+dependencies = [
+ "console",
+ "lazy_static",
+ "linked-hash-map",
+ "similar",
+]
+
 [[package]]
 name = "interpolate_name"
 version = "0.2.4"
@@ -2713,6 +2735,12 @@ dependencies = [
  "safemem",
 ]
 
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
 [[package]]
 name = "linux-raw-sys"
 version = "0.3.8"
@@ -4673,7 +4701,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
 dependencies = [
  "bitflags 1.3.2",
- "core-foundation",
+ "core-foundation 0.9.4",
  "core-foundation-sys",
  "libc",
  "security-framework-sys",
@@ -4976,6 +5004,12 @@ dependencies = [
  "quote",
 ]
 
+[[package]]
+name = "similar"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
+
 [[package]]
 name = "simplecss"
 version = "0.2.1"
@@ -5406,6 +5440,7 @@ dependencies = [
  "ignore",
  "image",
  "include_dir",
+ "insta",
  "itertools 0.13.0",
  "json-patch 2.0.0",
  "jsonrpsee",
@@ -5443,6 +5478,7 @@ dependencies = [
  "tauri-macos-sign",
  "tauri-utils 1.5.4",
  "tauri-utils 2.0.0-rc.5",
+ "tempfile",
  "tokio",
  "toml 0.8.10",
  "toml_edit 0.22.6",
@@ -6467,11 +6503,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows"
-version = "0.57.0"
+version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
+checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
 dependencies = [
- "windows-core 0.57.0",
+ "windows-core 0.58.0",
  "windows-targets 0.52.6",
 ]
 
@@ -6486,21 +6522,22 @@ dependencies = [
 
 [[package]]
 name = "windows-core"
-version = "0.57.0"
+version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
+checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
 dependencies = [
  "windows-implement",
  "windows-interface",
- "windows-result 0.1.1",
+ "windows-result",
+ "windows-strings",
  "windows-targets 0.52.6",
 ]
 
 [[package]]
 name = "windows-implement"
-version = "0.57.0"
+version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
+checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -6509,9 +6546,9 @@ dependencies = [
 
 [[package]]
 name = "windows-interface"
-version = "0.57.0"
+version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
+checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -6524,20 +6561,11 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
 dependencies = [
- "windows-result 0.2.0",
+ "windows-result",
  "windows-strings",
  "windows-targets 0.52.6",
 ]
 
-[[package]]
-name = "windows-result"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
 [[package]]
 name = "windows-result"
 version = "0.2.0"
@@ -6553,7 +6581,7 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
 dependencies = [
- "windows-result 0.2.0",
+ "windows-result",
  "windows-targets 0.52.6",
 ]
 

+ 5 - 1
tooling/cli/Cargo.toml

@@ -39,7 +39,7 @@ name = "cargo-tauri"
 path = "src/main.rs"
 
 [dependencies]
-cargo-mobile2 = { version = "0.13.3", default-features = false }
+cargo-mobile2 = { version = "0.13.4", default-features = false }
 jsonrpsee = { version = "0.24", features = [ "server" ] }
 jsonrpsee-core = "0.24"
 jsonrpsee-client-transport = { version = "0.24", features = [ "ws" ] }
@@ -101,6 +101,10 @@ phf = { version = "0.11", features = ["macros"] }
 walkdir = "2"
 elf = "0.7"
 memchr = "2"
+tempfile = "3"
+
+[dev-dependencies]
+insta = "1"
 
 [target."cfg(windows)".dependencies.windows-sys]
 version = "0.59"

+ 2 - 0
tooling/cli/src/helpers/mod.rs

@@ -10,6 +10,8 @@ pub mod flock;
 pub mod framework;
 pub mod fs;
 pub mod npm;
+#[cfg(target_os = "macos")]
+pub mod pbxproj;
 pub mod plugins;
 pub mod prompts;
 pub mod template;

+ 322 - 0
tooling/cli/src/helpers/pbxproj.rs

@@ -0,0 +1,322 @@
+// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+use std::{
+  collections::BTreeMap,
+  fmt,
+  path::{Path, PathBuf},
+};
+
+pub fn parse<P: AsRef<Path>>(path: P) -> crate::Result<Pbxproj> {
+  let path = path.as_ref();
+  let pbxproj = std::fs::read_to_string(path)?;
+
+  let mut proj = Pbxproj {
+    path: path.to_owned(),
+    raw_lines: pbxproj.split('\n').map(ToOwned::to_owned).collect(),
+    xc_build_configuration: BTreeMap::new(),
+    xc_configuration_list: BTreeMap::new(),
+    additions: BTreeMap::new(),
+    has_changes: false,
+  };
+
+  let mut state = State::Idle;
+
+  let mut iter = proj.raw_lines.iter().enumerate();
+
+  while let Some((line_number, line)) = iter.next() {
+    match &state {
+      State::Idle => {
+        if line == "/* Begin XCBuildConfiguration section */" {
+          state = State::XCBuildConfiguration;
+        } else if line == "/* Begin XCConfigurationList section */" {
+          state = State::XCConfigurationList;
+        }
+      }
+      // XCBuildConfiguration
+      State::XCBuildConfiguration => {
+        if line == "/* End XCBuildConfiguration section */" {
+          state = State::Idle;
+        } else if let Some((_identation, token)) = split_at_identation(line) {
+          let id: String = token.chars().take_while(|c| c.is_alphanumeric()).collect();
+          proj.xc_build_configuration.insert(
+            id.clone(),
+            XCBuildConfiguration {
+              build_settings: Vec::new(),
+            },
+          );
+          state = State::XCBuildConfigurationObject { id };
+        }
+      }
+      State::XCBuildConfigurationObject { id } => {
+        if line.contains("buildSettings") {
+          state = State::XCBuildConfigurationObjectBuildSettings { id: id.clone() };
+        } else if split_at_identation(line).map_or(false, |(_ident, token)| token == "};") {
+          state = State::XCBuildConfiguration;
+        }
+      }
+      State::XCBuildConfigurationObjectBuildSettings { id } => {
+        if let Some((identation, token)) = split_at_identation(line) {
+          if token == "};" {
+            state = State::XCBuildConfigurationObject { id: id.clone() };
+          } else {
+            let assignment = token.trim_end_matches(';');
+            if let Some((key, value)) = assignment.split_once(" = ") {
+              // multiline value
+              let value = if value == "(" {
+                let mut value = value.to_string();
+                loop {
+                  let Some((_next_line_number, next_line)) = iter.next() else {
+                    break;
+                  };
+
+                  value.push_str(next_line);
+                  value.push('\n');
+
+                  if let Some((_, token)) = split_at_identation(next_line) {
+                    if token == ");" {
+                      break;
+                    }
+                  }
+                }
+                value
+              } else {
+                value.trim().to_string()
+              };
+
+              proj
+                .xc_build_configuration
+                .get_mut(id)
+                .unwrap()
+                .build_settings
+                .push(BuildSettings {
+                  identation: identation.into(),
+                  line_number,
+                  key: key.trim().into(),
+                  value,
+                });
+            }
+          }
+        }
+      }
+      // XCConfigurationList
+      State::XCConfigurationList => {
+        if line == "/* End XCConfigurationList section */" {
+          state = State::Idle;
+        } else if let Some((_identation, token)) = split_at_identation(line) {
+          let Some((id, comment)) = token.split_once(' ') else {
+            continue;
+          };
+
+          proj.xc_configuration_list.insert(
+            id.to_string(),
+            XCConfigurationList {
+              comment: comment.trim_end_matches(" = {").to_string(),
+              build_configurations: Vec::new(),
+            },
+          );
+          state = State::XCConfigurationListObject { id: id.to_string() };
+        }
+      }
+      State::XCConfigurationListObject { id } => {
+        if line.contains("buildConfigurations") {
+          state = State::XCConfigurationListObjectBuildConfigurations { id: id.clone() };
+        } else if split_at_identation(line).map_or(false, |(_ident, token)| token == "};") {
+          state = State::XCConfigurationList;
+        }
+      }
+      State::XCConfigurationListObjectBuildConfigurations { id } => {
+        if let Some((_identation, token)) = split_at_identation(line) {
+          if token == ");" {
+            state = State::XCConfigurationListObject { id: id.clone() };
+          } else {
+            let Some((build_configuration_id, comments)) = token.split_once(' ') else {
+              continue;
+            };
+            proj
+              .xc_configuration_list
+              .get_mut(id)
+              .unwrap()
+              .build_configurations
+              .push(BuildConfigurationRef {
+                id: build_configuration_id.to_string(),
+                comments: comments.trim_end_matches(',').to_string(),
+              });
+          }
+        }
+      }
+    }
+  }
+
+  Ok(proj)
+}
+
+fn split_at_identation(s: &str) -> Option<(&str, &str)> {
+  s.chars()
+    .position(|c| !c.is_ascii_whitespace())
+    .map(|pos| s.split_at(pos))
+}
+
+enum State {
+  Idle,
+  // XCBuildConfiguration
+  XCBuildConfiguration,
+  XCBuildConfigurationObject { id: String },
+  XCBuildConfigurationObjectBuildSettings { id: String },
+  // XCConfigurationList
+  XCConfigurationList,
+  XCConfigurationListObject { id: String },
+  XCConfigurationListObjectBuildConfigurations { id: String },
+}
+
+pub struct Pbxproj {
+  path: PathBuf,
+  raw_lines: Vec<String>,
+  pub xc_build_configuration: BTreeMap<String, XCBuildConfiguration>,
+  pub xc_configuration_list: BTreeMap<String, XCConfigurationList>,
+
+  // maps the line number to the line to add
+  additions: BTreeMap<usize, String>,
+
+  has_changes: bool,
+}
+
+impl fmt::Debug for Pbxproj {
+  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    f.debug_struct("Pbxproj")
+      .field("xc_build_configuration", &self.xc_build_configuration)
+      .field("xc_configuration_list", &self.xc_configuration_list)
+      .finish()
+  }
+}
+
+impl Pbxproj {
+  pub fn has_changes(&self) -> bool {
+    !self.additions.is_empty() || self.has_changes
+  }
+
+  fn serialize(&self) -> String {
+    let mut proj = String::new();
+    let last_line_number = self.raw_lines.len() - 1;
+
+    for (number, line) in self.raw_lines.iter().enumerate() {
+      if let Some(new) = self.additions.get(&number) {
+        proj.push_str(new);
+        proj.push('\n');
+      }
+
+      proj.push_str(line);
+      if number != last_line_number {
+        proj.push('\n');
+      }
+    }
+
+    proj
+  }
+
+  pub fn save(&self) -> std::io::Result<()> {
+    std::fs::write(&self.path, self.serialize())
+  }
+
+  pub fn set_build_settings(&mut self, build_configuration_id: &str, key: &str, value: &str) {
+    let Some(build_configuration) = self.xc_build_configuration.get_mut(build_configuration_id)
+    else {
+      return;
+    };
+
+    if let Some(build_setting) = build_configuration
+      .build_settings
+      .iter_mut()
+      .find(|s| s.key == key)
+    {
+      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;
+    } else {
+      let Some(last_build_setting) = build_configuration.build_settings.last().cloned() else {
+        return;
+      };
+      build_configuration.build_settings.push(BuildSettings {
+        identation: last_build_setting.identation.clone(),
+        line_number: last_build_setting.line_number + 1,
+        key: key.to_string(),
+        value: value.to_string(),
+      });
+      self.additions.insert(
+        last_build_setting.line_number + 1,
+        format!("{}{key} = {value};", last_build_setting.identation),
+      );
+    }
+  }
+}
+
+#[derive(Debug)]
+pub struct XCBuildConfiguration {
+  build_settings: Vec<BuildSettings>,
+}
+
+impl XCBuildConfiguration {
+  pub fn get_build_setting(&self, key: &str) -> Option<&BuildSettings> {
+    self.build_settings.iter().find(|s| s.key == key)
+  }
+}
+
+#[derive(Debug, Clone)]
+pub struct BuildSettings {
+  identation: String,
+  line_number: usize,
+  pub key: String,
+  pub value: String,
+}
+
+#[derive(Debug, Clone)]
+pub struct XCConfigurationList {
+  pub comment: String,
+  pub build_configurations: Vec<BuildConfigurationRef>,
+}
+
+#[derive(Debug, Clone)]
+pub struct BuildConfigurationRef {
+  pub id: String,
+  pub comments: String,
+}
+
+#[cfg(test)]
+mod tests {
+  #[test]
+  fn parse() {
+    let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
+    let fixtures_path = manifest_dir.join("tests").join("fixtures").join("pbxproj");
+
+    let mut settings = insta::Settings::clone_current();
+    settings.set_snapshot_path(fixtures_path.join("snapshots"));
+    let _guard = settings.bind_to_scope();
+
+    insta::assert_debug_snapshot!(
+      "project.pbxproj",
+      super::parse(fixtures_path.join("project.pbxproj")).expect("failed to parse pbxproj")
+    );
+  }
+
+  #[test]
+  fn modify() {
+    let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
+    let fixtures_path = manifest_dir.join("tests").join("fixtures").join("pbxproj");
+
+    let mut settings = insta::Settings::clone_current();
+    settings.set_snapshot_path(fixtures_path.join("snapshots"));
+    let _guard = settings.bind_to_scope();
+
+    let mut pbxproj =
+      super::parse(fixtures_path.join("project.pbxproj")).expect("failed to parse pbxproj");
+
+    pbxproj.set_build_settings("DB0E254D0FD84970B57F6410", "PRODUCT_NAME", "\"Tauri Test\"");
+    pbxproj.set_build_settings("DB0E254D0FD84970B57F6410", "UNKNOWN", "9283j49238h");
+
+    insta::assert_snapshot!("project-modified.pbxproj", pbxproj.serialize());
+  }
+}

+ 2 - 44
tooling/cli/src/mobile/init.rs

@@ -24,7 +24,6 @@ use cargo_mobile2::{
 use handlebars::{
   Context, Handlebars, Helper, HelperResult, Output, RenderContext, RenderError, RenderErrorReason,
 };
-use serde::Serialize;
 
 use std::{env::var_os, path::PathBuf};
 
@@ -36,23 +35,8 @@ pub fn command(
 ) -> Result<()> {
   let wrapper = TextWrapper::default();
 
-  let tauri_init_config = TauriInitConfig {
-    #[cfg(target_os = "macos")]
-    ios: {
-      let (keychain, provisioning_profile) = super::ios::signing_from_env()?;
-      super::ios::init_config(keychain.as_ref(), provisioning_profile.as_ref())?
-    },
-  };
-
-  exec(
-    target,
-    &wrapper,
-    &tauri_init_config,
-    ci,
-    reinstall_deps,
-    skip_targets_install,
-  )
-  .map_err(|e| anyhow::anyhow!("{:#}", e))?;
+  exec(target, &wrapper, ci, reinstall_deps, skip_targets_install)
+    .map_err(|e| anyhow::anyhow!("{:#}", e))?;
   Ok(())
 }
 
@@ -93,33 +77,9 @@ pub fn configure_cargo(
   dot_cargo.write(app).map_err(Into::into)
 }
 
-#[cfg(target_os = "macos")]
-#[derive(Serialize)]
-pub enum CodeSignStyle {
-  Manual,
-  Automatic,
-}
-
-#[cfg(target_os = "macos")]
-#[derive(Serialize)]
-#[serde(rename_all = "kebab-case")]
-pub struct IosInitConfig {
-  pub code_sign_style: CodeSignStyle,
-  pub code_sign_identity: Option<String>,
-  pub team_id: Option<String>,
-  pub provisioning_profile_uuid: Option<String>,
-}
-
-#[derive(Serialize)]
-pub struct TauriInitConfig {
-  #[cfg(target_os = "macos")]
-  ios: IosInitConfig,
-}
-
 pub fn exec(
   target: Target,
   wrapper: &TextWrapper,
-  tauri_init_config: &TauriInitConfig,
   #[allow(unused_variables)] non_interactive: bool,
   #[allow(unused_variables)] reinstall_deps: bool,
   skip_targets_install: bool,
@@ -133,8 +93,6 @@ pub fn exec(
 
   let (handlebars, mut map) = handlebars(&app);
 
-  map.insert("tauri", tauri_init_config);
-
   let mut args = std::env::args_os();
 
   let (binary, mut build_args) = args

+ 45 - 56
tooling/cli/src/mobile/ios/build.rs

@@ -4,7 +4,8 @@
 
 use super::{
   configure_cargo, detect_target_ok, ensure_init, env, get_app, get_config, inject_resources,
-  log_finished, merge_plist, open_and_wait, MobileTarget, OptionsHandle,
+  load_pbxproj, log_finished, merge_plist, open_and_wait, project_config,
+  synchronize_project_config, MobileTarget, OptionsHandle,
 };
 use crate::{
   build::Options as BuildOptions,
@@ -138,7 +139,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, config) = {
+  let (interface, app, mut config) = {
     let tauri_config_guard = tauri_config.lock().unwrap();
     let tauri_config_ = tauri_config_guard.as_ref().unwrap();
 
@@ -170,32 +171,55 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
     .project_dir()
     .join(config.scheme())
     .join("Info.plist");
-  merge_plist(
-    vec![
-      tauri_path.join("Info.plist").into(),
-      tauri_path.join("Info.ios.plist").into(),
-    ],
-    &info_plist_path,
-  )?;
+  let merged_info_plist = merge_plist(vec![
+    info_plist_path.clone().into(),
+    tauri_path.join("Info.plist").into(),
+    tauri_path.join("Info.ios.plist").into(),
+  ])?;
+  merged_info_plist.to_file_xml(&info_plist_path)?;
 
   let mut env = env()?;
   configure_cargo(&app, None)?;
 
+  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 (keychain, provisioning_profile) = super::signing_from_env()?;
-  let init_config = super::init_config(keychain.as_ref(), provisioning_profile.as_ref())?;
-  if let Some(export_options_plist) =
-    create_export_options(&app, &init_config, options.export_method)
-  {
+  let project_config = project_config(keychain.as_ref(), provisioning_profile.as_ref())?;
+  let mut pbxproj = load_pbxproj(&config)?;
+
+  // synchronize pbxproj and exportoptions
+  synchronize_project_config(
+    &app,
+    &mut pbxproj,
+    &mut export_options_plist,
+    &project_config,
+    options.debug,
+  )?;
+  if pbxproj.has_changes() {
+    pbxproj.save()?;
+  }
+
+  // merge export options and write to temp file
+  let _export_options_tmp = if !export_options_plist.is_empty() {
     let export_options_plist_path = config.project_dir().join("ExportOptions.plist");
+    let export_options = tempfile::NamedTempFile::new()?;
 
-    merge_plist(
-      vec![
-        export_options_plist_path.clone().into(),
-        export_options_plist.into(),
-      ],
-      &export_options_plist_path,
-    )?;
-  }
+    let merged_plist = merge_plist(vec![
+      export_options.path().to_owned().into(),
+      export_options_plist_path.clone().into(),
+      plist::Value::from(export_options_plist).into(),
+    ])?;
+    merged_plist.to_file_xml(export_options.path())?;
+
+    config.set_export_options_plist_path(export_options.path());
+
+    Some(export_options)
+  } else {
+    None
+  };
 
   let open = options.open;
   let _handle = run_build(
@@ -215,41 +239,6 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
   Ok(())
 }
 
-fn create_export_options(
-  app: &cargo_mobile2::config::app::App,
-  config: &super::super::init::IosInitConfig,
-  export_method: Option<ExportMethod>,
-) -> Option<plist::Value> {
-  let mut plist = plist::Dictionary::new();
-
-  if let Some(method) = export_method {
-    plist.insert("method".to_string(), method.to_string().into());
-  }
-
-  if config.code_sign_identity.is_some() || config.provisioning_profile_uuid.is_some() {
-    plist.insert("signingStyle".to_string(), "manual".into());
-  }
-
-  if let Some(identity) = &config.code_sign_identity {
-    plist.insert("signingCertificate".to_string(), identity.clone().into());
-  }
-
-  if let Some(id) = &config.team_id {
-    plist.insert("teamID".to_string(), id.clone().into());
-  }
-
-  if let Some(profile_uuid) = &config.provisioning_profile_uuid {
-    let mut provisioning_profiles = plist::Dictionary::new();
-    provisioning_profiles.insert(app.reverse_identifier(), profile_uuid.clone().into());
-    plist.insert(
-      "provisioningProfiles".to_string(),
-      provisioning_profiles.into(),
-    );
-  }
-
-  (!plist.is_empty()).then(|| plist.into())
-}
-
 #[allow(clippy::too_many_arguments)]
 fn run_build(
   interface: AppInterface,

+ 6 - 7
tooling/cli/src/mobile/ios/dev.rs

@@ -185,13 +185,12 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
     .project_dir()
     .join(config.scheme())
     .join("Info.plist");
-  merge_plist(
-    vec![
-      tauri_path.join("Info.plist").into(),
-      tauri_path.join("Info.ios.plist").into(),
-    ],
-    &info_plist_path,
-  )?;
+  let merged_info_plist = merge_plist(vec![
+    info_plist_path.clone().into(),
+    tauri_path.join("Info.plist").into(),
+    tauri_path.join("Info.ios.plist").into(),
+  ])?;
+  merged_info_plist.to_file_xml(&info_plist_path)?;
 
   run_dev(
     interface,

+ 167 - 30
tooling/cli/src/mobile/ios/mod.rs

@@ -32,6 +32,7 @@ use crate::{
   helpers::{
     app_paths::tauri_dir,
     config::{BundleResources, Config as TauriConfig},
+    pbxproj,
   },
   Result,
 };
@@ -39,7 +40,7 @@ use crate::{
 use std::{
   env::{set_var, var_os},
   fs::create_dir_all,
-  path::{Path, PathBuf},
+  path::PathBuf,
   thread::sleep,
   time::Duration,
 };
@@ -344,8 +345,8 @@ impl From<plist::Value> for PlistKind {
   }
 }
 
-fn merge_plist(src: Vec<PlistKind>, dest: &Path) -> Result<()> {
-  let mut dest_plist = None;
+fn merge_plist(src: Vec<PlistKind>) -> Result<plist::Value> {
+  let mut merged_plist = plist::Dictionary::new();
 
   for plist_kind in src {
     let plist = match plist_kind {
@@ -353,61 +354,197 @@ fn merge_plist(src: Vec<PlistKind>, dest: &Path) -> Result<()> {
       PlistKind::Plist(v) => Ok(v),
     };
     if let Ok(src_plist) = plist {
-      if dest_plist.is_none() {
-        dest_plist.replace(plist::Value::from_file(dest)?);
-      }
-
-      let plist = dest_plist.as_mut().expect("plist not loaded");
-      if let Some(plist) = plist.as_dictionary_mut() {
-        if let Some(dict) = src_plist.into_dictionary() {
-          for (key, value) in dict {
-            plist.insert(key, value);
-          }
+      if let Some(dict) = src_plist.into_dictionary() {
+        for (key, value) in dict {
+          merged_plist.insert(key, value);
         }
       }
     }
   }
 
-  if let Some(dest_plist) = dest_plist {
-    dest_plist.to_file_xml(dest)?;
-  }
-
-  Ok(())
+  Ok(plist::Value::Dictionary(merged_plist))
 }
 
 pub fn signing_from_env() -> Result<(
   Option<tauri_macos_sign::Keychain>,
   Option<tauri_macos_sign::ProvisioningProfile>,
 )> {
-  let keychain = if let (Some(certificate), Some(certificate_password)) = (
+  let keychain = match (
     var_os("IOS_CERTIFICATE"),
     var_os("IOS_CERTIFICATE_PASSWORD"),
   ) {
-    tauri_macos_sign::Keychain::with_certificate(&certificate, &certificate_password).map(Some)?
-  } else {
-    None
+    (Some(certificate), Some(certificate_password)) => {
+      log::info!("Reading iOS certificates from ");
+      tauri_macos_sign::Keychain::with_certificate(&certificate, &certificate_password).map(Some)?
+    }
+    (Some(_), None) => {
+      log::warn!("The IOS_CERTIFICATE environment variable is set but not IOS_CERTIFICATE_PASSWORD. Ignoring the certificate...");
+      None
+    }
+    _ => None,
   };
+
   let provisioning_profile = if let Some(provisioning_profile) = var_os("IOS_MOBILE_PROVISION") {
     tauri_macos_sign::ProvisioningProfile::from_base64(&provisioning_profile).map(Some)?
   } else {
+    if keychain.is_some() {
+      log::warn!("You have provided an iOS certificate via environment variables but the IOS_MOBILE_PROVISION environment variable is not set. This will fail when signing unless the profile is set in your Xcode project.");
+    }
     None
   };
 
   Ok((keychain, provisioning_profile))
 }
 
-pub fn init_config(
+pub struct ProjectConfig {
+  pub code_sign_identity: Option<String>,
+  pub team_id: Option<String>,
+  pub provisioning_profile_uuid: Option<String>,
+}
+
+pub fn project_config(
   keychain: Option<&tauri_macos_sign::Keychain>,
   provisioning_profile: Option<&tauri_macos_sign::ProvisioningProfile>,
-) -> Result<super::init::IosInitConfig> {
-  Ok(super::init::IosInitConfig {
-    code_sign_style: if keychain.is_some() && provisioning_profile.is_some() {
-      super::init::CodeSignStyle::Manual
-    } else {
-      super::init::CodeSignStyle::Automatic
-    },
+) -> Result<ProjectConfig> {
+  Ok(ProjectConfig {
     code_sign_identity: keychain.map(|k| k.signing_identity()),
     team_id: keychain.and_then(|k| k.team_id().map(ToString::to_string)),
     provisioning_profile_uuid: provisioning_profile.and_then(|p| p.uuid().ok()),
   })
 }
+
+pub fn load_pbxproj(config: &AppleConfig) -> Result<pbxproj::Pbxproj> {
+  pbxproj::parse(
+    config
+      .project_dir()
+      .join(format!("{}.xcodeproj", config.app().name()))
+      .join("project.pbxproj"),
+  )
+}
+
+pub fn synchronize_project_config(
+  app: &App,
+  pbxproj: &mut pbxproj::Pbxproj,
+  export_options_list: &mut plist::Dictionary,
+  project_config: &ProjectConfig,
+  debug: bool,
+) -> Result<()> {
+  let manual_signing = project_config.code_sign_identity.is_some()
+    || project_config.provisioning_profile_uuid.is_some();
+
+  if let Some(xc_configuration_list) = pbxproj
+    .xc_configuration_list
+    .clone()
+    .into_values()
+    .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");
+      }
+
+      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);
+        pbxproj.set_build_settings(
+          &build_configuration_ref.id,
+          "\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\"",
+          &identity,
+        );
+      }
+
+      if let Some(id) = &project_config.team_id {
+        pbxproj.set_build_settings(&build_configuration_ref.id, "DEVELOPMENT_TEAM", id);
+        pbxproj.set_build_settings(
+          &build_configuration_ref.id,
+          "\"DEVELOPMENT_TEAM[sdk=iphoneos*]\"",
+          id,
+        );
+      }
+
+      if let Some(profile_uuid) = &project_config.provisioning_profile_uuid {
+        let profile_uuid = format!("\"{profile_uuid}\"");
+        pbxproj.set_build_settings(
+          &build_configuration_ref.id,
+          "PROVISIONING_PROFILE_SPECIFIER",
+          &profile_uuid,
+        );
+        pbxproj.set_build_settings(
+          &build_configuration_ref.id,
+          "\"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]\"",
+          &profile_uuid,
+        );
+      }
+    }
+  }
+
+  let build_configuration = {
+    if let Some(xc_configuration_list) = pbxproj
+      .xc_configuration_list
+      .clone()
+      .into_values()
+      .find(|l| l.comment.contains("_iOS"))
+    {
+      let mut configuration = None;
+      let target = if debug { "debug" } else { "release" };
+      for build_configuration_ref in xc_configuration_list.build_configurations {
+        if build_configuration_ref.comments.contains(target) {
+          configuration = pbxproj
+            .xc_build_configuration
+            .get(&build_configuration_ref.id);
+          break;
+        }
+      }
+
+      configuration
+    } else {
+      None
+    }
+  };
+
+  if let Some(build_configuration) = build_configuration {
+    if let Some(style) = build_configuration.get_build_setting("CODE_SIGN_STYLE") {
+      export_options_list.insert(
+        "signingStyle".to_string(),
+        style.value.to_lowercase().into(),
+      );
+    }
+
+    if let Some(identity) = build_configuration
+      .get_build_setting("\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\"")
+      .or_else(|| build_configuration.get_build_setting("CODE_SIGN_IDENTITY"))
+    {
+      export_options_list.insert(
+        "signingCertificate".to_string(),
+        identity.value.trim_matches('"').into(),
+      );
+    }
+
+    if let Some(id) = build_configuration
+      .get_build_setting("\"DEVELOPMENT_TEAM[sdk=iphoneos*]\"")
+      .or_else(|| build_configuration.get_build_setting("DEVELOPMENT_TEAM"))
+    {
+      export_options_list.insert("teamID".to_string(), id.value.trim_matches('"').into());
+    }
+
+    let profile_uuid = project_config
+      .provisioning_profile_uuid
+      .clone()
+      .or_else(|| {
+        build_configuration
+          .get_build_setting("\"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]\"")
+          .or_else(|| build_configuration.get_build_setting("PROVISIONING_PROFILE_SPECIFIER"))
+          .map(|setting| setting.value.trim_matches('"').to_string())
+      });
+    if let Some(profile_uuid) = profile_uuid {
+      let mut provisioning_profiles = plist::Dictionary::new();
+      provisioning_profiles.insert(app.reverse_identifier(), profile_uuid.into());
+      export_options_list.insert(
+        "provisioningProfiles".to_string(),
+        provisioning_profiles.into(),
+      );
+    }
+  }
+
+  Ok(())
+}

+ 0 - 7
tooling/cli/templates/mobile/ios/project.yml

@@ -15,13 +15,6 @@ settingGroups:
       {{#if apple.development-team}}
       DEVELOPMENT_TEAM: {{apple.development-team}}
       {{/if}}
-      CODE_SIGN_STYLE: {{tauri.ios.code-sign-style}}
-      {{#if tauri.ios.code-sign-identity}}
-      CODE_SIGN_IDENTITY: "{{tauri.ios.code-sign-identity}}"
-      {{/if}}
-      {{#if tauri.ios.provisioning-profile-uuid}}
-      PROVISIONING_PROFILE_SPECIFIER: "{{tauri.ios.provisioning-profile-uuid}}"
-      {{/if}}
 targetTemplates:
   app:
     type: application

+ 474 - 0
tooling/cli/tests/fixtures/pbxproj/project.pbxproj

@@ -0,0 +1,474 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 54;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */; };
+		3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */; };
+		328B4ADB3700C1873BEB7B10 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 90D3B673AFAB8D8AB561F616 /* main.mm */; };
+		6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6B7E79E23E646BA7968B457C /* Assets.xcassets */; };
+		9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62601E25FA39E62BE119B74D /* Metal.framework */; };
+		9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6082E363D51372A7658C351 /* UIKit.framework */; };
+		AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */; };
+		AFA0CA286325FD7A34968CA2 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 384966E551417F94A02D2706 /* Security.framework */; };
+		B60763BD194DFACA215EC7DA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC377692DC31A070A0188C9D /* QuartzCore.framework */; };
+		C6D80743F168BDF017B7769E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */; };
+		DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 338E66700FD330B99D434DD7 /* MetalKit.framework */; };
+		F86717F05E27C72C9FA1FB27 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 74A8FDFB350B966F5AAD4A24 /* assets */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		0E96CE07CD20273DD46BF325 /* main.rs */ = {isa = PBXFileReference; path = main.rs; sourceTree = "<group>"; };
+		1C1AB1B414CA2795AFBEDDB9 /* tray.rs */ = {isa = PBXFileReference; path = tray.rs; sourceTree = "<group>"; };
+		2F63E2AA460089BB58D40C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+		338E66700FD330B99D434DD7 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
+		384966E551417F94A02D2706 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
+		3CA88F22095BE63D88585625 /* menu_plugin.rs */ = {isa = PBXFileReference; path = menu_plugin.rs; sourceTree = "<group>"; };
+		4A00E5F95D64FD14E47F85BD /* libapi_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libapi_lib.a; sourceTree = "<group>"; };
+		4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
+		59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
+		5AC703CEBA41A121596066F3 /* api_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = api_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		62601E25FA39E62BE119B74D /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
+		6B7E79E23E646BA7968B457C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+		74A8FDFB350B966F5AAD4A24 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; };
+		785D025E9542F7E098BF22B5 /* lib.rs */ = {isa = PBXFileReference; path = lib.rs; sourceTree = "<group>"; };
+		879941AE3DAA14534BBC6391 /* api_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = api_iOS.entitlements; sourceTree = "<group>"; };
+		90D3B673AFAB8D8AB561F616 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
+		B6082E363D51372A7658C351 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+		DC377692DC31A070A0188C9D /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		EC8C7948C50C3C9B5D96CB61 /* bindings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bindings.h; sourceTree = "<group>"; };
+		F835F52713CE8F029D5D252C /* cmd.rs */ = {isa = PBXFileReference; path = cmd.rs; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		11E18DCDB3ADFE87C18915EF /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */,
+				3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */,
+				9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */,
+				DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */,
+				B60763BD194DFACA215EC7DA /* QuartzCore.framework in Frameworks */,
+				AFA0CA286325FD7A34968CA2 /* Security.framework in Frameworks */,
+				9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */,
+				C6D80743F168BDF017B7769E /* WebKit.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		0677CEAF1F282F38CBA0F140 = {
+			isa = PBXGroup;
+			children = (
+				74A8FDFB350B966F5AAD4A24 /* assets */,
+				6B7E79E23E646BA7968B457C /* Assets.xcassets */,
+				4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */,
+				F2116A6428EED18BE2A07E2B /* api_iOS */,
+				86D903732E10FAC4D300E8DF /* Externals */,
+				7A9A7AC155D9E22E54D6D847 /* Sources */,
+				CF9AA87D2F6E9C389B7AB70B /* src */,
+				10C9FC3FA3E12D6A4A67999D /* Frameworks */,
+				4AC51E67B71E27F15B02C5CD /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		07051859D6E2D8109C8FB128 /* bindings */ = {
+			isa = PBXGroup;
+			children = (
+				EC8C7948C50C3C9B5D96CB61 /* bindings.h */,
+			);
+			path = bindings;
+			sourceTree = "<group>";
+		};
+		10C9FC3FA3E12D6A4A67999D /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */,
+				4A00E5F95D64FD14E47F85BD /* libapi_lib.a */,
+				62601E25FA39E62BE119B74D /* Metal.framework */,
+				338E66700FD330B99D434DD7 /* MetalKit.framework */,
+				DC377692DC31A070A0188C9D /* QuartzCore.framework */,
+				384966E551417F94A02D2706 /* Security.framework */,
+				B6082E363D51372A7658C351 /* UIKit.framework */,
+				59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		4AC51E67B71E27F15B02C5CD /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				5AC703CEBA41A121596066F3 /* api_iOS.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		7A9A7AC155D9E22E54D6D847 /* Sources */ = {
+			isa = PBXGroup;
+			children = (
+				A3574F52DBC5463B9C3D043D /* api */,
+			);
+			path = Sources;
+			sourceTree = "<group>";
+		};
+		86D903732E10FAC4D300E8DF /* Externals */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = Externals;
+			sourceTree = "<group>";
+		};
+		A3574F52DBC5463B9C3D043D /* api */ = {
+			isa = PBXGroup;
+			children = (
+				90D3B673AFAB8D8AB561F616 /* main.mm */,
+				07051859D6E2D8109C8FB128 /* bindings */,
+			);
+			path = api;
+			sourceTree = "<group>";
+		};
+		CF9AA87D2F6E9C389B7AB70B /* src */ = {
+			isa = PBXGroup;
+			children = (
+				F835F52713CE8F029D5D252C /* cmd.rs */,
+				785D025E9542F7E098BF22B5 /* lib.rs */,
+				0E96CE07CD20273DD46BF325 /* main.rs */,
+				3CA88F22095BE63D88585625 /* menu_plugin.rs */,
+				1C1AB1B414CA2795AFBEDDB9 /* tray.rs */,
+			);
+			name = src;
+			path = ../../src;
+			sourceTree = "<group>";
+		};
+		F2116A6428EED18BE2A07E2B /* api_iOS */ = {
+			isa = PBXGroup;
+			children = (
+				879941AE3DAA14534BBC6391 /* api_iOS.entitlements */,
+				2F63E2AA460089BB58D40C79 /* Info.plist */,
+			);
+			path = api_iOS;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		54DC6E273C78071F3BA12EF3 /* api_iOS */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 01CBC40275452376830D79B1 /* Build configuration list for PBXNativeTarget "api_iOS" */;
+			buildPhases = (
+				FF948951157DE71465B5BD5F /* Build Rust Code */,
+				71E73CC9AB5F1323EC1F6365 /* Sources */,
+				CA2BEC44B6EDA1F21B6155CD /* Resources */,
+				11E18DCDB3ADFE87C18915EF /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = api_iOS;
+			productName = api_iOS;
+			productReference = 5AC703CEBA41A121596066F3 /* api_iOS.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		9BC88C3717DA5D4B78A51C15 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				BuildIndependentTargetsInParallel = YES;
+				LastUpgradeCheck = 1430;
+				TargetAttributes = {
+					54DC6E273C78071F3BA12EF3 = {
+						DevelopmentTeam = Q93MBH6S2F;
+					};
+				};
+			};
+			buildConfigurationList = 8FA67D0F928A09CD639137D1 /* Build configuration list for PBXProject "api" */;
+			compatibilityVersion = "Xcode 14.0";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				Base,
+				en,
+			);
+			mainGroup = 0677CEAF1F282F38CBA0F140;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				54DC6E273C78071F3BA12EF3 /* api_iOS */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		CA2BEC44B6EDA1F21B6155CD /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */,
+				AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */,
+				F86717F05E27C72C9FA1FB27 /* assets in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		FF948951157DE71465B5BD5F /* Build Rust Code */ = {
+			isa = PBXShellScriptBuildPhase;
+			alwaysOutOfDate = 1;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+			);
+			name = "Build Rust Code";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapi_lib.a",
+				"$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapi_lib.a",
+				"$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapi_lib.a",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "cargo tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths \"${FRAMEWORK_SEARCH_PATHS:?}\" --header-search-paths \"${HEADER_SEARCH_PATHS:?}\" --gcc-preprocessor-definitions \"${GCC_PREPROCESSOR_DEFINITIONS:-}\" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		71E73CC9AB5F1323EC1F6365 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				328B4ADB3700C1873BEB7B10 /* main.mm in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		A83F70B4C02DD0222038C7F1 /* release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				SWIFT_VERSION = 5.0;
+			};
+			name = release;
+		};
+		B6AD77E490F315562F75D3D7 /* debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"$(inherited)",
+					"DEBUG=1",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 5.0;
+			};
+			name = debug;
+		};
+		BF284FE6E7AE0C8DDCCE398B /* debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ARCHS = (
+					arm64,
+					"arm64-sim",
+				);
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = api_iOS/api_iOS.entitlements;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = Q93MBH6S2F;
+				ENABLE_BITCODE = NO;
+				"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
+				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"\".\"",
+				);
+				INFOPLIST_FILE = api_iOS/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				"LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				"LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api;
+				PRODUCT_NAME = "Tauri API";
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALID_ARCHS = "arm64  arm64-sim";
+			};
+			name = debug;
+		};
+		DB0E254D0FD84970B57F6410 /* release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ARCHS = (
+					arm64,
+					"arm64-sim",
+				);
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = api_iOS/api_iOS.entitlements;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = Q93MBH6S2F;
+				ENABLE_BITCODE = NO;
+				"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
+				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"\".\"",
+				);
+				INFOPLIST_FILE = api_iOS/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				"LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				"LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api;
+				PRODUCT_NAME = "Tauri API";
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALID_ARCHS = "arm64  arm64-sim";
+			};
+			name = release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		01CBC40275452376830D79B1 /* Build configuration list for PBXNativeTarget "api_iOS" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				BF284FE6E7AE0C8DDCCE398B /* debug */,
+				DB0E254D0FD84970B57F6410 /* release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = debug;
+		};
+		8FA67D0F928A09CD639137D1 /* Build configuration list for PBXProject "api" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				B6AD77E490F315562F75D3D7 /* debug */,
+				A83F70B4C02DD0222038C7F1 /* release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = debug;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 9BC88C3717DA5D4B78A51C15 /* Project object */;
+}

+ 479 - 0
tooling/cli/tests/fixtures/pbxproj/snapshots/tauri_cli__helpers__pbxproj__tests__project-modified.pbxproj.snap

@@ -0,0 +1,479 @@
+---
+source: src/helpers/pbxproj.rs
+expression: pbxproj.serialize()
+---
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 54;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */; };
+		3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */; };
+		328B4ADB3700C1873BEB7B10 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 90D3B673AFAB8D8AB561F616 /* main.mm */; };
+		6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6B7E79E23E646BA7968B457C /* Assets.xcassets */; };
+		9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62601E25FA39E62BE119B74D /* Metal.framework */; };
+		9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6082E363D51372A7658C351 /* UIKit.framework */; };
+		AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */; };
+		AFA0CA286325FD7A34968CA2 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 384966E551417F94A02D2706 /* Security.framework */; };
+		B60763BD194DFACA215EC7DA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC377692DC31A070A0188C9D /* QuartzCore.framework */; };
+		C6D80743F168BDF017B7769E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */; };
+		DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 338E66700FD330B99D434DD7 /* MetalKit.framework */; };
+		F86717F05E27C72C9FA1FB27 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 74A8FDFB350B966F5AAD4A24 /* assets */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		0E96CE07CD20273DD46BF325 /* main.rs */ = {isa = PBXFileReference; path = main.rs; sourceTree = "<group>"; };
+		1C1AB1B414CA2795AFBEDDB9 /* tray.rs */ = {isa = PBXFileReference; path = tray.rs; sourceTree = "<group>"; };
+		2F63E2AA460089BB58D40C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+		338E66700FD330B99D434DD7 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
+		384966E551417F94A02D2706 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
+		3CA88F22095BE63D88585625 /* menu_plugin.rs */ = {isa = PBXFileReference; path = menu_plugin.rs; sourceTree = "<group>"; };
+		4A00E5F95D64FD14E47F85BD /* libapi_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libapi_lib.a; sourceTree = "<group>"; };
+		4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
+		59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
+		5AC703CEBA41A121596066F3 /* api_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = api_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		62601E25FA39E62BE119B74D /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
+		6B7E79E23E646BA7968B457C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+		74A8FDFB350B966F5AAD4A24 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; };
+		785D025E9542F7E098BF22B5 /* lib.rs */ = {isa = PBXFileReference; path = lib.rs; sourceTree = "<group>"; };
+		879941AE3DAA14534BBC6391 /* api_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = api_iOS.entitlements; sourceTree = "<group>"; };
+		90D3B673AFAB8D8AB561F616 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
+		B6082E363D51372A7658C351 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+		DC377692DC31A070A0188C9D /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		EC8C7948C50C3C9B5D96CB61 /* bindings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bindings.h; sourceTree = "<group>"; };
+		F835F52713CE8F029D5D252C /* cmd.rs */ = {isa = PBXFileReference; path = cmd.rs; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		11E18DCDB3ADFE87C18915EF /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */,
+				3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */,
+				9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */,
+				DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */,
+				B60763BD194DFACA215EC7DA /* QuartzCore.framework in Frameworks */,
+				AFA0CA286325FD7A34968CA2 /* Security.framework in Frameworks */,
+				9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */,
+				C6D80743F168BDF017B7769E /* WebKit.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		0677CEAF1F282F38CBA0F140 = {
+			isa = PBXGroup;
+			children = (
+				74A8FDFB350B966F5AAD4A24 /* assets */,
+				6B7E79E23E646BA7968B457C /* Assets.xcassets */,
+				4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */,
+				F2116A6428EED18BE2A07E2B /* api_iOS */,
+				86D903732E10FAC4D300E8DF /* Externals */,
+				7A9A7AC155D9E22E54D6D847 /* Sources */,
+				CF9AA87D2F6E9C389B7AB70B /* src */,
+				10C9FC3FA3E12D6A4A67999D /* Frameworks */,
+				4AC51E67B71E27F15B02C5CD /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		07051859D6E2D8109C8FB128 /* bindings */ = {
+			isa = PBXGroup;
+			children = (
+				EC8C7948C50C3C9B5D96CB61 /* bindings.h */,
+			);
+			path = bindings;
+			sourceTree = "<group>";
+		};
+		10C9FC3FA3E12D6A4A67999D /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */,
+				4A00E5F95D64FD14E47F85BD /* libapi_lib.a */,
+				62601E25FA39E62BE119B74D /* Metal.framework */,
+				338E66700FD330B99D434DD7 /* MetalKit.framework */,
+				DC377692DC31A070A0188C9D /* QuartzCore.framework */,
+				384966E551417F94A02D2706 /* Security.framework */,
+				B6082E363D51372A7658C351 /* UIKit.framework */,
+				59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		4AC51E67B71E27F15B02C5CD /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				5AC703CEBA41A121596066F3 /* api_iOS.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		7A9A7AC155D9E22E54D6D847 /* Sources */ = {
+			isa = PBXGroup;
+			children = (
+				A3574F52DBC5463B9C3D043D /* api */,
+			);
+			path = Sources;
+			sourceTree = "<group>";
+		};
+		86D903732E10FAC4D300E8DF /* Externals */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = Externals;
+			sourceTree = "<group>";
+		};
+		A3574F52DBC5463B9C3D043D /* api */ = {
+			isa = PBXGroup;
+			children = (
+				90D3B673AFAB8D8AB561F616 /* main.mm */,
+				07051859D6E2D8109C8FB128 /* bindings */,
+			);
+			path = api;
+			sourceTree = "<group>";
+		};
+		CF9AA87D2F6E9C389B7AB70B /* src */ = {
+			isa = PBXGroup;
+			children = (
+				F835F52713CE8F029D5D252C /* cmd.rs */,
+				785D025E9542F7E098BF22B5 /* lib.rs */,
+				0E96CE07CD20273DD46BF325 /* main.rs */,
+				3CA88F22095BE63D88585625 /* menu_plugin.rs */,
+				1C1AB1B414CA2795AFBEDDB9 /* tray.rs */,
+			);
+			name = src;
+			path = ../../src;
+			sourceTree = "<group>";
+		};
+		F2116A6428EED18BE2A07E2B /* api_iOS */ = {
+			isa = PBXGroup;
+			children = (
+				879941AE3DAA14534BBC6391 /* api_iOS.entitlements */,
+				2F63E2AA460089BB58D40C79 /* Info.plist */,
+			);
+			path = api_iOS;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		54DC6E273C78071F3BA12EF3 /* api_iOS */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 01CBC40275452376830D79B1 /* Build configuration list for PBXNativeTarget "api_iOS" */;
+			buildPhases = (
+				FF948951157DE71465B5BD5F /* Build Rust Code */,
+				71E73CC9AB5F1323EC1F6365 /* Sources */,
+				CA2BEC44B6EDA1F21B6155CD /* Resources */,
+				11E18DCDB3ADFE87C18915EF /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = api_iOS;
+			productName = api_iOS;
+			productReference = 5AC703CEBA41A121596066F3 /* api_iOS.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		9BC88C3717DA5D4B78A51C15 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				BuildIndependentTargetsInParallel = YES;
+				LastUpgradeCheck = 1430;
+				TargetAttributes = {
+					54DC6E273C78071F3BA12EF3 = {
+						DevelopmentTeam = Q93MBH6S2F;
+					};
+				};
+			};
+			buildConfigurationList = 8FA67D0F928A09CD639137D1 /* Build configuration list for PBXProject "api" */;
+			compatibilityVersion = "Xcode 14.0";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				Base,
+				en,
+			);
+			mainGroup = 0677CEAF1F282F38CBA0F140;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				54DC6E273C78071F3BA12EF3 /* api_iOS */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		CA2BEC44B6EDA1F21B6155CD /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */,
+				AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */,
+				F86717F05E27C72C9FA1FB27 /* assets in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		FF948951157DE71465B5BD5F /* Build Rust Code */ = {
+			isa = PBXShellScriptBuildPhase;
+			alwaysOutOfDate = 1;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+			);
+			name = "Build Rust Code";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapi_lib.a",
+				"$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapi_lib.a",
+				"$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapi_lib.a",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "cargo tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths \"${FRAMEWORK_SEARCH_PATHS:?}\" --header-search-paths \"${HEADER_SEARCH_PATHS:?}\" --gcc-preprocessor-definitions \"${GCC_PREPROCESSOR_DEFINITIONS:-}\" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		71E73CC9AB5F1323EC1F6365 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				328B4ADB3700C1873BEB7B10 /* main.mm in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		A83F70B4C02DD0222038C7F1 /* release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				SWIFT_VERSION = 5.0;
+			};
+			name = release;
+		};
+		B6AD77E490F315562F75D3D7 /* debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"$(inherited)",
+					"DEBUG=1",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 5.0;
+			};
+			name = debug;
+		};
+		BF284FE6E7AE0C8DDCCE398B /* debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ARCHS = (
+					arm64,
+					"arm64-sim",
+				);
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = api_iOS/api_iOS.entitlements;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = Q93MBH6S2F;
+				ENABLE_BITCODE = NO;
+				"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
+				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"\".\"",
+				);
+				INFOPLIST_FILE = api_iOS/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				"LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				"LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api;
+				PRODUCT_NAME = "Tauri API";
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALID_ARCHS = "arm64  arm64-sim";
+			};
+			name = debug;
+		};
+		DB0E254D0FD84970B57F6410 /* release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ARCHS = (
+					arm64,
+					"arm64-sim",
+				);
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_ENTITLEMENTS = api_iOS/api_iOS.entitlements;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				DEVELOPMENT_TEAM = Q93MBH6S2F;
+				ENABLE_BITCODE = NO;
+				"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
+				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"\".\"",
+				);
+				INFOPLIST_FILE = api_iOS/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				"LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				"LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
+				PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api;
+				PRODUCT_NAME = "Tauri Test";
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALID_ARCHS = "arm64  arm64-sim";
+				UNKNOWN = 9283j49238h;
+			};
+			name = release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		01CBC40275452376830D79B1 /* Build configuration list for PBXNativeTarget "api_iOS" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				BF284FE6E7AE0C8DDCCE398B /* debug */,
+				DB0E254D0FD84970B57F6410 /* release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = debug;
+		};
+		8FA67D0F928A09CD639137D1 /* Build configuration list for PBXProject "api" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				B6AD77E490F315562F75D3D7 /* debug */,
+				A83F70B4C02DD0222038C7F1 /* release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = debug;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 9BC88C3717DA5D4B78A51C15 /* Project object */;
+}

+ 916 - 0
tooling/cli/tests/fixtures/pbxproj/snapshots/tauri_cli__helpers__pbxproj__tests__project.pbxproj.snap

@@ -0,0 +1,916 @@
+---
+source: src/helpers/pbxproj.rs
+expression: "super::parse(fixtures_path.join(\"project.pbxproj\")).expect(\"failed to parse pbxproj\")"
+---
+Pbxproj {
+    xc_build_configuration: {
+        "A83F70B4C02DD0222038C7F1": XCBuildConfiguration {
+            build_settings: [
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 263,
+                    key: "ALWAYS_SEARCH_USER_PATHS",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 264,
+                    key: "CLANG_ANALYZER_NONNULL",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 265,
+                    key: "CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION",
+                    value: "YES_AGGRESSIVE",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 266,
+                    key: "CLANG_CXX_LANGUAGE_STANDARD",
+                    value: "\"gnu++14\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 267,
+                    key: "CLANG_CXX_LIBRARY",
+                    value: "\"libc++\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 268,
+                    key: "CLANG_ENABLE_MODULES",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 269,
+                    key: "CLANG_ENABLE_OBJC_ARC",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 270,
+                    key: "CLANG_ENABLE_OBJC_WEAK",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 271,
+                    key: "CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 272,
+                    key: "CLANG_WARN_BOOL_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 273,
+                    key: "CLANG_WARN_COMMA",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 274,
+                    key: "CLANG_WARN_CONSTANT_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 275,
+                    key: "CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 276,
+                    key: "CLANG_WARN_DIRECT_OBJC_ISA_USAGE",
+                    value: "YES_ERROR",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 277,
+                    key: "CLANG_WARN_DOCUMENTATION_COMMENTS",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 278,
+                    key: "CLANG_WARN_EMPTY_BODY",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 279,
+                    key: "CLANG_WARN_ENUM_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 280,
+                    key: "CLANG_WARN_INFINITE_RECURSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 281,
+                    key: "CLANG_WARN_INT_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 282,
+                    key: "CLANG_WARN_NON_LITERAL_NULL_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 283,
+                    key: "CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 284,
+                    key: "CLANG_WARN_OBJC_LITERAL_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 285,
+                    key: "CLANG_WARN_OBJC_ROOT_CLASS",
+                    value: "YES_ERROR",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 286,
+                    key: "CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 287,
+                    key: "CLANG_WARN_RANGE_LOOP_ANALYSIS",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 288,
+                    key: "CLANG_WARN_STRICT_PROTOTYPES",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 289,
+                    key: "CLANG_WARN_SUSPICIOUS_MOVE",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 290,
+                    key: "CLANG_WARN_UNGUARDED_AVAILABILITY",
+                    value: "YES_AGGRESSIVE",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 291,
+                    key: "CLANG_WARN_UNREACHABLE_CODE",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 292,
+                    key: "CLANG_WARN__DUPLICATE_METHOD_MATCH",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 293,
+                    key: "COPY_PHASE_STRIP",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 294,
+                    key: "DEBUG_INFORMATION_FORMAT",
+                    value: "\"dwarf-with-dsym\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 295,
+                    key: "ENABLE_NS_ASSERTIONS",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 296,
+                    key: "ENABLE_STRICT_OBJC_MSGSEND",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 297,
+                    key: "GCC_C_LANGUAGE_STANDARD",
+                    value: "gnu11",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 298,
+                    key: "GCC_NO_COMMON_BLOCKS",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 299,
+                    key: "GCC_WARN_64_TO_32_BIT_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 300,
+                    key: "GCC_WARN_ABOUT_RETURN_TYPE",
+                    value: "YES_ERROR",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 301,
+                    key: "GCC_WARN_UNDECLARED_SELECTOR",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 302,
+                    key: "GCC_WARN_UNINITIALIZED_AUTOS",
+                    value: "YES_AGGRESSIVE",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 303,
+                    key: "GCC_WARN_UNUSED_FUNCTION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 304,
+                    key: "GCC_WARN_UNUSED_VARIABLE",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 305,
+                    key: "IPHONEOS_DEPLOYMENT_TARGET",
+                    value: "13.0",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 306,
+                    key: "MTL_ENABLE_DEBUG_INFO",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 307,
+                    key: "MTL_FAST_MATH",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 308,
+                    key: "PRODUCT_NAME",
+                    value: "\"$(TARGET_NAME)\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 309,
+                    key: "SDKROOT",
+                    value: "iphoneos",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 310,
+                    key: "SWIFT_COMPILATION_MODE",
+                    value: "wholemodule",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 311,
+                    key: "SWIFT_OPTIMIZATION_LEVEL",
+                    value: "\"-O\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 312,
+                    key: "SWIFT_VERSION",
+                    value: "5.0",
+                },
+            ],
+        },
+        "B6AD77E490F315562F75D3D7": XCBuildConfiguration {
+            build_settings: [
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 319,
+                    key: "ALWAYS_SEARCH_USER_PATHS",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 320,
+                    key: "CLANG_ANALYZER_NONNULL",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 321,
+                    key: "CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION",
+                    value: "YES_AGGRESSIVE",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 322,
+                    key: "CLANG_CXX_LANGUAGE_STANDARD",
+                    value: "\"gnu++14\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 323,
+                    key: "CLANG_CXX_LIBRARY",
+                    value: "\"libc++\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 324,
+                    key: "CLANG_ENABLE_MODULES",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 325,
+                    key: "CLANG_ENABLE_OBJC_ARC",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 326,
+                    key: "CLANG_ENABLE_OBJC_WEAK",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 327,
+                    key: "CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 328,
+                    key: "CLANG_WARN_BOOL_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 329,
+                    key: "CLANG_WARN_COMMA",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 330,
+                    key: "CLANG_WARN_CONSTANT_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 331,
+                    key: "CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 332,
+                    key: "CLANG_WARN_DIRECT_OBJC_ISA_USAGE",
+                    value: "YES_ERROR",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 333,
+                    key: "CLANG_WARN_DOCUMENTATION_COMMENTS",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 334,
+                    key: "CLANG_WARN_EMPTY_BODY",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 335,
+                    key: "CLANG_WARN_ENUM_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 336,
+                    key: "CLANG_WARN_INFINITE_RECURSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 337,
+                    key: "CLANG_WARN_INT_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 338,
+                    key: "CLANG_WARN_NON_LITERAL_NULL_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 339,
+                    key: "CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 340,
+                    key: "CLANG_WARN_OBJC_LITERAL_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 341,
+                    key: "CLANG_WARN_OBJC_ROOT_CLASS",
+                    value: "YES_ERROR",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 342,
+                    key: "CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 343,
+                    key: "CLANG_WARN_RANGE_LOOP_ANALYSIS",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 344,
+                    key: "CLANG_WARN_STRICT_PROTOTYPES",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 345,
+                    key: "CLANG_WARN_SUSPICIOUS_MOVE",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 346,
+                    key: "CLANG_WARN_UNGUARDED_AVAILABILITY",
+                    value: "YES_AGGRESSIVE",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 347,
+                    key: "CLANG_WARN_UNREACHABLE_CODE",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 348,
+                    key: "CLANG_WARN__DUPLICATE_METHOD_MATCH",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 349,
+                    key: "COPY_PHASE_STRIP",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 350,
+                    key: "DEBUG_INFORMATION_FORMAT",
+                    value: "dwarf",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 351,
+                    key: "ENABLE_STRICT_OBJC_MSGSEND",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 352,
+                    key: "ENABLE_TESTABILITY",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 353,
+                    key: "GCC_C_LANGUAGE_STANDARD",
+                    value: "gnu11",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 354,
+                    key: "GCC_DYNAMIC_NO_PIC",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 355,
+                    key: "GCC_NO_COMMON_BLOCKS",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 356,
+                    key: "GCC_OPTIMIZATION_LEVEL",
+                    value: "0",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 357,
+                    key: "GCC_PREPROCESSOR_DEFINITIONS",
+                    value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t);\n",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 361,
+                    key: "GCC_WARN_64_TO_32_BIT_CONVERSION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 362,
+                    key: "GCC_WARN_ABOUT_RETURN_TYPE",
+                    value: "YES_ERROR",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 363,
+                    key: "GCC_WARN_UNDECLARED_SELECTOR",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 364,
+                    key: "GCC_WARN_UNINITIALIZED_AUTOS",
+                    value: "YES_AGGRESSIVE",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 365,
+                    key: "GCC_WARN_UNUSED_FUNCTION",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 366,
+                    key: "GCC_WARN_UNUSED_VARIABLE",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 367,
+                    key: "IPHONEOS_DEPLOYMENT_TARGET",
+                    value: "13.0",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 368,
+                    key: "MTL_ENABLE_DEBUG_INFO",
+                    value: "INCLUDE_SOURCE",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 369,
+                    key: "MTL_FAST_MATH",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 370,
+                    key: "ONLY_ACTIVE_ARCH",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 371,
+                    key: "PRODUCT_NAME",
+                    value: "\"$(TARGET_NAME)\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 372,
+                    key: "SDKROOT",
+                    value: "iphoneos",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 373,
+                    key: "SWIFT_ACTIVE_COMPILATION_CONDITIONS",
+                    value: "DEBUG",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 374,
+                    key: "SWIFT_OPTIMIZATION_LEVEL",
+                    value: "\"-Onone\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 375,
+                    key: "SWIFT_VERSION",
+                    value: "5.0",
+                },
+            ],
+        },
+        "BF284FE6E7AE0C8DDCCE398B": XCBuildConfiguration {
+            build_settings: [
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 382,
+                    key: "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 383,
+                    key: "ARCHS",
+                    value: "(\t\t\t\t\tarm64,\n\t\t\t\t\t\"arm64-sim\",\n\t\t\t\t);\n",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 387,
+                    key: "ASSETCATALOG_COMPILER_APPICON_NAME",
+                    value: "AppIcon",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 388,
+                    key: "CODE_SIGN_ENTITLEMENTS",
+                    value: "api_iOS/api_iOS.entitlements",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 389,
+                    key: "CODE_SIGN_IDENTITY",
+                    value: "\"iPhone Developer\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 390,
+                    key: "DEVELOPMENT_TEAM",
+                    value: "Q93MBH6S2F",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 391,
+                    key: "ENABLE_BITCODE",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 392,
+                    key: "\"EXCLUDED_ARCHS[sdk=iphoneos*]\"",
+                    value: "\"arm64-sim x86_64\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 393,
+                    key: "\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\"",
+                    value: "arm64",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 394,
+                    key: "FRAMEWORK_SEARCH_PATHS",
+                    value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\".\\\"\",\n\t\t\t\t);\n",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 398,
+                    key: "INFOPLIST_FILE",
+                    value: "api_iOS/Info.plist",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 399,
+                    key: "LD_RUNPATH_SEARCH_PATHS",
+                    value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 403,
+                    key: "\"LIBRARY_SEARCH_PATHS[arch=arm64-sim]\"",
+                    value: "\"$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 404,
+                    key: "\"LIBRARY_SEARCH_PATHS[arch=arm64]\"",
+                    value: "\"$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 405,
+                    key: "\"LIBRARY_SEARCH_PATHS[arch=x86_64]\"",
+                    value: "\"$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 406,
+                    key: "PRODUCT_BUNDLE_IDENTIFIER",
+                    value: "com.tauri.api",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 407,
+                    key: "PRODUCT_NAME",
+                    value: "\"Tauri API\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 408,
+                    key: "SDKROOT",
+                    value: "iphoneos",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 409,
+                    key: "TARGETED_DEVICE_FAMILY",
+                    value: "\"1,2\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 410,
+                    key: "VALID_ARCHS",
+                    value: "\"arm64  arm64-sim\"",
+                },
+            ],
+        },
+        "DB0E254D0FD84970B57F6410": XCBuildConfiguration {
+            build_settings: [
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 417,
+                    key: "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES",
+                    value: "YES",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 418,
+                    key: "ARCHS",
+                    value: "(\t\t\t\t\tarm64,\n\t\t\t\t\t\"arm64-sim\",\n\t\t\t\t);\n",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 422,
+                    key: "ASSETCATALOG_COMPILER_APPICON_NAME",
+                    value: "AppIcon",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 423,
+                    key: "CODE_SIGN_ENTITLEMENTS",
+                    value: "api_iOS/api_iOS.entitlements",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 424,
+                    key: "CODE_SIGN_IDENTITY",
+                    value: "\"iPhone Developer\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 425,
+                    key: "DEVELOPMENT_TEAM",
+                    value: "Q93MBH6S2F",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 426,
+                    key: "ENABLE_BITCODE",
+                    value: "NO",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 427,
+                    key: "\"EXCLUDED_ARCHS[sdk=iphoneos*]\"",
+                    value: "\"arm64-sim x86_64\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 428,
+                    key: "\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\"",
+                    value: "arm64",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 429,
+                    key: "FRAMEWORK_SEARCH_PATHS",
+                    value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\".\\\"\",\n\t\t\t\t);\n",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 433,
+                    key: "INFOPLIST_FILE",
+                    value: "api_iOS/Info.plist",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 434,
+                    key: "LD_RUNPATH_SEARCH_PATHS",
+                    value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 438,
+                    key: "\"LIBRARY_SEARCH_PATHS[arch=arm64-sim]\"",
+                    value: "\"$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 439,
+                    key: "\"LIBRARY_SEARCH_PATHS[arch=arm64]\"",
+                    value: "\"$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 440,
+                    key: "\"LIBRARY_SEARCH_PATHS[arch=x86_64]\"",
+                    value: "\"$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 441,
+                    key: "PRODUCT_BUNDLE_IDENTIFIER",
+                    value: "com.tauri.api",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 442,
+                    key: "PRODUCT_NAME",
+                    value: "\"Tauri API\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 443,
+                    key: "SDKROOT",
+                    value: "iphoneos",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 444,
+                    key: "TARGETED_DEVICE_FAMILY",
+                    value: "\"1,2\"",
+                },
+                BuildSettings {
+                    identation: "\t\t\t\t",
+                    line_number: 445,
+                    key: "VALID_ARCHS",
+                    value: "\"arm64  arm64-sim\"",
+                },
+            ],
+        },
+    },
+    xc_configuration_list: {
+        "01CBC40275452376830D79B1": XCConfigurationList {
+            comment: "/* Build configuration list for PBXNativeTarget \"api_iOS\" */",
+            build_configurations: [
+                BuildConfigurationRef {
+                    id: "BF284FE6E7AE0C8DDCCE398B",
+                    comments: "/* debug */",
+                },
+                BuildConfigurationRef {
+                    id: "DB0E254D0FD84970B57F6410",
+                    comments: "/* release */",
+                },
+            ],
+        },
+        "8FA67D0F928A09CD639137D1": XCConfigurationList {
+            comment: "/* Build configuration list for PBXProject \"api\" */",
+            build_configurations: [
+                BuildConfigurationRef {
+                    id: "B6AD77E490F315562F75D3D7",
+                    comments: "/* debug */",
+                },
+                BuildConfigurationRef {
+                    id: "A83F70B4C02DD0222038C7F1",
+                    comments: "/* release */",
+                },
+            ],
+        },
+    },
+}