iOS
The desktop application of a Récit site also builds for iOS: the
same app: section, the same shell, an .ipa at the end. It needs a Mac.
Prerequisites
On a Mac:
- Xcode, complete (from the App Store), then
xcode-select --install; - CocoaPods (
brew install cocoapods), which Tauri's prerequisites still name; - Rust stable with the iOS targets:
rustup target add aarch64-apple-ios aarch64-apple-ios-sim(addx86_64-apple-iosfor the simulator of an Intel Mac); - an Apple Developer team, to sign anything that leaves the simulator;
@recit/appinstalled in the site, as for the desktop.
Elsewhere, recit app ios … stops with these prerequisites and runs nothing.
Section
| Key | Default | Meaning |
|---|---|---|
ios.developmentTeam | none, or APPLE_DEVELOPMENT_TEAM | the team that signs the application |
identifier | see the app page | becomes the bundle identifier, final |
icon | metadata.favicon | the AppIcon set is derived from it |
version | the site's package.json | the version Xcode shows; the build number is a flag |
The generated project ships a default launch screen; the application keeps it. The team goes into
the Xcode project when it is generated (recit app ios init) and into the signature of every build:
set it before the first init, or regenerate the project after.
Commands
| Command | Effect |
|---|---|
recit app ios init | generates the Xcode project once, in .recit/app/gen/apple/ (ignored by git); -- --ci skips the prompts |
recit app ios dev | runs the application in the simulator, or on a device, against recit-site dev, with hot reload |
recit app ios build -- --export-method debugging | a signed .ipa for the devices of the team, in .recit/app/gen/apple/build/ |
recit app ios build -- --export-method app-store-connect | a signed .ipa for TestFlight and the App Store; release-testing is the ad hoc export for registered devices |
recit app build --target ios | the site build followed by tauri ios build with Tauri's default export: pass --export-method to choose one |
The arguments after -- go to tauri ios … as they are, --build-number <n> included. The export
methods are the names of Xcode 15; @recit/app also accepts the old ones (app-store, ad-hoc,
development) and translates them. When a tool is missing, the command says which one, and how to
install it.
Signing
- A team.
ios.developmentTeamin theapp:section, or theAPPLE_DEVELOPMENT_TEAMvariable that Tauri reads itself; the config wins. Without a team, only the simulator builds. - A certificate and a profile. An Apple Development or Distribution certificate in the keychain and a provisioning profile that names the bundle identifier. On a Mac, Xcode manages both with automatic signing; in CI they come from secrets (below).
- An App Store Connect API key (issuer, key id,
.p8file) for theapp-store-connectexport and the TestFlight upload:APPLE_API_ISSUER,APPLE_API_KEY,APPLE_API_KEY_PATH.
The identifier is final once the application exists in App Store Connect.
In CI
The workflow .github/workflows/app-ios.yaml runs by hand on a macos-15 runner, like the desktop
one:
Bash
It installs Rust with the iOS targets, builds the site, generates the Xcode project, then:
- without the signing secrets, compiles the whole application for the simulator, unsigned
(
xcodebuild build … CODE_SIGNING_ALLOWED=NO): the project and the configuration are proven, no.ipaleaves the runner; - with them, imports the certificate and the profile into a temporary keychain, runs
recit app ios build -- --export-method <input> --build-number <run number>and uploads the.ipaas an artifact; with the inputuploadand theapp-store-connectexport, it also sends the.ipato TestFlight withxcrun altool --upload-app.
| Secret | Content |
|---|---|
APPLE_DEVELOPMENT_TEAM | the team id (ten characters) |
IOS_CERTIFICATE | the signing certificate, a .p12 in base64 |
IOS_CERTIFICATE_PASSWORD | its password |
IOS_MOBILE_PROVISION | the provisioning profile, a .mobileprovision in base64 |
APPLE_API_ISSUER | the issuer id of the App Store Connect API key |
APPLE_API_KEY | the key id |
APPLE_API_KEY_P8 | the content of the .p8 file, written to APPLE_API_KEY_PATH |
The three first ones enable the signed build; the three last ones the app-store-connect export and
the upload. The keychain is deleted at the end of the job.
TestFlight and the App Store
- Create the application in App Store Connect with the bundle identifier of
app:. - Export with
app-store-connectand upload: the workflow withupload, or Transporter by hand with the.ipaartifact. - The build appears in TestFlight after Apple's processing; the store review needs the usual metadata, screenshots and a privacy answer (the application makes no network request of its own: the site is embedded).
Not verified yet
What the first run on a Mac must look at, and where to fix it:
- the Xcode project's script phase finds the Tauri CLI: the workflow puts the one of
@recit/apponPATH; on a Mac, runrecit app ios initfrom the site so the CLI is resolved from there; - the scheme name ends with
_iOS, as Tauri's template names it; the simulator step looks it up; - a simulator build without signing (
CODE_SIGNING_ALLOWED=NO) goes through the script phase; - the
.ipalands in.recit/app/gen/apple/build/<arch>/, where the artifact and the upload look for it; xcrun altool --upload-appstill accepts uploads with an API key (Apple is retiringaltool; Transporter is the fallback).
Limits
- macOS only:
recit app ios …lists the prerequisites and stops elsewhere. - Hot reload on a device needs the dev server reachable on the local network:
devUrlislocalhost, see the note on Android, which has the same question. - No deep link and no updater on iOS: the store updates the application.
- Everything else is the desktop application: the same offline bundle, the same limits.