Skip to content

madsmtm/cargo-apple-runner

Cargo runner for Apple targets

Latest version License Documentation CI

Easily bundle, sign and launch binaries on Apple targets, including on the simulator and on real devices.

Usage

Install with:

cargo install cargo-apple-runner

And add the following to your project's .cargo/config.toml:

[target.'cfg(target_vendor = "apple")']
runner = "cargo-apple-runner"

Now you can test and run your (GUI) applications on the iOS simulator with:

cargo test --target aarch64-apple-ios-sim --target aarch64-apple-visionos-sim
cargo run --target aarch64-apple-ios-sim
# etc.

Or on Mac Catalyst with:

cargo run --example my_example --target aarch64-apple-ios-macabi

Supported platforms and requirements

Host: Requires at least macOS 10.12, same as rustc.

Targets: macOS, Mac Catalyst, iOS, tvOS, watchOS and visionOS.

Simulators: Uses xcrun simctl, only tested on Xcode 9.2 and above.

Devices: Yet unsupported, will use devicectl (see #1) and fall back to ios-deploy (see #2) on older Xcode.

Bundling

cargo-apple-runner will inspect your binary, and guess whether it needs to bundle it based on a few factors:

  • Whether your binary links AppKit, UIKit, WatchKit and similar system GUI frameworks.
  • TODO: Maybe something more?
  • TODO: Allow overriding this somehow?

Note that this might mean that for documentation tests to be runnable in parallel with cargo nextest, you might need to use the standalone_crate attribute on GUI tests to avoid these making your other doc tests need to be launched as well.

Custom Info.plist

Most real-world applications will want to modify the data in the application's Info.plist, you can use the embed_plist crate to do so:

embed_plist::embed_plist!("Info.plist");

If this is not done, cargo-apple-runner will generate a reasonable Info.plist for you.

Signing

cargo-apple-runner will sign your application with whatever signing identity is passed in the CODE_SIGN_IDENTITY environment variable. If not set, it will default to "ad-hoc" signing.

Custom entitlements

In some cases, you might need to request different entitlements for your application.

You can use the embed_entitlements crate to do so:

embed_entitlements::embed_entitlements!("my_app.entitlements");

Note that when building for a real (non-simulator) device, you will need to configure a provisioning profile with those entitlements allowed. On macOS, certain entitlements are allowed by default, see this tech note.

As a small optimization when using entitlements, you can consider adding the following to .cargo/config.toml to reduce link-time (since signing will be done by the runner):

[target.'cfg(all(target_vendor = "apple", not(target_env = "sim")))']
# Signing is done by `cargo-apple-runner`.
rustflags = ["-Clink-arg=-Wl,-no_adhoc_codesign"]

Launching

Similar to when bundling, cargo-apple-runner will also guess whether it needs to launch your binary, or whether it can simply spawn it.

Spawning is generally more efficient, since it can be done in parallel, while launching must be serialized (as only a single application can be the frontmost application).

Usage in CI

Example GitHub Actions workflow that runs tests on macOS, Mac Catalyst, the iOS simulator, the tvOS simulator and the visionOS simulator.

name: CI

permissions:
  contents: read

on:
  pull_request:
  push:
    branches:
    - main

jobs:
  test:
    runs-on: macos-latest

    strategy:
      matrix:
        include:
        - target: aarch64-apple-darwin
        - target: aarch64-apple-ios-macabi
        - target: aarch64-apple-ios-sim
          simulator: "iPhone 17"
        - target: aarch64-apple-tvos-sim
          simulator: "Apple TV"
        - target: aarch64-apple-visionos-sim
          simulator: "Apple Vision Pro"
        - target: aarch64-apple-watchos-sim
          simulator: "Apple Watch SE 3 (40mm)"

    env:
      # Configure the job to use `cargo-apple-runner` when launching our binaries.
      # (Alternatively, you could commit the `.cargo/config.toml` above).
      CARGO_TARGET_AARCH64_APPLE_DARWIN_RUNNER: cargo-apple-runner
      CARGO_TARGET_AARCH64_APPLE_IOS_MACABI_RUNNER: cargo-apple-runner
      CARGO_TARGET_AARCH64_APPLE_IOS_SIM_RUNNER: cargo-apple-runner
      CARGO_TARGET_AARCH64_APPLE_TVOS_SIM_RUNNER: cargo-apple-runner
      CARGO_TARGET_AARCH64_APPLE_VISIONOS_SIM_RUNNER: cargo-apple-runner
      CARGO_TARGET_AARCH64_APPLE_WATCHOS_SIM_RUNNER: cargo-apple-runner
      CARGO_TARGET_AARCH64_APPLE_WATCHOS_SIM_RUNNER: cargo-apple-runner
      # Make `--target` default to the target from the matrix.
      CARGO_BUILD_TARGET: ${{ matrix.target }}

    steps:
    - uses: taiki-e/checkout-action@v1

    - name: Install `cargo-apple-runner`
      uses: taiki-e/install-action@cargo-apple-runner

    - name: Install Rustup target
      run: rustup target add ${{ matrix.target }}

    - uses: Swatinem/rust-cache@v2

    # You can find names of existing simulator devices at:
    # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md#installed-simulators
    - name: Start simulator
      if: ${{ matrix.simulator }}
      run: xcrun simctl boot ${{ matrix.simulator }}

    - name: Build
      run: cargo build

    - name: Test
      run: cargo test

Limitations

This is intended as a development tool only; when deploying on real devices, consider using something else. I can recommend cargo-xcode, this gives the most control and helps with the complex process of notarizing and submitting to the App Store.

Will only supports bundled assets (at least after #5), reading from other directories may fail (we don't copy the entire workspace to the device).

Only a few Cargo environment variables are automatically passed onwards to the simulator, use SIMCTL_CHILD_* to explicitly pass the environment variables you want to pass to the program being run.

License

This project is trio-licensed under the Zlib, Apache-2.0 or MIT license, at your option.

Credits

About

Cargo runner for bundling and launching applications on simulator / on device

Topics

Resources

License

Apache-2.0 and 2 other licenses found

Licenses found

Apache-2.0
LICENSE-APACHE.txt
MIT
LICENSE-MIT.txt
Zlib
LICENSE-ZLIB.txt

Contributing

Stars

Watchers

Forks

Contributors

Languages