* fix(ios): add Photos permission controls * chore(i18n): sync native Photos strings * fix(ios): align Swedish Photos disclosure * test(ios): complete limited Photos UI proof * chore(i18n): refresh native source lines
OpenClaw iOS
OpenClaw iOS is the officially released iPhone app. It connects to an OpenClaw Gateway as a role: node for chat, voice, approvals, sharing, and device-aware automation.
Distribution Status
- Public distribution: App Store.
- App Store Connect uploads use the App Store release Fastlane path.
- Local/manual deploy from source via Xcode remains the default development path for app development.
Support Notes
- UI and onboarding changes ship through normal app releases.
- Some node commands require foreground access because of iOS platform limits.
- Permissions, background behavior, and push delivery are documented below so release and support checks stay explicit.
Exact Xcode Manual Deploy Flow
- Prereqs:
- Xcode 26.x
pnpmxcodegen- Apple Development signing set up in Xcode
- From repo root:
pnpm install
pnpm ios:open
- In Xcode:
- Scheme:
OpenClaw - Destination: connected iPhone (recommended for real behavior)
- Build configuration:
Debug - Run (
Product->Run)
- Scheme:
- If signing fails on a personal team:
- Use unique local bundle IDs via
apps/ios/LocalSigning.xcconfig. - Start from
apps/ios/LocalSigning.xcconfig.example.
- Use unique local bundle IDs via
Generate without opening Xcode:
pnpm ios:gen
App Store Release Flow
Prereqs:
- Xcode 26.x
pnpmxcodegenfastlane- Apple account signed into Xcode for the canonical OpenClaw team (
FWJYW4S8P8) - Fastlane Apple Developer Portal session for the canonical OpenClaw team when creating bundle IDs or enabling services
- Release-owner access to the encrypted signing repo password (
MATCH_PASSWORD) - App Store Connect app already created for
ai.openclawfoundation.app - App Store Connect API key set up in Keychain via
scripts/ios-app-store-connect-keychain-setup.shwhen auto-resolving a build number or uploading to App Store Connect
Release behavior:
- Local development uses the canonical
ai.openclawfoundation.app*bundle IDs when the OpenClaw team is available, and uniqueai.openclawfoundation.app.test.*bundle IDs only for non-canonical fallback teams. - App Store release uses canonical
ai.openclawfoundation.app*bundle IDs through a temporary generated xcconfig inapps/ios/build/AppStoreRelease.xcconfig. - App Store release uses manual
Apple Distributionsigning with profile names pinned inapps/ios/Config/AppStoreSigning.json. - Fastlane owns one-time Developer Portal setup, encrypted
matchsigning sync to the repo/branch pinned inapps/ios/Config/AppStoreSigning.json, and release handling. - App Store release also switches the app to
OpenClawPushMode=appStore, which derives relay transport, official distribution, the canonical production relay, production APNs, production relay profile,appleStrictproof, and the App-Attest-capable entitlement file. pnpm ios:release:uploadgenerates App Store screenshots, uploads release notes, and attachesapps/ios/APP-REVIEW-NOTES.mdas a rendered PDF before archiving and uploading the IPA.- Agent-driven App Store uploads must use
pnpm ios:release:uploadas the only release path. If that command fails, stop and fix the failing screenshot, metadata, archive, validation, or upload step before trying again. - Do not treat
pnpm ios:release:archive,asc builds upload,asc release stage,asc publish appstore, direct Fastlane lanes, or App Store Connect mutation commands as fallback upload paths afterpnpm ios:release:uploadfails. - The release archive is validated before upload by inspecting the exported IPA's signed entitlements, embedded App Store profile, and push mode. The upload fails if the IPA is not an App Store production relay build.
- App Review submission is manual in App Store Connect. The release lane uploads a build, public metadata, and the App Review PDF attachment, but it does not submit for review or upload the App Store Connect
Notesfield. - The release flow does not modify
apps/ios/.local-signing.xcconfigorapps/ios/LocalSigning.xcconfig. - Release uploads require an explicit CalVer version passed with
--version. apps/ios/CHANGELOG.mdis the iOS-only changelog and release-note source.- The release version must use CalVer like
2026.4.10. - That release value becomes:
CFBundleShortVersionString = 2026.4.10CFBundleVersion = next App Store Connect build number for 2026.4.10
- Local defaults derive from root
package.json; App Store uploads use the explicit--versionvalue. - See
apps/ios/VERSIONING.mdfor the full workflow.
Relay behavior for App Store builds:
- App Store release builds use the canonical hosted relay at
https://ios-push-relay.openclaw.ai. - App Store release builds reject custom relay URL overrides. Future self-hosted relay support should use a separate explicit release path, not the public App Store build lane.
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:
- App Store Connect API auth uses Keychain for private key material plus non-secret
apps/ios/fastlane/.envvariables. - The encrypted signing repo password lives outside this repo in the release-owner vault and is exposed locally as
MATCH_PASSWORD. - The share sheet requires the Apple Developer App Group in
apps/ios/Config/AppStoreSigning.jsonto be associated with both the app and share-extension bundle IDs before App Store profiles are regenerated. - Relay registration requires the App Attest capability on the main app ID before App Store profiles are regenerated.
- Apple Distribution private keys, certificates, provisioning profiles, and decrypted signing sync output stay under
apps/ios/build/or Keychain and are gitignored. - Rotating release signing means refreshing Fastlane
matchassets and pushing a fresh encrypted sync state.
Prepare the generated release xcconfig/project without archiving:
pnpm ios:release:prepare -- --version 2026.6.11 --build-number 7
Archive without upload:
pnpm ios:release:archive -- --version 2026.6.11
This command is for local archive validation only. It is not a fallback upload
path after pnpm ios:release:upload fails.
Archive and upload to App Store Connect:
pnpm ios:release:upload -- --version 2026.6.11
If you need to force a specific build number:
pnpm ios:release:upload -- --version 2026.6.11 --build-number 7
Maintainer Quick Release Checklist
Use this when a clone is missing local iOS release setup and you want the shortest path to an App Store Connect upload.
- Confirm Fastlane auth is set up:
cd apps/ios
fastlane ios auth_check
- If auth is missing, bootstrap it once on this Mac:
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.watchkitapp
The main app and share extension must both be associated with the App Group pinned in
apps/ios/Config/AppStoreSigning.json. The main app must also have App Attest enabled.Use
pnpm ios:release:signing:setupfor the initial portal setup, thenMATCH_PASSWORD=... pnpm ios:release:signing:sync:pushto publish encrypted Fastlane match assets to the shared private repo. -
If you are starting a brand-new production release train, add or update the matching iOS changelog section and validate the release notes:
pnpm ios:version:check -- --version 2026.6.11
- Upload the build with explicit release intent:
pnpm ios:release:upload -- --version 2026.6.11 --build-number 3
-
If
pnpm ios:release:uploadfails, stop at that failure. Do not archive and upload the IPA through another command. Fix the failing release-lane step, then rerunpnpm ios:release:upload. -
Expected behavior:
- Fastlane reads the explicit
--versionvalue - validates iOS versioning inputs for that version
- resolves the next App Store Connect build number for that short version
- generates deterministic App Store screenshots
- uploads release notes, screenshots, and the App Review PDF attachment to the editable App Store version
- generates
apps/ios/build/AppStoreRelease.xcconfig - archives
OpenClaw - validates the exported IPA's push mode, signed entitlements, and embedded App Store profile
- uploads the IPA to App Store Connect for processing and App Review use
- leaves App Review submission for a maintainer to complete manually
- Fastlane reads the explicit
-
Expected outputs after a successful run:
apps/ios/build/app-store/OpenClaw-<version>.ipaapps/ios/build/app-store/OpenClaw-<version>.app.dSYM.zip- Fastlane log line like
Uploaded 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/.envfrom another trusted local clone on the same Mac. The Keychain-backed private key remains machine-local and is not stored in the repo.
iOS Versioning Workflow
- Release upload version: explicit
--version - Local default version: root
package.json - iOS-only changelog:
apps/ios/CHANGELOG.md - Generated local artifacts:
apps/ios/build/Version.xcconfigapps/ios/SwiftSources.input.xcfilelist- temporary Fastlane metadata containing release notes rendered from
apps/ios/CHANGELOG.md
- Useful commands:
pnpm ios:version
pnpm ios:version:check
pnpm ios:version -- --version 2026.6.11
pnpm ios:filelist:gen
Recommended flow:
App Store Connect iteration on an existing train
- Choose the App Store train explicitly, for example
2026.6.11. - Update
apps/ios/CHANGELOG.md, usually under## Unreleasedwhile iterating. - Run
pnpm ios:version:check -- --version 2026.6.11after changelog changes. - Upload additional App Store Connect builds with
pnpm ios:release:upload -- --version 2026.6.11. - Let Fastlane bump only the numeric build number.
Starting the next production release train
- Confirm the target gateway version in root
package.json. - Update
apps/ios/CHANGELOG.mdfor the new release as needed. - Run
pnpm ios:version:check -- --version <release-version>. - Submit the first App Store Connect build with
pnpm ios:release:upload -- --version <release-version>. - Keep iterating on that same explicit version until the release candidate is ready.
See apps/ios/VERSIONING.md for the detailed spec.
APNs Expectations For Local/Manual Builds
- The app calls
registerForRemoteNotifications()at launch. apps/ios/Sources/OpenClaw.entitlementsderivesaps-environmentfrom the active build configuration/signing override.- App Attest relay builds use
apps/ios/Sources/OpenClawAppAttest.entitlements; local/direct builds do not require App Attest provisioning. - APNs token registration to gateway happens only after gateway connection (
push.apns.register). - Local/manual Debug builds default to
OpenClawPushMode=localSandbox, direct APNs registration, and a developmentaps-environmententitlement. Local/manual Release builds default toOpenClawPushMode=localProductionand direct production APNs registration. - Your selected team/profile must support Push Notifications for the app bundle ID you are signing.
- If push capability or provisioning is wrong, APNs registration fails at runtime (check Xcode logs for
APNs registration failed). - The gateway host also needs direct APNs auth configured separately with
OPENCLAW_APNS_TEAM_ID,OPENCLAW_APNS_KEY_ID, and eitherOPENCLAW_APNS_PRIVATE_KEY_P8orOPENCLAW_APNS_PRIVATE_KEY_PATH. - Recommended gateway-host storage for the APNs
.p8file is~/.openclaw/credentials/apns/AuthKey_<KEYID>.p8with restrictive permissions, then pointOPENCLAW_APNS_PRIVATE_KEY_PATHat that file. apps/ios/fastlane/.envonly covers App Store Connect / Fastlane auth; it does not provide gateway APNs credentials for local direct-push testing.- Debug builds default to sandbox APNs through
OpenClawPushMode=localSandbox; Release builds default to production APNs throughOpenClawPushMode=localProduction.
APNs Expectations For Official Builds
- Official App Store builds register with the external push relay before they publish
push.apns.registerto the gateway. - The gateway registration for relay mode contains an opaque relay handle, a registration-scoped send grant, relay origin metadata, and installation metadata instead of the raw APNs token.
- The relay registration is bound to the gateway identity fetched from
gateway.identity.get, so another gateway cannot reuse that stored registration. - The app persists the relay handle metadata locally so reconnects can republish the gateway registration without re-registering on every connect.
- If the relay base URL changes in a later build, the app refreshes the relay registration instead of reusing the old relay origin.
- App Store release mode uses the internal
productionrelay profile, production APNs, App Attest, and a StoreKit app transaction JWS during registration. - Gateway-side relay sending is configured through
gateway.push.apns.relay.baseUrlinopenclaw.json.OPENCLAW_APNS_RELAY_BASE_URLremains a temporary env override only.
Official Build Relay Trust Model
iOS -> gateway- The app must pair with the gateway and establish both node and operator sessions.
- The operator session is used to fetch
gateway.identity.get.
iOS -> relay- The app registers with the relay over HTTPS using App Attest plus a StoreKit app transaction JWS.
- The relay requires the official App Store distribution path, which is why local Xcode/dev installs cannot use the hosted relay.
gateway delegation- The app includes the gateway identity in relay registration.
- The relay returns a relay handle and registration-scoped send grant delegated to that gateway.
gateway -> relay- The gateway signs relay send requests with its own device identity.
- The relay verifies both the delegated send grant and the gateway signature before it sends to APNs.
relay -> APNs- Production APNs credentials and raw official-build APNs tokens stay in the relay deployment, not on the gateway.
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.
What Works Now (Concrete)
- Pairing via QR or setup code flow (
/pair qror/pair, then/pair approvein Telegram). - Gateway connection via discovery or manual host/port with TLS fingerprint trust prompt.
- Chat + Talk surfaces through the operator gateway session.
- iOS node commands in foreground: camera snap/clip, canvas present/navigate/eval/snapshot, screen record, location, contacts, calendar, reminders, photos, motion, local notifications.
- Authenticated background
node.presence.alivebeacons that update gateway last-seen metadata when the app moves between foreground and background, without treating suspended sockets as connected. - Share extension deep-link forwarding into the connected gateway session.
Computer Use Relationship
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.
Location Automation Use Case (Testing)
Use this for automation signals ("I moved", "I arrived", "I left"), not as a keep-awake mechanism.
- Product intent:
- movement-aware automations driven by iOS location events
- example: arrival/exit geofence, significant movement, visit detection
- Non-goal:
- continuous GPS polling just to keep the app alive
Test path to include in QA runs:
- Enable location permission in app:
- set
Alwayspermission - verify background location capability is enabled in the build profile
- set
- Background the app and trigger movement:
- walk/drive enough for a significant location update, or cross a configured geofence
- Validate gateway side effects:
- node reconnect/wake if needed
- expected location/movement event arrives at gateway
- automation trigger executes once (no duplicate storm)
- Validate resource impact:
- no sustained high thermal state
- no excessive background battery drain over a short observation window
Pass criteria:
- movement events are delivered reliably enough for automation UX
- no location-driven reconnect spam loops
- app remains stable after repeated background/foreground transitions
Known Issues / Limitations / Problems
- Foreground-first: iOS can suspend sockets in background; reconnect recovery is still being tuned.
- Background command limits are strict:
canvas.*,camera.*,screen.*, andtalk.*are blocked when backgrounded. - Background location requires
Alwayslocation permission. - Pairing/auth errors intentionally pause reconnect loops until a human fixes auth/pairing state.
- Voice Wake and Talk contend for the same microphone; Talk suppresses wake capture while active.
- APNs reliability depends on local signing/provisioning/topic alignment.
- Expect rough UX edges and occasional reconnect churn during active development.
Current In-Progress Workstream
Automatic wake/reconnect hardening:
- improve wake/resume behavior across scene transitions
- reduce dead-socket states after background -> foreground
- tighten node/operator session reconnect coordination
- reduce manual recovery steps after transient network failures
Debugging Checklist
- Confirm build/signing baseline:
- regenerate project (
xcodegen generate) - verify selected team + bundle IDs
- regenerate project (
- In app
Settings -> Gateway:- confirm status text, server, and remote address
- verify whether status shows pairing/auth gating
- If pairing is required:
- run
/pair approvefrom Telegram, then reconnect
- run
- If discovery is flaky:
- enable
Discovery Debug Logs - inspect
Settings -> Gateway -> Discovery Logs
- enable
- If network path is unclear:
- switch to manual host/port + TLS in Gateway Advanced settings
- In Xcode console, filter for subsystem/category signals:
ai.openclawfoundation.appGatewayDiagAPNs registration failed
- Validate background expectations:
- repro in foreground first
- then test background transitions and confirm reconnect on return