Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugin): add option to use a Xcode project for iOS #9843

Merged
merged 9 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changes/plugin-ios-xcode-project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"tauri-cli": patch:feat
"@tauri-apps/cli": patch:feat
"tauri-plugin": patch:feat
"tauri-utils": patch:feat
"tauri": patch:feat
---

Added an option to use a Xcode project for the iOS plugin instead of a plain SwiftPM project.
2 changes: 1 addition & 1 deletion core/tauri-plugin/src/build/mobile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub(crate) fn setup(
&[".build", "Package.resolved", "Tests"],
)
.context("failed to copy tauri-api to the plugin project")?;
tauri_utils::build::link_swift_library(
tauri_utils::build::link_apple_library(
&std::env::var("CARGO_PKG_NAME").unwrap(),
manifest_dir.join(path),
);
Expand Down
68 changes: 67 additions & 1 deletion core/tauri-utils/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@

/// Link a Swift library.
#[cfg(target_os = "macos")]
pub fn link_swift_library(name: &str, source: impl AsRef<std::path::Path>) {
pub fn link_apple_library(name: &str, source: impl AsRef<std::path::Path>) {
if source.as_ref().join("Package.swift").exists() {
link_swift_library(name, source);
} else {
link_xcode_library(name, source);
}
}

/// Link a Swift library.
#[cfg(target_os = "macos")]
fn link_swift_library(name: &str, source: impl AsRef<std::path::Path>) {
let source = source.as_ref();

let sdk_root = std::env::var_os("SDKROOT");
Expand All @@ -23,3 +33,59 @@ pub fn link_swift_library(name: &str, source: impl AsRef<std::path::Path>) {
std::env::set_var("SDKROOT", root);
}
}

/// Link a Xcode library.
#[cfg(target_os = "macos")]
fn link_xcode_library(name: &str, source: impl AsRef<std::path::Path>) {
use std::{path::PathBuf, process::Command};

let source = source.as_ref();
let configuration = if std::env::var("DEBUG")
.map(|v| v == "true")
.unwrap_or_default()
{
"Debug"
} else {
"Release"
};

let (sdk, arch) = match std::env::var("TARGET").unwrap().as_str() {
"aarch64-apple-ios" => ("iphoneos", "arm64"),
"aarch64-apple-ios-sim" => ("iphonesimulator", "arm64"),
"x86_64-apple-ios" => ("iphonesimulator", "x86_64"),
_ => return,
};

let out_dir = std::env::var_os("OUT_DIR").map(PathBuf::from).unwrap();
let derived_data_path = out_dir.join(format!("derivedData-{name}"));

let status = Command::new("xcodebuild")
.arg("build")
.arg("-scheme")
.arg(name)
.arg("-configuration")
.arg(configuration)
.arg("-sdk")
.arg(sdk)
.arg("-arch")
.arg(arch)
.arg("-derivedDataPath")
.arg(&derived_data_path)
.arg("BUILD_LIBRARY_FOR_DISTRIBUTION=YES")
.arg("OTHER_SWIFT_FLAGS=-no-verify-emitted-module-interface")
.current_dir(source)
.env_clear()
.status()
.unwrap();

assert!(status.success());

let lib_out_dir = derived_data_path
.join("Build")
.join("Products")
.join(format!("{configuration}-{sdk}"));

println!("cargo:rerun-if-changed={}", source.display());
println!("cargo:rustc-link-search=native={}", lib_out_dir.display());
println!("cargo:rustc-link-lib=static={name}");
}
2 changes: 1 addition & 1 deletion core/tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ fn main() {
if target_os == "ios" {
let lib_path =
PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("mobile/ios-api");
tauri_utils::build::link_swift_library("Tauri", &lib_path);
tauri_utils::build::link_apple_library("Tauri", &lib_path);
println!("cargo:ios_library_path={}", lib_path.display());
}
}
Expand Down
62 changes: 31 additions & 31 deletions core/tauri/mobile/ios-api/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,35 @@
import PackageDescription

let package = Package(
name: "Tauri",
platforms: [
.macOS(.v10_13),
.iOS(.v11),
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "Tauri",
type: .static,
targets: ["Tauri"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(name: "SwiftRs", url: "https://github.com/Brendonovich/swift-rs", from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "Tauri",
dependencies: [
.byName(name: "SwiftRs"),
],
path: "Sources"
),
.testTarget(
name: "TauriTests",
dependencies: ["Tauri"]
),
]
name: "Tauri",
platforms: [
.macOS(.v10_13),
.iOS(.v11),
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "Tauri",
type: .static,
targets: ["Tauri"])
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(name: "SwiftRs", url: "https://github.com/Brendonovich/swift-rs", from: "1.0.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "Tauri",
dependencies: [
.byName(name: "SwiftRs")
],
path: "Sources"
),
.testTarget(
name: "TauriTests",
dependencies: ["Tauri"]
),
]
)
11 changes: 11 additions & 0 deletions examples/api/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions examples/api/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ name = "api_lib"
crate-type = ["staticlib", "cdylib", "rlib"]

[build-dependencies]
tauri-build = { path = "../../../core/tauri-build", features = ["codegen", "isolation"] }
tauri-build = { path = "../../../core/tauri-build", features = [
"codegen",
"isolation",
] }

[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = [ "derive" ] }
serde = { version = "1.0", features = ["derive"] }
tiny_http = "0.11"
log = "0.4"
tauri-plugin-sample = { path = "./tauri-plugin-sample/" }
Expand All @@ -28,15 +31,15 @@ features = [
"image-png",
"isolation",
"macos-private-api",
"tray-icon"
"tray-icon",
]

[dev-dependencies.tauri]
path = "../../../core/tauri"
features = ["test"]

[features]
prod = [ "tauri/custom-protocol" ]
prod = ["tauri/custom-protocol"]

# default to small, optimized release binaries
[profile.release]
Expand Down
2 changes: 1 addition & 1 deletion tooling/cli/src/mobile/ios/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ fn run_dev(
}
Err(e) => {
crate::dev::kill_before_dev_process();
Err(e.into())
Err(e)
}
}
} else {
Expand Down
28 changes: 26 additions & 2 deletions tooling/cli/src/plugin/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
VersionMetadata,
};
use anyhow::Context;
use clap::Parser;
use clap::{Parser, ValueEnum};
use handlebars::{to_json, Handlebars};
use heck::{ToKebabCase, ToPascalCase, ToSnakeCase};
use include_dir::{include_dir, Dir};
Expand Down Expand Up @@ -53,6 +53,17 @@ pub struct Options {
/// Whether to initialize Android and iOS projects for the plugin.
#[clap(long)]
pub(crate) mobile: bool,
/// Type of framework to use for the iOS project.
#[clap(long)]
pub(crate) ios_framework: Option<IosFrameworkKind>,
}

