mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
feat: configure ios app store release signing
This commit is contained in:
@@ -58,11 +58,11 @@ Maintenance update for the current OpenClaw release.
|
||||
|
||||
## 2026.5.12 - 2026-05-12
|
||||
|
||||
Maintenance update for the current OpenClaw beta release.
|
||||
Maintenance update for the current OpenClaw release.
|
||||
|
||||
## 2026.5.10 - 2026-05-10
|
||||
|
||||
Maintenance update for the current OpenClaw beta release.
|
||||
Maintenance update for the current OpenClaw release.
|
||||
|
||||
- Gateway connections now recover after a trusted Gateway certificate changes by refreshing the stored certificate pin during reconnect.
|
||||
|
||||
@@ -128,7 +128,7 @@ Maintenance update for the current OpenClaw release.
|
||||
|
||||
## 2026.4.19 - 2026-04-19
|
||||
|
||||
Maintenance update for the current OpenClaw beta release.
|
||||
Maintenance update for the current OpenClaw release.
|
||||
|
||||
## 2026.4.18 - 2026-04-18
|
||||
|
||||
@@ -136,11 +136,11 @@ Maintenance update for the current OpenClaw release.
|
||||
|
||||
## 2026.4.15 - 2026-04-15
|
||||
|
||||
Maintenance update for the current OpenClaw beta release.
|
||||
Maintenance update for the current OpenClaw release.
|
||||
|
||||
## 2026.4.14 - 2026-04-14
|
||||
|
||||
Maintenance update for the current OpenClaw beta release.
|
||||
Maintenance update for the current OpenClaw release.
|
||||
|
||||
## 2026.4.12 - 2026-04-12
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ OPENCLAW_IOS_DEFAULT_TEAM = FWJYW4S8P8
|
||||
OPENCLAW_IOS_SELECTED_TEAM = $(OPENCLAW_IOS_DEFAULT_TEAM)
|
||||
OPENCLAW_DEVELOPMENT_TEAM = $(OPENCLAW_IOS_SELECTED_TEAM)
|
||||
OPENCLAW_CODE_SIGN_STYLE = Automatic
|
||||
OPENCLAW_CODE_SIGN_IDENTITY = Apple Development
|
||||
OPENCLAW_APP_BUNDLE_ID = ai.openclawfoundation.app
|
||||
OPENCLAW_WATCH_APP_BUNDLE_ID = ai.openclawfoundation.app.watchkitapp
|
||||
OPENCLAW_WATCH_EXTENSION_BUNDLE_ID = ai.openclawfoundation.app.watchkitapp.extension
|
||||
@@ -18,7 +19,7 @@ OPENCLAW_WATCH_EXTENSION_PROFILE =
|
||||
#include? "../LocalSigning.xcconfig"
|
||||
|
||||
CODE_SIGN_STYLE = $(OPENCLAW_CODE_SIGN_STYLE)
|
||||
CODE_SIGN_IDENTITY = Apple Development
|
||||
CODE_SIGN_IDENTITY = $(OPENCLAW_CODE_SIGN_IDENTITY)
|
||||
DEVELOPMENT_TEAM = $(OPENCLAW_DEVELOPMENT_TEAM)
|
||||
|
||||
// Let Xcode manage provisioning for the selected local team unless a local override pins one.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// This file is only an example and should stay committed.
|
||||
|
||||
OPENCLAW_CODE_SIGN_STYLE = Automatic
|
||||
OPENCLAW_CODE_SIGN_IDENTITY = Apple Development
|
||||
OPENCLAW_DEVELOPMENT_TEAM = YOUR_TEAM_ID
|
||||
|
||||
OPENCLAW_APP_BUNDLE_ID = ai.openclawfoundation.app
|
||||
|
||||
+48
-32
@@ -4,8 +4,8 @@ This iOS app is super-alpha and internal-use only. The first public App Store re
|
||||
|
||||
## Distribution Status
|
||||
|
||||
- Public distribution: not available.
|
||||
- Internal beta distribution: local archive + TestFlight upload via Fastlane.
|
||||
- Public distribution: App Store Connect app created; production signing is configured through the App Store release Fastlane path.
|
||||
- Internal TestFlight distribution: uses the same App Store distribution archive uploaded to App Store Connect.
|
||||
- Local/manual deploy from source via Xcode remains the default development path.
|
||||
|
||||
## Super-Alpha Disclaimer
|
||||
@@ -47,7 +47,7 @@ Shortcut command (same flow + open project):
|
||||
pnpm ios:open
|
||||
```
|
||||
|
||||
## Local Beta Release Flow
|
||||
## App Store Release Flow
|
||||
|
||||
Prereqs:
|
||||
|
||||
@@ -55,52 +55,61 @@ Prereqs:
|
||||
- `pnpm`
|
||||
- `xcodegen`
|
||||
- `fastlane`
|
||||
- Apple account signed into Xcode for automatic signing/provisioning
|
||||
- App Store Connect API key set up in Keychain via `scripts/ios-asc-keychain-setup.sh` when auto-resolving a beta build number or uploading to TestFlight
|
||||
- Apple account signed into Xcode for the canonical OpenClaw team (`FWJYW4S8P8`)
|
||||
- Xcode account permissions to create Apple Distribution certificates, App IDs, and App Store provisioning profiles
|
||||
- App Store Connect app already created for `ai.openclawfoundation.app`
|
||||
- App Store Connect API key set up in Keychain via `scripts/ios-asc-keychain-setup.sh` when 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 unique `ai.openclawfoundation.app.test.*` bundle IDs only for non-canonical fallback teams.
|
||||
- Beta release uses canonical `ai.openclawfoundation.app*` bundle IDs through a temporary generated xcconfig in `apps/ios/build/BetaRelease.xcconfig`.
|
||||
- Beta release also switches the app to `OpenClawPushTransport=relay`, `OpenClawPushDistribution=official`, and `OpenClawPushAPNsEnvironment=production`.
|
||||
- App Store release uses canonical `ai.openclawfoundation.app*` bundle IDs through a temporary generated xcconfig in `apps/ios/build/AppStoreRelease.xcconfig`.
|
||||
- App Store release uses automatic signing with `Apple Distribution` and `-allowProvisioningUpdates`, so Xcode can create missing distribution certificates/profiles for the canonical team when the signed-in account has permission.
|
||||
- App Store release also switches the app to `OpenClawPushTransport=relay`, `OpenClawPushDistribution=official`, `OpenClawPushAPNsEnvironment=production`, and a production `aps-environment` entitlement.
|
||||
- App Store screenshots use `pnpm ios:screenshots`, which drives Fastlane Snapshot through a deterministic connected screenshot fixture instead of a live gateway.
|
||||
- The beta flow does not modify `apps/ios/.local-signing.xcconfig` or `apps/ios/LocalSigning.xcconfig`.
|
||||
- The release flow does not modify `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.
|
||||
- The pinned iOS version must use CalVer like `2026.4.10`.
|
||||
- That pinned value becomes:
|
||||
- `CFBundleShortVersionString = 2026.4.10`
|
||||
- `CFBundleVersion = next TestFlight build number for 2026.4.10`
|
||||
- `CFBundleVersion = next App Store Connect build number for 2026.4.10`
|
||||
- Changing the root gateway version does not change the iOS app version until you explicitly pin from the gateway.
|
||||
- See `apps/ios/VERSIONING.md` for the full workflow.
|
||||
|
||||
Relay behavior for beta builds:
|
||||
Relay behavior for App Store builds:
|
||||
|
||||
- Beta builds default to `https://ios-push-relay.openclaw.ai`.
|
||||
- Optional custom relay override: `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.
|
||||
|
||||
Prepare the generated release xcconfig/project without archiving:
|
||||
|
||||
```bash
|
||||
pnpm ios:release:prepare -- --build-number 7
|
||||
```
|
||||
|
||||
Archive without upload:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta:archive
|
||||
pnpm ios:release:archive
|
||||
```
|
||||
|
||||
Archive and upload to TestFlight:
|
||||
Archive and upload to App Store Connect:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta
|
||||
pnpm ios:release
|
||||
```
|
||||
|
||||
If you need to force a specific build number:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta -- --build-number 7
|
||||
pnpm ios:release -- --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 a TestFlight upload.
|
||||
Use this when a clone is missing local iOS release setup and you want the shortest path to an App Store Connect upload.
|
||||
|
||||
1. Confirm Fastlane auth is set up:
|
||||
|
||||
@@ -120,38 +129,45 @@ scripts/ios-asc-keychain-setup.sh \
|
||||
|
||||
This should create `apps/ios/fastlane/.env` with the non-secret ASC variables while the private key stays in Keychain.
|
||||
|
||||
3. Optional: set a custom official/TestFlight relay URL for the build. If unset, the beta flow uses `https://ios-push-relay.openclaw.ai`.
|
||||
3. Confirm the App Store Connect app and Apple Developer identifiers/capabilities exist for:
|
||||
- `ai.openclawfoundation.app`
|
||||
- `ai.openclawfoundation.app.share`
|
||||
- `ai.openclawfoundation.app.activitywidget`
|
||||
- `ai.openclawfoundation.app.watchkitapp`
|
||||
- `ai.openclawfoundation.app.watchkitapp.extension`
|
||||
|
||||
4. Optional: set a custom official relay URL for the build. If unset, the release flow uses `https://ios-push-relay.openclaw.ai`.
|
||||
|
||||
```bash
|
||||
export OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com
|
||||
```
|
||||
|
||||
4. If you are starting a brand-new production release train, pin iOS to the current gateway version first:
|
||||
5. If you are starting a brand-new production release train, pin iOS to the current gateway version first:
|
||||
|
||||
```bash
|
||||
pnpm ios:version:pin -- --from-gateway
|
||||
```
|
||||
|
||||
5. Upload the beta:
|
||||
6. Upload the build:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta
|
||||
pnpm ios:release
|
||||
```
|
||||
|
||||
6. Expected behavior:
|
||||
7. Expected behavior:
|
||||
- Fastlane reads `apps/ios/version.json`
|
||||
- verifies synced iOS versioning artifacts
|
||||
- resolves the next TestFlight build number for that short version
|
||||
- generates `apps/ios/build/BetaRelease.xcconfig`
|
||||
- resolves the next App Store Connect build number for that short version
|
||||
- generates `apps/ios/build/AppStoreRelease.xcconfig`
|
||||
- archives `OpenClaw`
|
||||
- uploads the IPA to TestFlight
|
||||
- uploads the IPA to App Store Connect for TestFlight/App Review use
|
||||
|
||||
7. Expected outputs after a successful run:
|
||||
- `apps/ios/build/beta/OpenClaw-<version>.ipa`
|
||||
- `apps/ios/build/beta/OpenClaw-<version>.app.dSYM.zip`
|
||||
- Fastlane log line like `Uploaded iOS beta: version=<version> short=<short> build=<build>`
|
||||
8. Expected outputs after a successful run:
|
||||
- `apps/ios/build/app-store/OpenClaw-<version>.ipa`
|
||||
- `apps/ios/build/app-store/OpenClaw-<version>.app.dSYM.zip`
|
||||
- Fastlane log line like `Uploaded iOS App Store build: version=<version> short=<short> build=<build>`
|
||||
|
||||
8. 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.
|
||||
9. 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.
|
||||
|
||||
## iOS Versioning Workflow
|
||||
|
||||
@@ -177,7 +193,7 @@ Recommended flow:
|
||||
1. Keep `apps/ios/version.json` pinned to the current train version.
|
||||
2. Update `apps/ios/CHANGELOG.md`, usually under `## Unreleased` while iterating.
|
||||
3. Run `pnpm ios:version:sync` after changelog changes.
|
||||
4. Upload more TestFlight builds with `pnpm ios:beta`.
|
||||
4. Upload more TestFlight builds with `pnpm ios:release`.
|
||||
5. Let Fastlane bump only the numeric build number.
|
||||
|
||||
### Starting the next production release train
|
||||
@@ -190,7 +206,7 @@ pnpm ios:version:pin -- --from-gateway
|
||||
|
||||
2. Update `apps/ios/CHANGELOG.md` for the new release as needed.
|
||||
3. Run `pnpm ios:version:sync`.
|
||||
4. Submit the first TestFlight build for that newly pinned version.
|
||||
4. Submit the first App Store Connect build for that newly pinned version.
|
||||
5. Keep iterating on that same version until the release candidate is ready.
|
||||
|
||||
See `apps/ios/VERSIONING.md` for the detailed spec.
|
||||
@@ -198,9 +214,9 @@ 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.entitlements` sets `aps-environment` to `development`.
|
||||
- `apps/ios/Sources/OpenClaw.entitlements` derives `aps-environment` from the active build configuration/signing override.
|
||||
- APNs token registration to gateway happens only after gateway connection (`push.apns.register`).
|
||||
- Local/manual builds default to `OpenClawPushTransport=direct` and `OpenClawPushDistribution=local`.
|
||||
- Local/manual builds default to `OpenClawPushTransport=direct`, `OpenClawPushDistribution=local`, and a development `aps-environment` entitlement.
|
||||
- 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 either `OPENCLAW_APNS_PRIVATE_KEY_P8` or `OPENCLAW_APNS_PRIVATE_KEY_PATH`.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Config/Version.xcconfig"
|
||||
|
||||
OPENCLAW_CODE_SIGN_STYLE = Manual
|
||||
OPENCLAW_CODE_SIGN_IDENTITY = Apple Development
|
||||
OPENCLAW_DEVELOPMENT_TEAM = FWJYW4S8P8
|
||||
|
||||
OPENCLAW_APP_BUNDLE_ID = ai.openclawfoundation.app
|
||||
@@ -12,6 +13,7 @@ OPENCLAW_SHARE_BUNDLE_ID = ai.openclawfoundation.app.share
|
||||
OPENCLAW_WATCH_APP_BUNDLE_ID = ai.openclawfoundation.app.watchkitapp
|
||||
OPENCLAW_WATCH_EXTENSION_BUNDLE_ID = ai.openclawfoundation.app.watchkitapp.extension
|
||||
OPENCLAW_ACTIVITY_WIDGET_BUNDLE_ID = ai.openclawfoundation.app.activitywidget
|
||||
OPENCLAW_APNS_ENTITLEMENT_ENVIRONMENT = development
|
||||
|
||||
OPENCLAW_APP_PROFILE = ai.openclawfoundation.app Development
|
||||
OPENCLAW_SHARE_PROFILE = ai.openclawfoundation.app.share Development
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<string>$(OPENCLAW_APNS_ENTITLEMENT_ENVIRONMENT)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ Pinned iOS version `2026.4.10` maps to:
|
||||
- `apps/ios/fastlane/metadata/en-US/release_notes.txt`
|
||||
- generated from `apps/ios/CHANGELOG.md`
|
||||
- `apps/ios/build/Version.xcconfig`
|
||||
- local gitignored build override generated per build or beta prep
|
||||
- local gitignored build override generated per build or release prep
|
||||
|
||||
## Tooling surfaces
|
||||
|
||||
@@ -81,16 +81,16 @@ Pinned iOS version `2026.4.10` maps to:
|
||||
- `scripts/ios-pin-version.ts`
|
||||
- explicitly pins iOS to a chosen release version or the current gateway version
|
||||
|
||||
### Build and beta flow
|
||||
### Build and App Store release flow
|
||||
|
||||
- `scripts/ios-write-version-xcconfig.sh`
|
||||
- reads the pinned iOS version
|
||||
- writes the local numeric build override file in `apps/ios/build/Version.xcconfig`
|
||||
- `scripts/ios-beta-prepare.sh`
|
||||
- prepares beta signing and bundle settings against the pinned iOS version
|
||||
- `scripts/ios-release-prepare.sh`
|
||||
- prepares App Store distribution signing and bundle settings against the pinned iOS version
|
||||
- `apps/ios/fastlane/Fastfile`
|
||||
- resolves version metadata from the pinned iOS helper
|
||||
- increments TestFlight build numbers for the pinned short version
|
||||
- increments App Store Connect build numbers for the pinned short version
|
||||
|
||||
## Release-note resolution order
|
||||
|
||||
@@ -118,7 +118,7 @@ pnpm ios:version:pin -- --version 2026.4.10
|
||||
|
||||
1. keep `apps/ios/version.json` pinned to the current TestFlight train version
|
||||
2. update `apps/ios/CHANGELOG.md` under `## Unreleased` while iterating
|
||||
3. upload more betas with the usual flow
|
||||
3. upload more App Store Connect builds with the usual flow
|
||||
4. let Fastlane increment only `CFBundleVersion`
|
||||
|
||||
This keeps the TestFlight version stable while review is in flight.
|
||||
@@ -139,7 +139,7 @@ pnpm ios:version:pin -- --from-gateway
|
||||
- `apps/ios/fastlane/metadata/en-US/release_notes.txt`
|
||||
3. update `apps/ios/CHANGELOG.md` for the new release if needed
|
||||
4. run `pnpm ios:version:sync` again if the changelog changed
|
||||
5. submit the first TestFlight build for that newly pinned version
|
||||
5. submit the first App Store Connect build for that newly pinned version
|
||||
6. keep iterating only by build number until the release candidate is ready
|
||||
7. release that reviewed TestFlight build to production
|
||||
|
||||
|
||||
+33
-33
@@ -4,7 +4,7 @@ require "json"
|
||||
|
||||
default_platform(:ios)
|
||||
|
||||
BETA_APP_IDENTIFIER = "ai.openclawfoundation.app"
|
||||
APP_STORE_APP_IDENTIFIER = "ai.openclawfoundation.app"
|
||||
DEFAULT_SNAPSHOT_DEVICES = ["iPhone 16 Pro Max", "iPad Pro 13-inch (M4)"].freeze
|
||||
SNAPSHOT_STATUS_BAR_ARGUMENTS = "--time 09:41 --dataNetwork wifi --wifiMode active --wifiBars 3 --cellularMode active --cellularBars 4 --batteryState charged --batteryLevel 100".freeze
|
||||
REQUIRED_SCREENSHOT_FAMILIES = {
|
||||
@@ -178,45 +178,45 @@ def shell_join(parts)
|
||||
Shellwords.join(parts.compact)
|
||||
end
|
||||
|
||||
def resolve_beta_build_number(api_key:, short_version:)
|
||||
explicit = ENV["IOS_BETA_BUILD_NUMBER"]
|
||||
def resolve_release_build_number(api_key:, short_version:)
|
||||
explicit = ENV["IOS_RELEASE_BUILD_NUMBER"]
|
||||
if env_present?(explicit)
|
||||
UI.user_error!("Invalid IOS_BETA_BUILD_NUMBER '#{explicit}'. Expected digits only.") unless explicit.match?(/\A\d+\z/)
|
||||
UI.message("Using explicit iOS beta build number #{explicit}.")
|
||||
UI.user_error!("Invalid iOS release build number '#{explicit}'. Expected digits only.") unless explicit.match?(/\A\d+\z/)
|
||||
UI.message("Using explicit iOS release build number #{explicit}.")
|
||||
return explicit
|
||||
end
|
||||
|
||||
latest_build = latest_testflight_build_number(
|
||||
api_key: api_key,
|
||||
app_identifier: BETA_APP_IDENTIFIER,
|
||||
app_identifier: APP_STORE_APP_IDENTIFIER,
|
||||
version: short_version,
|
||||
initial_build_number: 0
|
||||
)
|
||||
next_build = latest_build.to_i + 1
|
||||
UI.message("Resolved iOS beta build number #{next_build} for #{short_version} (latest TestFlight build: #{latest_build}).")
|
||||
UI.message("Resolved iOS release build number #{next_build} for #{short_version} (latest App Store Connect build: #{latest_build}).")
|
||||
next_build.to_s
|
||||
end
|
||||
|
||||
def beta_build_number_needs_asc_auth?
|
||||
explicit = ENV["IOS_BETA_BUILD_NUMBER"]
|
||||
def release_build_number_needs_asc_auth?
|
||||
explicit = ENV["IOS_RELEASE_BUILD_NUMBER"]
|
||||
!env_present?(explicit)
|
||||
end
|
||||
|
||||
def prepare_beta_release!(version:, build_number:)
|
||||
script_path = File.join(repo_root, "scripts", "ios-beta-prepare.sh")
|
||||
UI.message("Preparing iOS beta release #{version} (build #{build_number}).")
|
||||
def prepare_app_store_release!(version:, build_number:)
|
||||
script_path = File.join(repo_root, "scripts", "ios-release-prepare.sh")
|
||||
UI.message("Preparing iOS App Store release #{version} (build #{build_number}).")
|
||||
sh(shell_join(["bash", script_path, "--build-number", build_number]))
|
||||
|
||||
beta_xcconfig = File.join(ios_root, "build", "BetaRelease.xcconfig")
|
||||
UI.user_error!("Missing beta xcconfig at #{beta_xcconfig}.") unless File.exist?(beta_xcconfig)
|
||||
release_xcconfig = File.join(ios_root, "build", "AppStoreRelease.xcconfig")
|
||||
UI.user_error!("Missing App Store release xcconfig at #{release_xcconfig}.") unless File.exist?(release_xcconfig)
|
||||
|
||||
ENV["XCODE_XCCONFIG_FILE"] = beta_xcconfig
|
||||
beta_xcconfig
|
||||
ENV["XCODE_XCCONFIG_FILE"] = release_xcconfig
|
||||
release_xcconfig
|
||||
end
|
||||
|
||||
def build_beta_release(context)
|
||||
def build_app_store_release(context)
|
||||
version = context[:version]
|
||||
output_directory = File.join("build", "beta")
|
||||
output_directory = File.join("build", "app-store")
|
||||
archive_path = File.join(output_directory, "OpenClaw-#{version}.xcarchive")
|
||||
|
||||
build_app(
|
||||
@@ -294,40 +294,40 @@ platform :ios do
|
||||
api_key
|
||||
end
|
||||
|
||||
private_lane :prepare_beta_context do |options|
|
||||
private_lane :prepare_app_store_context do |options|
|
||||
require_api_key = options[:require_api_key] == true
|
||||
needs_api_key = require_api_key || beta_build_number_needs_asc_auth?
|
||||
needs_api_key = require_api_key || release_build_number_needs_asc_auth?
|
||||
api_key = needs_api_key ? asc_api_key : nil
|
||||
sync_ios_versioning!
|
||||
version_metadata = read_ios_version_metadata
|
||||
version = version_metadata[:version]
|
||||
short_version = version_metadata[:short_version]
|
||||
build_number = resolve_beta_build_number(api_key: api_key, short_version: short_version)
|
||||
beta_xcconfig = prepare_beta_release!(version: version, build_number: build_number)
|
||||
build_number = resolve_release_build_number(api_key: api_key, short_version: short_version)
|
||||
release_xcconfig = prepare_app_store_release!(version: version, build_number: build_number)
|
||||
|
||||
{
|
||||
api_key: api_key,
|
||||
beta_xcconfig: beta_xcconfig,
|
||||
build_number: build_number,
|
||||
release_xcconfig: release_xcconfig,
|
||||
short_version: short_version,
|
||||
version: version
|
||||
}
|
||||
end
|
||||
|
||||
desc "Build a beta archive locally without uploading"
|
||||
lane :beta_archive do
|
||||
context = prepare_beta_context(require_api_key: false)
|
||||
build = build_beta_release(context)
|
||||
UI.success("Built iOS beta archive: version=#{build[:version]} short=#{build[:short_version]} build=#{build[:build_number]}")
|
||||
desc "Build an App Store distribution archive locally without uploading"
|
||||
lane :app_store_archive do
|
||||
context = prepare_app_store_context(require_api_key: false)
|
||||
build = build_app_store_release(context)
|
||||
UI.success("Built iOS App Store archive: version=#{build[:version]} short=#{build[:short_version]} build=#{build[:build_number]}")
|
||||
build
|
||||
ensure
|
||||
ENV.delete("XCODE_XCCONFIG_FILE")
|
||||
end
|
||||
|
||||
desc "Build + upload a beta to TestFlight"
|
||||
lane :beta do
|
||||
context = prepare_beta_context(require_api_key: true)
|
||||
build = build_beta_release(context)
|
||||
desc "Build + upload an App Store distribution build to App Store Connect"
|
||||
lane :app_store do
|
||||
context = prepare_app_store_context(require_api_key: true)
|
||||
build = build_app_store_release(context)
|
||||
|
||||
upload_to_testflight(
|
||||
api_key: context[:api_key],
|
||||
@@ -336,7 +336,7 @@ platform :ios do
|
||||
uses_non_exempt_encryption: false
|
||||
)
|
||||
|
||||
UI.success("Uploaded iOS beta: version=#{build[:version]} short=#{build[:short_version]} build=#{build[:build_number]}")
|
||||
UI.success("Uploaded iOS App Store build: version=#{build[:version]} short=#{build[:short_version]} build=#{build[:build_number]}")
|
||||
ensure
|
||||
ENV.delete("XCODE_XCCONFIG_FILE")
|
||||
end
|
||||
|
||||
+16
-16
@@ -29,7 +29,7 @@ ASC_KEYCHAIN_SERVICE=openclaw-asc-key
|
||||
ASC_KEYCHAIN_ACCOUNT=YOUR_MAC_USERNAME
|
||||
```
|
||||
|
||||
Important: `apps/ios/fastlane/.env` is only for Fastlane/App Store Connect auth and optional beta-archive settings. It does **not** configure gateway-side direct APNs push delivery for local iOS builds.
|
||||
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):
|
||||
|
||||
@@ -53,7 +53,7 @@ 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 beta archives.
|
||||
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.
|
||||
|
||||
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`.
|
||||
|
||||
@@ -66,15 +66,15 @@ fastlane ios auth_check
|
||||
|
||||
ASC auth is only required when:
|
||||
|
||||
- uploading to TestFlight
|
||||
- uploading to App Store Connect
|
||||
- auto-resolving the next build number from App Store Connect
|
||||
|
||||
If you pass `--build-number` to `pnpm ios:beta:archive`, the local archive path does not need ASC auth.
|
||||
If you pass `--build-number` to `pnpm ios:release:archive`, the local archive path does not need ASC auth.
|
||||
|
||||
Archive locally without upload:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta:archive
|
||||
pnpm ios:release:archive
|
||||
```
|
||||
|
||||
Generate deterministic App Store screenshots:
|
||||
@@ -85,17 +85,17 @@ 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 TestFlight:
|
||||
Upload to App Store Connect:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta
|
||||
pnpm ios:release
|
||||
```
|
||||
|
||||
Direct Fastlane entry point:
|
||||
|
||||
```bash
|
||||
cd apps/ios
|
||||
fastlane ios beta
|
||||
fastlane ios app_store
|
||||
```
|
||||
|
||||
Maintainer recovery path for a fresh clone on the same Mac:
|
||||
@@ -123,7 +123,7 @@ fastlane ios auth_check
|
||||
pnpm ios:version:pin -- --from-gateway
|
||||
```
|
||||
|
||||
5. Set the official/TestFlight relay URL before release:
|
||||
5. Set the official relay URL before release:
|
||||
|
||||
```bash
|
||||
export OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com
|
||||
@@ -132,14 +132,14 @@ export OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com
|
||||
6. Upload:
|
||||
|
||||
```bash
|
||||
pnpm ios:beta
|
||||
pnpm ios:release
|
||||
```
|
||||
|
||||
Quick verification after upload:
|
||||
|
||||
- confirm `apps/ios/build/beta/OpenClaw-<version>.ipa` exists
|
||||
- confirm Fastlane prints `Uploaded iOS beta: version=<version> short=<short> build=<build>`
|
||||
- remember that TestFlight processing can take a few minutes after the upload succeeds
|
||||
- confirm `apps/ios/build/app-store/OpenClaw-<version>.ipa` exists
|
||||
- confirm Fastlane prints `Uploaded iOS App Store build: version=<version> short=<short> build=<build>`
|
||||
- remember that App Store Connect/TestFlight processing can take a few minutes after the upload succeeds
|
||||
|
||||
Versioning rules:
|
||||
|
||||
@@ -149,9 +149,9 @@ Versioning rules:
|
||||
- `pnpm ios:version:pin -- --from-gateway` promotes the current root gateway version into the pinned iOS release version
|
||||
- Fastlane uses the pinned iOS version only; changing `package.json.version` alone does not change the iOS app version
|
||||
- Fastlane sets `CFBundleShortVersionString` to the pinned iOS version, for example `2026.4.10`
|
||||
- Fastlane resolves `CFBundleVersion` as the next integer TestFlight build number for that short version
|
||||
- Fastlane resolves `CFBundleVersion` as the next integer App Store Connect build number for that short version
|
||||
- Run `pnpm ios:version:sync` after changing `apps/ios/version.json` or `apps/ios/CHANGELOG.md`
|
||||
- `pnpm ios:version:check` validates that checked-in iOS version artifacts are in sync
|
||||
- The beta flow regenerates `apps/ios/OpenClaw.xcodeproj` from `apps/ios/project.yml` before archiving
|
||||
- Local beta signing uses a temporary generated xcconfig and leaves local development signing overrides untouched
|
||||
- The release flow regenerates `apps/ios/OpenClaw.xcodeproj` from `apps/ios/project.yml` before archiving
|
||||
- Local App Store signing uses a temporary generated xcconfig and leaves local development signing overrides untouched
|
||||
- See `apps/ios/VERSIONING.md` for the detailed workflow
|
||||
|
||||
+10
-8
@@ -99,7 +99,7 @@ targets:
|
||||
swiftlint lint --config "$SRCROOT/.swiftlint.yml" --use-script-input-file-lists
|
||||
settings:
|
||||
base:
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_IDENTITY: "$(OPENCLAW_CODE_SIGN_IDENTITY)"
|
||||
CODE_SIGN_ENTITLEMENTS: Sources/OpenClaw.entitlements
|
||||
CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)"
|
||||
@@ -113,11 +113,13 @@ targets:
|
||||
ENABLE_APP_INTENTS_METADATA_GENERATION: NO
|
||||
configs:
|
||||
Debug:
|
||||
OPENCLAW_APNS_ENTITLEMENT_ENVIRONMENT: development
|
||||
OPENCLAW_PUSH_TRANSPORT: direct
|
||||
OPENCLAW_PUSH_DISTRIBUTION: local
|
||||
OPENCLAW_PUSH_RELAY_BASE_URL: ""
|
||||
OPENCLAW_PUSH_APNS_ENVIRONMENT: sandbox
|
||||
Release:
|
||||
OPENCLAW_APNS_ENTITLEMENT_ENVIRONMENT: production
|
||||
OPENCLAW_PUSH_TRANSPORT: direct
|
||||
OPENCLAW_PUSH_DISTRIBUTION: local
|
||||
OPENCLAW_PUSH_RELAY_BASE_URL: ""
|
||||
@@ -184,7 +186,7 @@ targets:
|
||||
- sdk: AppIntents.framework
|
||||
settings:
|
||||
base:
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_IDENTITY: "$(OPENCLAW_CODE_SIGN_IDENTITY)"
|
||||
CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)"
|
||||
ENABLE_APPINTENTS_METADATA: NO
|
||||
@@ -224,7 +226,7 @@ targets:
|
||||
- sdk: ActivityKit.framework
|
||||
settings:
|
||||
base:
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_IDENTITY: "$(OPENCLAW_CODE_SIGN_IDENTITY)"
|
||||
CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)"
|
||||
PRODUCT_BUNDLE_IDENTIFIER: "$(OPENCLAW_ACTIVITY_WIDGET_BUNDLE_ID)"
|
||||
@@ -259,7 +261,7 @@ targets:
|
||||
settings:
|
||||
base:
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_IDENTITY: "$(OPENCLAW_CODE_SIGN_IDENTITY)"
|
||||
CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)"
|
||||
ENABLE_APPINTENTS_METADATA: NO
|
||||
@@ -293,7 +295,7 @@ targets:
|
||||
ProvisioningStyle: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
settings:
|
||||
base:
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_IDENTITY: "$(OPENCLAW_CODE_SIGN_IDENTITY)"
|
||||
CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)"
|
||||
PRODUCT_BUNDLE_IDENTIFIER: "$(OPENCLAW_WATCH_EXTENSION_BUNDLE_ID)"
|
||||
@@ -326,7 +328,7 @@ targets:
|
||||
- sdk: AppIntents.framework
|
||||
settings:
|
||||
base:
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_IDENTITY: "$(OPENCLAW_CODE_SIGN_IDENTITY)"
|
||||
CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)"
|
||||
PRODUCT_BUNDLE_IDENTIFIER: "$(OPENCLAW_APP_BUNDLE_ID).tests"
|
||||
@@ -354,7 +356,7 @@ targets:
|
||||
- package: OpenClawKit
|
||||
settings:
|
||||
base:
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_IDENTITY: "$(OPENCLAW_CODE_SIGN_IDENTITY)"
|
||||
CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)"
|
||||
PRODUCT_BUNDLE_IDENTIFIER: "$(OPENCLAW_APP_BUNDLE_ID).logic-tests"
|
||||
@@ -381,7 +383,7 @@ targets:
|
||||
- target: OpenClaw
|
||||
settings:
|
||||
base:
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_IDENTITY: "$(OPENCLAW_CODE_SIGN_IDENTITY)"
|
||||
CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)"
|
||||
DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)"
|
||||
PRODUCT_BUNDLE_IDENTIFIER: "$(OPENCLAW_APP_BUNDLE_ID).ui-tests"
|
||||
|
||||
+3
-3
@@ -1550,12 +1550,12 @@
|
||||
"gateway:watch:raw": "node scripts/watch-node.mjs gateway --force",
|
||||
"gen:host-env-policy:swift": "node scripts/generate-host-env-security-policy-swift.mjs --write",
|
||||
"ghsa:patch": "node scripts/ghsa-patch.mjs",
|
||||
"ios:beta": "bash scripts/ios-beta-release.sh",
|
||||
"ios:beta:archive": "bash scripts/ios-beta-archive.sh",
|
||||
"ios:beta:prepare": "bash scripts/ios-beta-prepare.sh",
|
||||
"ios:build": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build'",
|
||||
"ios:gen": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate'",
|
||||
"ios:open": "bash -lc './scripts/ios-configure-signing.sh && ./scripts/ios-write-version-xcconfig.sh && cd apps/ios && xcodegen generate && open OpenClaw.xcodeproj'",
|
||||
"ios:release": "bash scripts/ios-release.sh",
|
||||
"ios:release:archive": "bash scripts/ios-release-archive.sh",
|
||||
"ios:release:prepare": "bash scripts/ios-release-prepare.sh",
|
||||
"ios:run": "bash scripts/ios-run.sh",
|
||||
"ios:screenshots": "bash scripts/ios-screenshots.sh",
|
||||
"ios:version": "node --import tsx scripts/ios-version.ts --json",
|
||||
|
||||
@@ -73,6 +73,8 @@ watch_app_bundle_id="${OPENCLAW_IOS_WATCH_APP_BUNDLE_ID:-${bundle_base}.watchkit
|
||||
watch_extension_bundle_id="${OPENCLAW_IOS_WATCH_EXTENSION_BUNDLE_ID:-${watch_app_bundle_id}.extension}"
|
||||
|
||||
code_sign_style="${OPENCLAW_IOS_CODE_SIGN_STYLE:-Automatic}"
|
||||
code_sign_identity="${OPENCLAW_IOS_CODE_SIGN_IDENTITY:-Apple Development}"
|
||||
apns_entitlement_environment="${OPENCLAW_IOS_APNS_ENTITLEMENT_ENVIRONMENT:-development}"
|
||||
app_profile="${OPENCLAW_IOS_APP_PROFILE:-}"
|
||||
share_profile="${OPENCLAW_IOS_SHARE_PROFILE:-}"
|
||||
watch_app_profile="${OPENCLAW_IOS_WATCH_APP_PROFILE:-}"
|
||||
@@ -87,9 +89,12 @@ cat >"${tmp_file}" <<EOF
|
||||
// OPENCLAW_IOS_APP_BUNDLE_ID / OPENCLAW_IOS_BUNDLE_ID_BASE
|
||||
// OPENCLAW_IOS_SHARE_BUNDLE_ID / OPENCLAW_IOS_ACTIVITY_WIDGET_BUNDLE_ID
|
||||
// OPENCLAW_IOS_WATCH_APP_BUNDLE_ID / OPENCLAW_IOS_WATCH_EXTENSION_BUNDLE_ID
|
||||
// OPENCLAW_IOS_CODE_SIGN_STYLE / OPENCLAW_IOS_APP_PROFILE / OPENCLAW_IOS_SHARE_PROFILE
|
||||
// OPENCLAW_IOS_WATCH_APP_PROFILE / OPENCLAW_IOS_WATCH_EXTENSION_PROFILE
|
||||
// OPENCLAW_IOS_CODE_SIGN_STYLE / OPENCLAW_IOS_CODE_SIGN_IDENTITY
|
||||
// OPENCLAW_IOS_APNS_ENTITLEMENT_ENVIRONMENT / OPENCLAW_IOS_APP_PROFILE
|
||||
// OPENCLAW_IOS_SHARE_PROFILE / OPENCLAW_IOS_WATCH_APP_PROFILE
|
||||
// OPENCLAW_IOS_WATCH_EXTENSION_PROFILE
|
||||
OPENCLAW_CODE_SIGN_STYLE = ${code_sign_style}
|
||||
OPENCLAW_CODE_SIGN_IDENTITY = ${code_sign_identity}
|
||||
OPENCLAW_DEVELOPMENT_TEAM = ${team_id}
|
||||
// Keep legacy key for compatibility with older signing config paths.
|
||||
OPENCLAW_IOS_SELECTED_TEAM = ${team_id}
|
||||
@@ -98,6 +103,7 @@ OPENCLAW_SHARE_BUNDLE_ID = ${share_bundle_id}
|
||||
OPENCLAW_ACTIVITY_WIDGET_BUNDLE_ID = ${activity_widget_bundle_id}
|
||||
OPENCLAW_WATCH_APP_BUNDLE_ID = ${watch_app_bundle_id}
|
||||
OPENCLAW_WATCH_EXTENSION_BUNDLE_ID = ${watch_extension_bundle_id}
|
||||
OPENCLAW_APNS_ENTITLEMENT_ENVIRONMENT = ${apns_entitlement_environment}
|
||||
OPENCLAW_APP_PROFILE = ${app_profile}
|
||||
OPENCLAW_SHARE_PROFILE = ${share_profile}
|
||||
OPENCLAW_WATCH_APP_PROFILE = ${watch_app_profile}
|
||||
|
||||
@@ -4,13 +4,13 @@ set -euo pipefail
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/ios-beta-release.sh [--build-number 7]
|
||||
scripts/ios-release-archive.sh [--build-number 7]
|
||||
|
||||
Archives and uploads a beta-release IPA to TestFlight locally.
|
||||
Archives and exports an App Store distribution IPA locally without uploading.
|
||||
EOF
|
||||
}
|
||||
|
||||
BUILD_NUMBER="${IOS_BETA_BUILD_NUMBER:-}"
|
||||
BUILD_NUMBER="${IOS_RELEASE_BUILD_NUMBER:-}"
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
@@ -36,5 +36,5 @@ done
|
||||
|
||||
(
|
||||
cd "${ROOT_DIR}/apps/ios"
|
||||
IOS_BETA_BUILD_NUMBER="${BUILD_NUMBER}" fastlane ios beta
|
||||
IOS_RELEASE_BUILD_NUMBER="${BUILD_NUMBER}" fastlane ios app_store_archive
|
||||
)
|
||||
@@ -4,16 +4,17 @@ set -euo pipefail
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/ios-beta-prepare.sh --build-number 7 [--team-id TEAMID]
|
||||
scripts/ios-release-prepare.sh --build-number 7 [--team-id TEAMID]
|
||||
|
||||
Optional custom relay:
|
||||
OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com \
|
||||
scripts/ios-beta-prepare.sh --build-number 7 [--team-id TEAMID]
|
||||
scripts/ios-release-prepare.sh --build-number 7 [--team-id TEAMID]
|
||||
|
||||
Prepares local beta-release inputs without touching local signing overrides:
|
||||
Prepares local App Store release inputs without touching local signing overrides:
|
||||
- reads apps/ios/version.json and writes apps/ios/build/Version.xcconfig
|
||||
- writes apps/ios/build/BetaRelease.xcconfig with canonical bundle IDs
|
||||
- configures the beta build for relay-backed APNs registration
|
||||
- writes apps/ios/build/AppStoreRelease.xcconfig with canonical bundle IDs
|
||||
- configures the release build for relay-backed APNs registration
|
||||
- configures automatic App Store distribution signing for the canonical team
|
||||
- regenerates apps/ios/OpenClaw.xcodeproj via xcodegen
|
||||
EOF
|
||||
}
|
||||
@@ -21,7 +22,7 @@ EOF
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
IOS_DIR="${ROOT_DIR}/apps/ios"
|
||||
BUILD_DIR="${IOS_DIR}/build"
|
||||
BETA_XCCONFIG="${IOS_DIR}/build/BetaRelease.xcconfig"
|
||||
RELEASE_XCCONFIG="${IOS_DIR}/build/AppStoreRelease.xcconfig"
|
||||
TEAM_HELPER="${ROOT_DIR}/scripts/ios-team-id.sh"
|
||||
VERSION_HELPER="${ROOT_DIR}/scripts/ios-write-version-xcconfig.sh"
|
||||
IOS_VERSION_HELPER="${ROOT_DIR}/scripts/ios-version.ts"
|
||||
@@ -124,7 +125,7 @@ if [[ -z "${TEAM_ID}" ]]; then
|
||||
fi
|
||||
|
||||
if [[ "${TEAM_ID}" != "${CANONICAL_TEAM_ID}" ]]; then
|
||||
echo "iOS beta release must use canonical OpenClaw Team ID ${CANONICAL_TEAM_ID}; got ${TEAM_ID}." >&2
|
||||
echo "iOS App Store release must use canonical OpenClaw Team ID ${CANONICAL_TEAM_ID}; got ${TEAM_ID}." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -153,10 +154,11 @@ fi
|
||||
bash "${VERSION_HELPER}" --build-number "${BUILD_NUMBER}"
|
||||
)
|
||||
|
||||
write_generated_file "${BETA_XCCONFIG}" <<EOF
|
||||
// Auto-generated by scripts/ios-beta-prepare.sh.
|
||||
// Local beta-release override; do not commit.
|
||||
write_generated_file "${RELEASE_XCCONFIG}" <<EOF
|
||||
// Auto-generated by scripts/ios-release-prepare.sh.
|
||||
// Local App Store release override; do not commit.
|
||||
OPENCLAW_CODE_SIGN_STYLE = Automatic
|
||||
OPENCLAW_CODE_SIGN_IDENTITY = Apple Distribution
|
||||
OPENCLAW_DEVELOPMENT_TEAM = ${TEAM_ID}
|
||||
OPENCLAW_IOS_SELECTED_TEAM = ${TEAM_ID}
|
||||
OPENCLAW_APP_BUNDLE_ID = ai.openclawfoundation.app
|
||||
@@ -164,8 +166,11 @@ OPENCLAW_SHARE_BUNDLE_ID = ai.openclawfoundation.app.share
|
||||
OPENCLAW_ACTIVITY_WIDGET_BUNDLE_ID = ai.openclawfoundation.app.activitywidget
|
||||
OPENCLAW_WATCH_APP_BUNDLE_ID = ai.openclawfoundation.app.watchkitapp
|
||||
OPENCLAW_WATCH_EXTENSION_BUNDLE_ID = ai.openclawfoundation.app.watchkitapp.extension
|
||||
OPENCLAW_APNS_ENTITLEMENT_ENVIRONMENT = production
|
||||
OPENCLAW_APP_PROFILE =
|
||||
OPENCLAW_SHARE_PROFILE =
|
||||
OPENCLAW_WATCH_APP_PROFILE =
|
||||
OPENCLAW_WATCH_EXTENSION_PROFILE =
|
||||
OPENCLAW_PUSH_TRANSPORT = relay
|
||||
OPENCLAW_PUSH_DISTRIBUTION = official
|
||||
OPENCLAW_URL_SLASH = /
|
||||
@@ -178,5 +183,5 @@ EOF
|
||||
xcodegen generate
|
||||
)
|
||||
|
||||
echo "Prepared iOS beta release: version=${IOS_VERSION} build=${BUILD_NUMBER} team=${TEAM_ID}"
|
||||
echo "XCODE_XCCONFIG_FILE=${BETA_XCCONFIG}"
|
||||
echo "Prepared iOS App Store release: version=${IOS_VERSION} build=${BUILD_NUMBER} team=${TEAM_ID}"
|
||||
echo "XCODE_XCCONFIG_FILE=${RELEASE_XCCONFIG}"
|
||||
@@ -4,13 +4,13 @@ set -euo pipefail
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/ios-beta-archive.sh [--build-number 7]
|
||||
scripts/ios-release.sh [--build-number 7]
|
||||
|
||||
Archives and exports a beta-release IPA locally without uploading.
|
||||
Archives and uploads an App Store distribution build to App Store Connect.
|
||||
EOF
|
||||
}
|
||||
|
||||
BUILD_NUMBER="${IOS_BETA_BUILD_NUMBER:-}"
|
||||
BUILD_NUMBER="${IOS_RELEASE_BUILD_NUMBER:-}"
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
@@ -36,5 +36,5 @@ done
|
||||
|
||||
(
|
||||
cd "${ROOT_DIR}/apps/ios"
|
||||
IOS_BETA_BUILD_NUMBER="${BUILD_NUMBER}" fastlane ios beta_archive
|
||||
IOS_RELEASE_BUILD_NUMBER="${BUILD_NUMBER}" fastlane ios app_store
|
||||
)
|
||||
@@ -1,9 +1,9 @@
|
||||
// iOS beta prepare tests cover release-signing guardrails.
|
||||
// iOS release prepare tests cover release-signing guardrails.
|
||||
import { execFileSync } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const SCRIPT = path.join(process.cwd(), "scripts", "ios-beta-prepare.sh");
|
||||
const SCRIPT = path.join(process.cwd(), "scripts", "ios-release-prepare.sh");
|
||||
const BASH_BIN = process.platform === "win32" ? "bash" : "/bin/bash";
|
||||
const BASH_ARGS = process.platform === "win32" ? [SCRIPT] : ["--noprofile", "--norc", SCRIPT];
|
||||
|
||||
@@ -36,13 +36,13 @@ function runPrepare(extraArgs: string[]): { ok: boolean; stdout: string; stderr:
|
||||
}
|
||||
}
|
||||
|
||||
describe("scripts/ios-beta-prepare.sh", () => {
|
||||
it("rejects non-canonical beta signing teams before generating release inputs", () => {
|
||||
describe("scripts/ios-release-prepare.sh", () => {
|
||||
it("rejects non-canonical signing teams before generating release inputs", () => {
|
||||
const result = runPrepare(["--build-number", "7"]);
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.stderr).toContain(
|
||||
"iOS beta release must use canonical OpenClaw Team ID FWJYW4S8P8",
|
||||
"iOS App Store release must use canonical OpenClaw Team ID FWJYW4S8P8",
|
||||
);
|
||||
expect(result.stderr).toContain("got Y3YUZP442G");
|
||||
});
|
||||
Reference in New Issue
Block a user