apps/ios/README.md
This iOS app is super-alpha and internal-use only. The first public App Store release targets iPhone and connects to an OpenClaw Gateway as a role: node.
pnpmxcodegenpnpm install
./scripts/ios-configure-signing.sh
cd apps/ios
xcodegen generate
open OpenClaw.xcodeproj
OpenClawDebugProduct -> Run)apps/ios/LocalSigning.xcconfig.apps/ios/LocalSigning.xcconfig.example.Shortcut command (same flow + open project):
pnpm ios:open
Prereqs:
pnpmxcodegenfastlaneFWJYW4S8P8)MATCH_PASSWORD)ai.openclawfoundation.appscripts/ios-app-store-connect-keychain-setup.sh when auto-resolving a build number or uploading to App Store ConnectRelease behavior:
ai.openclawfoundation.app* bundle IDs when the OpenClaw team is available, and unique ai.openclawfoundation.app.test.* bundle IDs only for non-canonical fallback teams.ai.openclawfoundation.app* bundle IDs through a temporary generated xcconfig in apps/ios/build/AppStoreRelease.xcconfig.Apple Distribution signing with profile names pinned in apps/ios/Config/AppStoreSigning.json.match signing sync to the repo/branch pinned in apps/ios/Config/AppStoreSigning.json, and release handling.OpenClawPushTransport=relay, OpenClawPushDistribution=official, OpenClawPushAPNsEnvironment=production, and a production aps-environment entitlement.pnpm ios:release:upload generates App Store screenshots and uploads release notes before archiving and uploading the IPA.pnpm ios:release remains a compatibility alias for pnpm ios:release:upload; prefer the explicit upload command in new release docs and automation.apps/ios/.local-signing.xcconfig or apps/ios/LocalSigning.xcconfig.apps/ios/version.json is the pinned iOS release version source.apps/ios/CHANGELOG.md is the iOS-only changelog and release-note source.2026.4.10.CFBundleShortVersionString = 2026.4.10CFBundleVersion = next App Store Connect build number for 2026.4.10apps/ios/VERSIONING.md for the full workflow.Relay behavior for App Store builds:
https://ios-push-relay.openclaw.ai.OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com
This must be a plain https://host[:port][/path] base URL without whitespace, query params, fragments, or xcconfig metacharacters.Signing setup commands:
pnpm ios:release:signing:plan
pnpm ios:release:signing:check
pnpm ios:release:signing:setup
MATCH_PASSWORD=... pnpm ios:release:signing:sync:push
MATCH_PASSWORD=... pnpm ios:release:signing:sync:pull
Release-owner secrets:
apps/ios/fastlane/.env variables.MATCH_PASSWORD.apps/ios/Config/AppStoreSigning.json to be associated with both the app and share-extension bundle IDs before App Store profiles are regenerated.apps/ios/build/ or Keychain and are gitignored.match assets and pushing a fresh encrypted sync state.Prepare the generated release xcconfig/project without archiving:
pnpm ios:release:prepare -- --build-number 7
Archive without upload:
pnpm ios:release:archive
Archive and upload to App Store Connect:
pnpm ios:release:upload
If you need to force a specific build number:
pnpm ios:release:upload -- --build-number 7
Use this when a clone is missing local iOS release setup and you want the shortest path to an App Store Connect upload.
cd apps/ios
fastlane ios auth_check
scripts/ios-app-store-connect-keychain-setup.sh \
--key-path /absolute/path/to/AuthKey_XXXXXXXXXX.p8 \
--issuer-id YOUR_ISSUER_ID \
--write-env
This should create apps/ios/fastlane/.env with non-secret App Store Connect variables while the private key stays in Keychain.
Confirm the App Store Connect app and Apple Developer identifiers/capabilities exist for:
ai.openclawfoundation.appai.openclawfoundation.app.shareai.openclawfoundation.app.activitywidgetai.openclawfoundation.app.watchkitappThe main app and share extension must both be associated with the App Group pinned in apps/ios/Config/AppStoreSigning.json.
Use pnpm ios:release:signing:setup for the initial portal setup, then MATCH_PASSWORD=... pnpm ios:release:signing:sync:push to publish encrypted Fastlane match assets to the shared private repo.
Optional: set a custom official relay URL for the build. If unset, the release flow uses https://ios-push-relay.openclaw.ai.
export OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com
pnpm ios:version:pin -- --from-gateway
pnpm ios:release:upload
Expected behavior:
apps/ios/version.jsonapps/ios/build/AppStoreRelease.xcconfigOpenClawExpected outputs after a successful run:
apps/ios/build/app-store/OpenClaw-<version>.ipaapps/ios/build/app-store/OpenClaw-<version>.app.dSYM.zipUploaded iOS App Store build: version=<version> short=<short> build=<build>If this is a fresh clone on a maintainer machine that already works elsewhere, it is OK to copy the non-secret apps/ios/fastlane/.env from another trusted local clone on the same Mac. The Keychain-backed private key remains machine-local and is not stored in the repo.
apps/ios/version.jsonapps/ios/CHANGELOG.mdapps/ios/Config/Version.xcconfigapps/ios/fastlane/metadata/en-US/release_notes.txtpnpm ios:version
pnpm ios:version:check
pnpm ios:version:sync
pnpm ios:version:pin -- --from-gateway
pnpm ios:version:pin -- --version 2026.4.10
Recommended flow:
apps/ios/version.json pinned to the current train version.apps/ios/CHANGELOG.md, usually under ## Unreleased while iterating.pnpm ios:version:sync after changelog changes.pnpm ios:release:upload.pnpm ios:version:pin -- --from-gateway
apps/ios/CHANGELOG.md for the new release as needed.pnpm ios:version:sync.See apps/ios/VERSIONING.md for the detailed spec.
registerForRemoteNotifications() at launch.apps/ios/Sources/OpenClaw.entitlements derives aps-environment from the active build configuration/signing override.push.apns.register).OpenClawPushTransport=direct, OpenClawPushDistribution=local, and a development aps-environment entitlement.APNs registration failed).OPENCLAW_APNS_TEAM_ID, OPENCLAW_APNS_KEY_ID, and either OPENCLAW_APNS_PRIVATE_KEY_P8 or OPENCLAW_APNS_PRIVATE_KEY_PATH..p8 file is ~/.openclaw/credentials/apns/AuthKey_<KEYID>.p8 with restrictive permissions, then point OPENCLAW_APNS_PRIVATE_KEY_PATH at that file.apps/ios/fastlane/.env only covers App Store Connect / Fastlane auth; it does not provide gateway APNs credentials for local direct-push testing.OpenClawPushAPNsEnvironment=sandbox; Release builds default to production.push.apns.register to the gateway.gateway.identity.get, so another gateway cannot reuse that stored registration.gateway.push.apns.relay.baseUrl in openclaw.json. OPENCLAW_APNS_RELAY_BASE_URL remains a temporary env override only.iOS -> gateway
gateway.identity.get.iOS -> relay
gateway delegation
gateway -> relay
relay -> APNs
This exists to keep the hosted relay limited to genuine OpenClaw official builds and to ensure a gateway can only send pushes for iOS devices that paired with that gateway.
/pair qr or /pair, then /pair approve in Telegram).node.presence.alive beacons that update gateway last-seen metadata when the app moves between foreground and background, without treating suspended sockets as connected.The iOS app is not a Codex Computer Use backend. Computer Use and cua-driver mcp are macOS desktop-control paths; iOS exposes device capabilities as OpenClaw node commands through the gateway. Agents can drive the iPhone canvas, camera, screen, location, voice, and other node capabilities with node.invoke, subject to iOS foreground/background limits.
Use this for automation signals ("I moved", "I arrived", "I left"), not as a keep-awake mechanism.
Test path to include in QA runs:
Always permissionPass criteria:
canvas.*, camera.*, screen.*, and talk.* are blocked when backgrounded.Always location permission.Automatic wake/reconnect hardening:
xcodegen generate)Settings -> Gateway:
/pair approve from Telegram, then reconnectDiscovery Debug LogsSettings -> Gateway -> Discovery Logsai.openclawfoundation.appGatewayDiagAPNs registration failed