mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
feat(ios): auto-select local signing team (#18421)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: bbb9c3aa48
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -36,10 +36,12 @@ bin/docs-list
|
||||
apps/macos/.build-local/
|
||||
apps/macos/.swiftpm/
|
||||
apps/shared/MoltbotKit/.swiftpm/
|
||||
apps/shared/OpenClawKit/.swiftpm/
|
||||
Core/
|
||||
apps/ios/*.xcodeproj/
|
||||
apps/ios/*.xcworkspace/
|
||||
apps/ios/.swiftpm/
|
||||
apps/ios/.local-signing.xcconfig
|
||||
vendor/
|
||||
apps/ios/Clawdbot.xcodeproj/
|
||||
apps/ios/Clawdbot.xcodeproj/**
|
||||
|
||||
@@ -52,6 +52,7 @@ Docs: https://docs.openclaw.ai
|
||||
- iOS/Gateway: stabilize connect/discovery state handling, add onboarding reset recovery in Settings, and fix iOS gateway-controller coverage for command-surface and last-connection persistence behavior. (#18164) Thanks @mbelinky.
|
||||
- iOS/Talk: harden mobile talk config handling by ignoring redacted/env-placeholder API keys, support secure local keychain override, improve accessibility motion/contrast behavior in status UI, and tighten ATS to local-network allowance. (#18163) Thanks @mbelinky.
|
||||
- iOS/Location: restore the significant location monitor implementation (service hooks + protocol surface + ATS key alignment) after merge drift so iOS builds compile again. (#18260) Thanks @ngutman.
|
||||
- iOS/Signing: auto-select local Apple Development team during iOS project generation/build, prefer the canonical OpenClaw team when available, and support local per-machine signing overrides without committing team IDs. (#18421) Thanks @ngutman.
|
||||
- Discord/Telegram: make per-account message action gates effective for both action listing and execution, and preserve top-level gate restrictions when account overrides only specify a subset of `actions` keys (account key -> base key -> default fallback). (#18494)
|
||||
- Telegram: keep DM-topic replies and draft previews in the originating private-chat topic by preserving positive `message_thread_id` values for DM threads. (#18586) Thanks @sebslight.
|
||||
- Telegram: preserve private-chat topic `message_thread_id` on outbound sends (message/sticker/poll), keep thread-not-found retry fallback, and avoid masking `chat not found` routing errors. (#18993) Thanks @obviyus.
|
||||
|
||||
13
apps/ios/Config/Signing.xcconfig
Normal file
13
apps/ios/Config/Signing.xcconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
// Shared iOS signing defaults for local development + CI.
|
||||
OPENCLAW_IOS_DEFAULT_TEAM = Y5PE65HELJ
|
||||
OPENCLAW_IOS_SELECTED_TEAM = $(OPENCLAW_IOS_DEFAULT_TEAM)
|
||||
|
||||
// Local contributors can override this by running scripts/ios-configure-signing.sh.
|
||||
#include? "../.local-signing.xcconfig"
|
||||
|
||||
CODE_SIGN_STYLE = Automatic
|
||||
CODE_SIGN_IDENTITY = Apple Development
|
||||
DEVELOPMENT_TEAM = $(OPENCLAW_IOS_SELECTED_TEAM)
|
||||
|
||||
// Let Xcode manage provisioning for the selected local team.
|
||||
PROVISIONING_PROFILE_SPECIFIER =
|
||||
@@ -39,13 +39,20 @@ pnpm install
|
||||
pnpm ios:open
|
||||
```
|
||||
|
||||
`pnpm ios:open` now runs `scripts/ios-configure-signing.sh` before `xcodegen`:
|
||||
|
||||
- If `IOS_DEVELOPMENT_TEAM` is set, it uses that team.
|
||||
- Otherwise it prefers the canonical OpenClaw team (`Y5PE65HELJ`) when that team exists locally.
|
||||
- If not present, it picks the first non-personal team from your Xcode account (falls back to personal team if needed).
|
||||
- It writes the selected team to `apps/ios/.local-signing.xcconfig` (local-only, gitignored).
|
||||
|
||||
Then in Xcode:
|
||||
|
||||
1. Select the `OpenClaw` scheme
|
||||
2. Select a simulator or a connected device
|
||||
3. Run
|
||||
|
||||
If you're using a personal Apple Development team, you may need to change the bundle identifier in Xcode to a unique value so signing succeeds.
|
||||
If you're using a personal Apple Development team, you may still need to change the bundle identifier in Xcode to a unique value so signing succeeds.
|
||||
|
||||
## Build From CLI
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ platform :ios do
|
||||
if team_id.nil? || team_id.strip.empty?
|
||||
helper_path = File.expand_path("../../scripts/ios-team-id.sh", __dir__)
|
||||
if File.exist?(helper_path)
|
||||
team_id = sh("bash #{helper_path.shellescape}").strip
|
||||
# Keep CI/local compatibility where teams are present in keychain but not Xcode account metadata.
|
||||
team_id = sh("IOS_ALLOW_KEYCHAIN_TEAM_FALLBACK=1 bash #{helper_path.shellescape}").strip
|
||||
end
|
||||
end
|
||||
UI.user_error!("Missing IOS_DEVELOPMENT_TEAM (Apple Team ID). Add it to fastlane/.env or export it in your shell.") if team_id.nil? || team_id.strip.empty?
|
||||
|
||||
@@ -22,7 +22,7 @@ ASC_KEY_PATH=/absolute/path/to/AuthKey_XXXXXXXXXX.p8
|
||||
IOS_DEVELOPMENT_TEAM=YOUR_TEAM_ID
|
||||
```
|
||||
|
||||
Tip: run `scripts/ios-team-id.sh` from the repo root to print a Team ID to paste into `.env`. Fastlane falls back to this helper if `IOS_DEVELOPMENT_TEAM` is missing.
|
||||
Tip: run `scripts/ios-team-id.sh` from the repo root to print a Team ID to paste into `.env`. The helper prefers the canonical OpenClaw team (`Y5PE65HELJ`) when present locally; otherwise it prefers the first non-personal team from your Xcode account (then personal team if needed). Fastlane uses this helper automatically if `IOS_DEVELOPMENT_TEAM` is missing.
|
||||
|
||||
Run:
|
||||
|
||||
|
||||
@@ -66,13 +66,12 @@ targets:
|
||||
exit 1
|
||||
fi
|
||||
swiftlint lint --config "$SRCROOT/.swiftlint.yml" --use-script-input-file-lists
|
||||
configFiles:
|
||||
Debug: Config/Signing.xcconfig
|
||||
Release: Config/Signing.xcconfig
|
||||
settings:
|
||||
base:
|
||||
CODE_SIGN_IDENTITY: "Apple Development"
|
||||
CODE_SIGN_STYLE: Manual
|
||||
DEVELOPMENT_TEAM: Y5PE65HELJ
|
||||
PRODUCT_BUNDLE_IDENTIFIER: ai.openclaw.ios
|
||||
PROVISIONING_PROFILE_SPECIFIER: "ai.openclaw.ios Development"
|
||||
SWIFT_VERSION: "6.0"
|
||||
SWIFT_STRICT_CONCURRENCY: complete
|
||||
ENABLE_APPINTENTS_METADATA: NO
|
||||
|
||||
@@ -71,10 +71,10 @@
|
||||
"gateway:dev": "OPENCLAW_SKIP_CHANNELS=1 CLAWDBOT_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway",
|
||||
"gateway:dev:reset": "OPENCLAW_SKIP_CHANNELS=1 CLAWDBOT_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway --reset",
|
||||
"gateway:watch": "node scripts/watch-node.mjs gateway --force",
|
||||
"ios:build": "bash -lc '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": "cd apps/ios && xcodegen generate",
|
||||
"ios:open": "cd apps/ios && xcodegen generate && open OpenClaw.xcodeproj",
|
||||
"ios:run": "bash -lc 'cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build && xcrun simctl boot \"${IOS_SIM:-iPhone 17}\" || true && xcrun simctl launch booted ai.openclaw.ios'",
|
||||
"ios:build": "bash -lc './scripts/ios-configure-signing.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 && cd apps/ios && xcodegen generate'",
|
||||
"ios:open": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate && open OpenClaw.xcodeproj'",
|
||||
"ios:run": "bash -lc './scripts/ios-configure-signing.sh && cd apps/ios && xcodegen generate && xcodebuild -project OpenClaw.xcodeproj -scheme OpenClaw -destination \"${IOS_DEST:-platform=iOS Simulator,name=iPhone 17}\" -configuration Debug build && xcrun simctl boot \"${IOS_SIM:-iPhone 17}\" || true && xcrun simctl launch booted ai.openclaw.ios'",
|
||||
"lint": "oxlint --type-aware",
|
||||
"lint:all": "pnpm lint && pnpm lint:swift",
|
||||
"lint:docs": "pnpm dlx markdownlint-cli2",
|
||||
|
||||
41
scripts/ios-configure-signing.sh
Executable file
41
scripts/ios-configure-signing.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
IOS_DIR="${ROOT_DIR}/apps/ios"
|
||||
TEAM_ID_SCRIPT="${ROOT_DIR}/scripts/ios-team-id.sh"
|
||||
LOCAL_SIGNING_FILE="${IOS_DIR}/.local-signing.xcconfig"
|
||||
|
||||
if [[ ! -x "${TEAM_ID_SCRIPT}" ]]; then
|
||||
echo "ERROR: Missing team detection helper: ${TEAM_ID_SCRIPT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
team_id=""
|
||||
if team_id="$("${TEAM_ID_SCRIPT}" 2>/dev/null)"; then
|
||||
:
|
||||
else
|
||||
if [[ "${IOS_SIGNING_REQUIRED:-0}" == "1" ]]; then
|
||||
"${TEAM_ID_SCRIPT}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "WARN: Unable to detect an Apple Team ID; keeping existing iOS signing override (if any)." >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
tmp_file="$(mktemp "${TMPDIR:-/tmp}/openclaw-ios-signing.XXXXXX")"
|
||||
cat >"${tmp_file}" <<EOF
|
||||
// Auto-generated by scripts/ios-configure-signing.sh.
|
||||
// This file is local-only and should not be committed.
|
||||
OPENCLAW_IOS_SELECTED_TEAM = ${team_id}
|
||||
EOF
|
||||
|
||||
if [[ -f "${LOCAL_SIGNING_FILE}" ]] && cmp -s "${tmp_file}" "${LOCAL_SIGNING_FILE}"; then
|
||||
rm -f "${tmp_file}"
|
||||
echo "iOS signing team already configured: ${team_id}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mv "${tmp_file}" "${LOCAL_SIGNING_FILE}"
|
||||
echo "Configured iOS signing team: ${team_id}"
|
||||
@@ -1,15 +1,134 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
team_id="$(defaults read com.apple.dt.Xcode IDEProvisioningTeamIdentifiers 2>/dev/null | grep -Eo '[A-Z0-9]{10}' | head -n1 || true)"
|
||||
|
||||
if [[ -z "$team_id" ]]; then
|
||||
team_id="$(security find-identity -p codesigning -v 2>/dev/null | grep -Eo '\\([A-Z0-9]{10}\\)' | head -n1 | tr -d '()' || true)"
|
||||
if [[ -n "${IOS_DEVELOPMENT_TEAM:-}" ]]; then
|
||||
printf '%s\n' "${IOS_DEVELOPMENT_TEAM}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -z "$team_id" ]]; then
|
||||
echo "No Apple Team ID found. Open Xcode or install signing certificates first." >&2
|
||||
preferred_team="${IOS_PREFERRED_TEAM_ID:-${OPENCLAW_IOS_DEFAULT_TEAM_ID:-Y5PE65HELJ}}"
|
||||
preferred_team_name="${IOS_PREFERRED_TEAM_NAME:-}"
|
||||
allow_keychain_fallback="${IOS_ALLOW_KEYCHAIN_TEAM_FALLBACK:-0}"
|
||||
prefer_non_free_team="${IOS_PREFER_NON_FREE_TEAM:-1}"
|
||||
|
||||
declare -a team_ids=()
|
||||
declare -a team_is_free=()
|
||||
declare -a team_names=()
|
||||
|
||||
append_team() {
|
||||
local candidate_id="$1"
|
||||
local candidate_is_free="$2"
|
||||
local candidate_name="$3"
|
||||
[[ -z "$candidate_id" ]] && return
|
||||
|
||||
local i
|
||||
for i in "${!team_ids[@]}"; do
|
||||
if [[ "${team_ids[$i]}" == "$candidate_id" ]]; then
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
team_ids+=("$candidate_id")
|
||||
team_is_free+=("$candidate_is_free")
|
||||
team_names+=("$candidate_name")
|
||||
}
|
||||
|
||||
load_teams_from_xcode_preferences() {
|
||||
local plist_path="${HOME}/Library/Preferences/com.apple.dt.Xcode.plist"
|
||||
[[ -f "$plist_path" ]] || return 0
|
||||
|
||||
while IFS=$'\t' read -r team_id is_free team_name; do
|
||||
[[ -z "$team_id" ]] && continue
|
||||
append_team "$team_id" "${is_free:-0}" "${team_name:-}"
|
||||
done < <(
|
||||
plutil -extract IDEProvisioningTeams json -o - "$plist_path" 2>/dev/null \
|
||||
| /usr/bin/python3 -c '
|
||||
import json
|
||||
import sys
|
||||
|
||||
try:
|
||||
data = json.load(sys.stdin)
|
||||
except Exception:
|
||||
raise SystemExit(0)
|
||||
|
||||
if not isinstance(data, dict):
|
||||
raise SystemExit(0)
|
||||
|
||||
for teams in data.values():
|
||||
if not isinstance(teams, list):
|
||||
continue
|
||||
for team in teams:
|
||||
if not isinstance(team, dict):
|
||||
continue
|
||||
team_id = str(team.get("teamID", "")).strip()
|
||||
if not team_id:
|
||||
continue
|
||||
is_free = "1" if bool(team.get("isFreeProvisioningTeam", False)) else "0"
|
||||
team_name = str(team.get("teamName", "")).replace("\t", " ").strip()
|
||||
print(f"{team_id}\t{is_free}\t{team_name}")
|
||||
'
|
||||
)
|
||||
}
|
||||
|
||||
load_teams_from_legacy_defaults_key() {
|
||||
while IFS= read -r team; do
|
||||
[[ -z "$team" ]] && continue
|
||||
append_team "$team" "0" ""
|
||||
done < <(
|
||||
defaults read com.apple.dt.Xcode IDEProvisioningTeamIdentifiers 2>/dev/null \
|
||||
| grep -Eo '[A-Z0-9]{10}' || true
|
||||
)
|
||||
}
|
||||
|
||||
load_teams_from_xcode_preferences
|
||||
load_teams_from_legacy_defaults_key
|
||||
|
||||
if [[ ${#team_ids[@]} -eq 0 && "$allow_keychain_fallback" == "1" ]]; then
|
||||
while IFS= read -r team; do
|
||||
[[ -z "$team" ]] && continue
|
||||
append_team "$team" "0" ""
|
||||
done < <(
|
||||
security find-identity -p codesigning -v 2>/dev/null \
|
||||
| grep -Eo '\([A-Z0-9]{10}\)' \
|
||||
| tr -d '()' || true
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ ${#team_ids[@]} -eq 0 ]]; then
|
||||
if [[ "$allow_keychain_fallback" == "1" ]]; then
|
||||
echo "No Apple Team ID found. Open Xcode or install signing certificates first." >&2
|
||||
else
|
||||
echo "No Apple Team ID found in Xcode accounts. Open Xcode → Settings → Accounts and sign in, then retry." >&2
|
||||
echo "(Set IOS_ALLOW_KEYCHAIN_TEAM_FALLBACK=1 to allow keychain-only team detection.)" >&2
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$team_id"
|
||||
for i in "${!team_ids[@]}"; do
|
||||
if [[ "${team_ids[$i]}" == "$preferred_team" ]]; then
|
||||
printf '%s\n' "${team_ids[$i]}"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "$preferred_team_name" ]]; then
|
||||
preferred_team_name_lc="$(printf '%s' "$preferred_team_name" | tr '[:upper:]' '[:lower:]')"
|
||||
for i in "${!team_ids[@]}"; do
|
||||
team_name_lc="$(printf '%s' "${team_names[$i]}" | tr '[:upper:]' '[:lower:]')"
|
||||
if [[ "$team_name_lc" == "$preferred_team_name_lc" ]]; then
|
||||
printf '%s\n' "${team_ids[$i]}"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ "$prefer_non_free_team" == "1" ]]; then
|
||||
for i in "${!team_ids[@]}"; do
|
||||
if [[ "${team_is_free[$i]}" == "0" ]]; then
|
||||
printf '%s\n' "${team_ids[$i]}"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
printf '%s\n' "${team_ids[0]}"
|
||||
|
||||
Reference in New Issue
Block a user