diff --git a/.changes/visionos.md b/.changes/visionos.md new file mode 100644 index 00000000..d400b06e --- /dev/null +++ b/.changes/visionos.md @@ -0,0 +1,5 @@ +--- +"cargo-mobile2": minor +--- + +Added visionOS support for Apple Vision Pro based on https://github.com/rust-lang/rust/pull/121419 \ No newline at end of file diff --git a/src/apple/config/mod.rs b/src/apple/config/mod.rs index 8187d231..565a133a 100644 --- a/src/apple/config/mod.rs +++ b/src/apple/config/mod.rs @@ -21,6 +21,7 @@ use thiserror::Error; static DEFAULT_PROJECT_DIR: &str = "gen/apple"; const DEFAULT_BUNDLE_VERSION: VersionNumber = VersionNumber::new(VersionTriple::new(1, 0, 0), None); const DEFAULT_IOS_VERSION: VersionDouble = VersionDouble::new(13, 0); +const DEFAULT_VISIONOS_VERSION: VersionDouble = VersionDouble::new(1, 0); const DEFAULT_MACOS_VERSION: VersionDouble = VersionDouble::new(11, 0); #[derive(Debug, Default, Serialize, Deserialize)] @@ -151,6 +152,8 @@ pub struct Metadata { #[serde(default)] pub ios: Platform, #[serde(default)] + pub visionos: Platform, + #[serde(default)] pub macos: Platform, } @@ -159,6 +162,7 @@ impl Default for Metadata { Self { supported: true, ios: Default::default(), + visionos: Default::default(), macos: Default::default(), } } @@ -173,6 +177,10 @@ impl Metadata { &self.ios } + pub fn visionos(&self) -> &Platform { + &self.visionos + } + pub fn macos(&self) -> &Platform { &self.macos } @@ -286,6 +294,7 @@ pub struct Config { bundle_version: VersionNumber, bundle_version_short: VersionTriple, ios_version: VersionDouble, + visionos_version: VersionDouble, macos_version: VersionDouble, use_legacy_build_system: bool, plist_pairs: Vec, @@ -353,6 +362,12 @@ impl Config { .transpose() .map_err(Error::IosVersionInvalid)? .unwrap_or(DEFAULT_IOS_VERSION), + visionos_version: raw + .visionos_version + .map(|str| VersionDouble::from_str(&str)) + .transpose() + .map_err(Error::IosVersionInvalid)? + .unwrap_or(DEFAULT_VISIONOS_VERSION), macos_version: raw .macos_version .map(|str| VersionDouble::from_str(&str)) diff --git a/src/apple/config/raw.rs b/src/apple/config/raw.rs index 4014d00f..562f5c71 100644 --- a/src/apple/config/raw.rs +++ b/src/apple/config/raw.rs @@ -123,6 +123,7 @@ pub struct Raw { pub bundle_version: Option, pub bundle_version_short: Option, pub ios_version: Option, + pub visionos_version: Option, pub macos_version: Option, pub use_legacy_build_system: Option, pub plist_pairs: Option>, @@ -145,6 +146,7 @@ impl Raw { bundle_version: None, bundle_version_short: None, ios_version: None, + visionos_version: None, macos_version: None, use_legacy_build_system: None, plist_pairs: None, @@ -227,6 +229,7 @@ impl Raw { bundle_version: None, bundle_version_short: None, ios_version: None, + visionos_version: None, macos_version: None, use_legacy_build_system: None, plist_pairs: None, diff --git a/src/apple/device/mod.rs b/src/apple/device/mod.rs index 80cdbd80..6e5a18f6 100644 --- a/src/apple/device/mod.rs +++ b/src/apple/device/mod.rs @@ -58,6 +58,7 @@ impl Reportable for RunError { pub enum DeviceKind { Simulator, IosDeployDevice, + VisionOsDeployDevice, DeviceCtlDevice, } @@ -133,7 +134,9 @@ impl<'a> Device<'a> { match self.kind { DeviceKind::Simulator => simctl::run(config, env, non_interactive, &self.id) .map_err(|e| RunError::DeployFailed(e.to_string())), - DeviceKind::IosDeployDevice | DeviceKind::DeviceCtlDevice => { + DeviceKind::IosDeployDevice + | DeviceKind::VisionOsDeployDevice + | DeviceKind::DeviceCtlDevice => { println!("Exporting app..."); self.target .export(config, env, noise_level) diff --git a/src/apple/device/simctl/mod.rs b/src/apple/device/simctl/mod.rs index ee62f431..eeac51c8 100644 --- a/src/apple/device/simctl/mod.rs +++ b/src/apple/device/simctl/mod.rs @@ -27,16 +27,24 @@ impl Display for Device { impl<'a> From for AppleDevice<'a> { fn from(device: Device) -> AppleDevice<'a> { + let name = device.name.clone(); + let is_visionos = name.contains("Apple Vision Pro"); + let target = Target::for_triple(if cfg!(target_arch = "aarch64") { + match is_visionos { + true => "aarch64-apple-visionos", + _ => "aarch64-apple-ios", // TODO: figure out how to check for sim here, or probably do this elsewhere, and just add -sim to the triple + // true => "aarch64-apple-visionos-sim", + // _ => "aarch64-apple-ios-sim + } + } else { + "x86_64-apple-ios" + }); + AppleDevice::new( device.udid, device.name, "".into(), - Target::for_arch(if cfg!(target_arch = "aarch64") { - "arm64-sim" - } else { - "x86_64" - }) - .unwrap(), + target.unwrap(), DeviceKind::Simulator, ) } diff --git a/src/apple/target.rs b/src/apple/target.rs index d888586f..4980f40f 100644 --- a/src/apple/target.rs +++ b/src/apple/target.rs @@ -143,24 +143,24 @@ pub struct Target<'a> { } impl<'a> TargetTrait<'a> for Target<'a> { - const DEFAULT_KEY: &'static str = "aarch64"; + const DEFAULT_KEY: &'static str = "aarch64-apple-ios"; fn all() -> &'a BTreeMap<&'a str, Self> { static TARGETS: OnceCell>> = OnceCell::new(); TARGETS.get_or_init(|| { let mut targets = BTreeMap::new(); targets.insert( - "aarch64", + "aarch64-apple-ios", Target { triple: "aarch64-apple-ios", arch: "arm64", sdk: "iphoneos", - alias: Some("arm64e"), + alias: Some("arm64e-ios"), min_xcode_version: None, }, ); targets.insert( - "x86_64", + "x86_64-apple-ios", Target { triple: "x86_64-apple-ios", arch: "x86_64", @@ -175,12 +175,32 @@ impl<'a> TargetTrait<'a> for Target<'a> { }, ); targets.insert( - "aarch64-sim", + "aarch64-apple-ios-sim", Target { triple: "aarch64-apple-ios-sim", arch: "arm64-sim", sdk: "iphonesimulator", - alias: Some("arm64e-sim"), + alias: Some("arm64e-ios-sim"), + min_xcode_version: None, + }, + ); + targets.insert( + "aarch64-apple-visionos", + Target { + triple: "aarch64-apple-visionos", + arch: "arm64", + sdk: "xros", + alias: Some("arm64e-xros"), + min_xcode_version: None, + }, + ); + targets.insert( + "aarch64-apple-visionos-sim", + Target { + triple: "aarch64-apple-visionos-sim", + arch: "arm64-sim", + sdk: "xrsimulator", + alias: Some("arm64e-xros-sim"), min_xcode_version: None, }, ); @@ -201,6 +221,13 @@ impl<'a> TargetTrait<'a> for Target<'a> { } } +pub enum TargetPlatform { + MacOS, + #[allow(non_camel_case_types)] + iOS, + VisionOS, +} + impl<'a> Target<'a> { // TODO: Make this cleaner pub fn macos() -> Self { @@ -213,16 +240,44 @@ impl<'a> Target<'a> { } } + pub fn get_platform(&self) -> TargetPlatform { + let platform = if self.is_macos() { + TargetPlatform::MacOS + } else if self.is_ios() { + TargetPlatform::iOS + } else if self.is_visionos() { + TargetPlatform::VisionOS + } else { + TargetPlatform::MacOS + }; + + platform + } + pub fn is_macos(&self) -> bool { *self == Self::macos() } + pub fn is_ios(&self) -> bool { + self.triple.contains("apple-ios") + } + + pub fn is_visionos(&self) -> bool { + self.triple.contains("apple-visionos") + } + pub fn for_arch(arch: &str) -> Option<&'a Self> { Self::all() .values() .find(|target| target.arch == arch || target.alias == Some(arch)) } + pub fn for_triple(triple: &str) -> Option<&'a Self> { + Self::all() + .values() + .find(|target| target.triple == triple || target.alias == Some(triple)) + } + fn min_xcode_version_satisfied(&self) -> Result<(), VersionCheckError> { self.min_xcode_version .map(|(min_version, msg)| { @@ -247,10 +302,10 @@ impl<'a> Target<'a> { metadata: &'a Metadata, subcommand: &'a str, ) -> Result, VersionCheckError> { - let metadata = if self.is_macos() { - metadata.macos() - } else { - metadata.ios() + let metadata = match self.get_platform() { + TargetPlatform::MacOS => metadata.macos(), + TargetPlatform::iOS => metadata.ios(), + TargetPlatform::VisionOS => metadata.visionos(), }; self.min_xcode_version_satisfied().map(|()| { CargoCommand::new(subcommand)