apps/ios/fastlane/SETUP.md
Install:
brew install fastlane
Create an App Store Connect API key:
.p8, note the Issuer ID and Key IDRecommended (macOS): store the private key in Keychain and write non-secret vars:
scripts/ios-app-store-connect-keychain-setup.sh \
--key-path /absolute/path/to/AuthKey_XXXXXXXXXX.p8 \
--issuer-id YOUR_ISSUER_ID \
--write-env
This writes these auth variables in apps/ios/fastlane/.env:
APP_STORE_CONNECT_KEY_ID=YOUR_KEY_ID
APP_STORE_CONNECT_ISSUER_ID=YOUR_ISSUER_ID
APP_STORE_CONNECT_KEYCHAIN_SERVICE=openclaw-app-store-connect-key
APP_STORE_CONNECT_KEYCHAIN_ACCOUNT=YOUR_MAC_USERNAME
Important: apps/ios/fastlane/.env is only for Fastlane/App Store Connect auth and optional release-archive settings. It does not configure gateway-side direct APNs push delivery for local iOS builds.
Optional app targeting variables (helpful if Fastlane cannot auto-resolve app by bundle):
APP_STORE_CONNECT_APP_IDENTIFIER=ai.openclawfoundation.app
# or
APP_STORE_CONNECT_APP_ID=YOUR_APP_STORE_CONNECT_APP_ID
File-based fallback (CI/non-macOS):
APP_STORE_CONNECT_KEY_ID=YOUR_KEY_ID
APP_STORE_CONNECT_ISSUER_ID=YOUR_ISSUER_ID
APP_STORE_CONNECT_KEY_PATH=/absolute/path/to/AuthKey_XXXXXXXXXX.p8
Code signing variable (optional in .env):
IOS_DEVELOPMENT_TEAM=YOUR_TEAM_ID
Tip: run scripts/ios-team-id.sh --require-canonical from repo root to verify the canonical OpenClaw iOS team (FWJYW4S8P8) is available locally. Fastlane uses the same canonical-only path when IOS_DEVELOPMENT_TEAM is missing, and rejects non-canonical teams for release archives.
App Store release signing is manual and profile-pinned. The canonical manifest is apps/ios/Config/AppStoreSigning.json, and Fastlane match owns the encrypted signing repo and branch named there.
One-time or rotation setup:
pnpm ios:release:signing:plan
pnpm ios:release:signing:check
pnpm ios:release:signing:setup
signing:setup uses Fastlane produce and modify_services to create Developer Portal bundle IDs and enable required services before running match. The main app and share extension also require the shared App Group from apps/ios/Config/AppStoreSigning.json; associate that group with both bundle IDs in the Apple Developer Portal before regenerating profiles. If Fastlane does not already have a valid Apple Developer Portal session, run fastlane spaceauth for a release-owner Apple ID and export the resulting FASTLANE_SESSION.
Shared encrypted signing storage:
MATCH_PASSWORD=... pnpm ios:release:signing:sync:push
MATCH_PASSWORD=... pnpm ios:release:signing:sync:pull
The signing repo is private and encrypted. Store MATCH_PASSWORD in the release-owner vault, not in this product repo. sync:pull uses Fastlane match to decrypt, install profiles, and import the distribution signing identity into the local Keychain.
For local/manual iOS builds that stay on direct APNs, configure the gateway host separately with OPENCLAW_APNS_TEAM_ID, OPENCLAW_APNS_KEY_ID, and either OPENCLAW_APNS_PRIVATE_KEY_P8 or OPENCLAW_APNS_PRIVATE_KEY_PATH. Those gateway runtime env vars are separate from Fastlane's .env.
Validate auth:
cd apps/ios
fastlane ios auth_check
App Store Connect API auth is required when:
If you pass --build-number to pnpm ios:release:archive, the local archive path does not need App Store Connect API auth.
Archive locally without upload:
pnpm ios:release:archive
Generate deterministic App Store screenshots:
pnpm ios:screenshots
The screenshot lane runs the app with --openclaw-screenshot-mode, which enters the built-in connected screenshot fixture instead of pairing with a live gateway. By default it captures the tab set on iPhone 16 Pro Max and iPad Pro 13-inch (M4); override devices with a comma-separated OPENCLAW_SNAPSHOT_DEVICES value when the requested simulators exist locally.
Upload to App Store Connect:
pnpm ios:release:upload
Direct Fastlane entry point:
cd apps/ios
fastlane ios release_upload
Maintainer recovery path for a fresh clone on the same Mac:
apps/ios/fastlane/.env so it contains the non-secret variables:APP_STORE_CONNECT_KEY_ID=YOUR_KEY_ID
APP_STORE_CONNECT_ISSUER_ID=YOUR_ISSUER_ID
APP_STORE_CONNECT_KEYCHAIN_SERVICE=openclaw-app-store-connect-key
APP_STORE_CONNECT_KEYCHAIN_ACCOUNT=YOUR_MAC_USERNAME
cd apps/ios
fastlane ios auth_check
pnpm ios:version:pin -- --from-gateway
export OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com
pnpm ios:release:upload
Quick verification after upload:
apps/ios/build/app-store/OpenClaw-<version>.ipa existsUploaded iOS App Store build: version=<version> short=<short> build=<build>Versioning rules:
apps/ios/version.json is the pinned iOS release version sourceapps/ios/CHANGELOG.md is the iOS-only changelog and release-note sourceYYYY.M.Dpnpm ios:version:pin -- --from-gateway promotes the current root gateway version into the pinned iOS release versionpackage.json.version alone does not change the iOS app versionCFBundleShortVersionString to the pinned iOS version, for example 2026.4.10CFBundleVersion as the next integer App Store Connect build number for that short versionpnpm ios:version:sync after changing apps/ios/version.json or apps/ios/CHANGELOG.mdpnpm ios:version:check validates that checked-in iOS version artifacts are in syncapps/ios/OpenClaw.xcodeproj from apps/ios/project.yml before archivingapps/ios/Config/AppStoreSigning.json and leaves local development signing overrides untouchedpnpm ios:release:upload generates and uploads screenshots and release notes before archiving, then uploads the IPA without submitting it for App Reviewapps/ios/VERSIONING.md for the detailed workflow