#[derive(Debug, Clone, ValueEnum)]
pub enum IosFrameworkKind {
/// Swift Package Manager project
Spm,
/// Xcode project
Xcode,
}

impl Options {
Expand Down Expand Up @@ -155,6 +166,8 @@ pub fn command(mut options: Options) -> Result<()> {
None
};

let ios_framework = options.ios_framework.unwrap_or(IosFrameworkKind::Spm);

let mut created_dirs = Vec::new();
template::render_with_generator(
&handlebars,
Expand Down Expand Up @@ -193,7 +206,18 @@ pub fn command(mut options: Options) -> Result<()> {
return Ok(None);
}
}
"ios" if !(options.ios || options.mobile) => return Ok(None),
"ios-spm" | "ios-xcode" if !(options.ios || options.mobile) => return Ok(None),
"ios-spm" if !matches!(ios_framework, IosFrameworkKind::Spm) => return Ok(None),
"ios-xcode" if !matches!(ios_framework, IosFrameworkKind::Xcode) => return Ok(None),
"ios-spm" | "ios-xcode" => {
let folder_name = components.next().unwrap().as_os_str().to_string_lossy();

path = Path::new("ios")
.join(Component::Normal(&std::ffi::OsString::from(
&folder_name.replace("{{ plugin_name }}", &plugin_name),
)))
.join(components.collect::<PathBuf>());
}
"guest-js" | "rollup.config.js" | "tsconfig.json" | "package.json"
if options.no_api =>
{
Expand Down
4 changes: 4 additions & 0 deletions tooling/cli/src/plugin/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ pub struct Options {
/// Whether to initialize Android and iOS projects for the plugin.
#[clap(long)]
mobile: bool,
/// Type of framework to use for the iOS project.
#[clap(long)]
pub(crate) ios_framework: Option<super::init::IosFrameworkKind>,
}

impl From<Options> for super::init::Options {
Expand All @@ -49,6 +52,7 @@ impl From<Options> for super::init::Options {
android: o.android,
ios: o.ios,
mobile: o.mobile,
ios_framework: o.ios_framework,
}
}
}
Expand Down
Loading
Loading