diff --git a/apps/ios/.periphery.yml b/apps/ios/.periphery.yml
index e9156a8170cb..d8aca1812330 100644
--- a/apps/ios/.periphery.yml
+++ b/apps/ios/.periphery.yml
@@ -12,7 +12,7 @@ report_include:
- Sources/**
- ShareExtension/**
- ActivityWidget/**
- - WatchExtension/Sources/**
+ - WatchApp/Sources/**
build_arguments:
- -destination
- generic/platform=iOS Simulator
diff --git a/apps/ios/Config/AppStoreSigning.json b/apps/ios/Config/AppStoreSigning.json
index 00e1bf920dee..a884f95a6ee4 100644
--- a/apps/ios/Config/AppStoreSigning.json
+++ b/apps/ios/Config/AppStoreSigning.json
@@ -39,15 +39,6 @@
"profileKey": "OPENCLAW_WATCH_APP_PROFILE",
"profileName": "OpenClaw App Store ai.openclawfoundation.app.watchkitapp",
"capabilities": []
- },
- {
- "target": "OpenClawWatchExtension",
- "displayName": "OpenClaw Watch Extension",
- "bundleId": "ai.openclawfoundation.app.watchkitapp.extension",
- "platform": "IOS",
- "profileKey": "OPENCLAW_WATCH_EXTENSION_PROFILE",
- "profileName": "OpenClaw App Store ai.openclawfoundation.app.watchkitapp.extension",
- "capabilities": []
}
]
}
diff --git a/apps/ios/Config/Signing.xcconfig b/apps/ios/Config/Signing.xcconfig
index ae945ffe9599..b515822f1d9e 100644
--- a/apps/ios/Config/Signing.xcconfig
+++ b/apps/ios/Config/Signing.xcconfig
@@ -8,11 +8,9 @@ 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
OPENCLAW_ACTIVITY_WIDGET_BUNDLE_ID = ai.openclawfoundation.app.activitywidget
OPENCLAW_ACTIVITY_WIDGET_PROFILE =
OPENCLAW_WATCH_APP_PROFILE =
-OPENCLAW_WATCH_EXTENSION_PROFILE =
// Local contributors can override this by running scripts/ios-configure-signing.sh.
// Keep include after defaults: xcconfig is evaluated top-to-bottom.
diff --git a/apps/ios/LocalSigning.xcconfig.example b/apps/ios/LocalSigning.xcconfig.example
index 1eb12be9fc4c..e7db6c2e52a2 100644
--- a/apps/ios/LocalSigning.xcconfig.example
+++ b/apps/ios/LocalSigning.xcconfig.example
@@ -9,11 +9,9 @@ OPENCLAW_APP_BUNDLE_ID = ai.openclawfoundation.app
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
// Leave empty with automatic signing.
OPENCLAW_APP_PROFILE =
OPENCLAW_SHARE_PROFILE =
OPENCLAW_ACTIVITY_WIDGET_PROFILE =
OPENCLAW_WATCH_APP_PROFILE =
-OPENCLAW_WATCH_EXTENSION_PROFILE =
diff --git a/apps/ios/README.md b/apps/ios/README.md
index 1f187bfc5d51..148309559788 100644
--- a/apps/ios/README.md
+++ b/apps/ios/README.md
@@ -155,7 +155,6 @@ This should create `apps/ios/fastlane/.env` with non-secret App Store Connect va
- `ai.openclawfoundation.app.share`
- `ai.openclawfoundation.app.activitywidget`
- `ai.openclawfoundation.app.watchkitapp`
- - `ai.openclawfoundation.app.watchkitapp.extension`
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.
diff --git a/apps/ios/Signing.xcconfig b/apps/ios/Signing.xcconfig
index 7079f35f765e..d98da9d40174 100644
--- a/apps/ios/Signing.xcconfig
+++ b/apps/ios/Signing.xcconfig
@@ -11,7 +11,6 @@ OPENCLAW_DEVELOPMENT_TEAM = FWJYW4S8P8
OPENCLAW_APP_BUNDLE_ID = ai.openclawfoundation.app
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
@@ -19,7 +18,6 @@ OPENCLAW_APP_PROFILE = ai.openclawfoundation.app Development
OPENCLAW_SHARE_PROFILE = ai.openclawfoundation.app.share Development
OPENCLAW_ACTIVITY_WIDGET_PROFILE =
OPENCLAW_WATCH_APP_PROFILE =
-OPENCLAW_WATCH_EXTENSION_PROFILE =
// Keep local includes after defaults: xcconfig is evaluated top-to-bottom,
// so later assignments in local files override the defaults above.
diff --git a/apps/ios/SwiftSources.input.xcfilelist b/apps/ios/SwiftSources.input.xcfilelist
index bcf39f7ad0bf..967286e17f62 100644
--- a/apps/ios/SwiftSources.input.xcfilelist
+++ b/apps/ios/SwiftSources.input.xcfilelist
@@ -109,10 +109,10 @@ Sources/Voice/VoiceWakePreferences.swift
ShareExtension/ShareViewController.swift
ActivityWidget/OpenClawActivityWidgetBundle.swift
ActivityWidget/OpenClawLiveActivity.swift
-WatchExtension/Sources/OpenClawWatchApp.swift
-WatchExtension/Sources/WatchConnectivityReceiver.swift
-WatchExtension/Sources/WatchInboxStore.swift
-WatchExtension/Sources/WatchInboxView.swift
+WatchApp/Sources/OpenClawWatchApp.swift
+WatchApp/Sources/WatchConnectivityReceiver.swift
+WatchApp/Sources/WatchInboxStore.swift
+WatchApp/Sources/WatchInboxView.swift
../shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift
../shared/OpenClawKit/Sources/OpenClawChatUI/ChatMarkdownRenderer.swift
../shared/OpenClawKit/Sources/OpenClawChatUI/ChatMarkdownPreprocessor.swift
diff --git a/apps/ios/WatchExtension/Assets.xcassets/OpenClawIcon.imageset/Contents.json b/apps/ios/WatchApp/Assets.xcassets/OpenClawIcon.imageset/Contents.json
similarity index 100%
rename from apps/ios/WatchExtension/Assets.xcassets/OpenClawIcon.imageset/Contents.json
rename to apps/ios/WatchApp/Assets.xcassets/OpenClawIcon.imageset/Contents.json
diff --git a/apps/ios/WatchExtension/Assets.xcassets/OpenClawIcon.imageset/openclaw-icon.png b/apps/ios/WatchApp/Assets.xcassets/OpenClawIcon.imageset/openclaw-icon.png
similarity index 100%
rename from apps/ios/WatchExtension/Assets.xcassets/OpenClawIcon.imageset/openclaw-icon.png
rename to apps/ios/WatchApp/Assets.xcassets/OpenClawIcon.imageset/openclaw-icon.png
diff --git a/apps/ios/WatchApp/Info.plist b/apps/ios/WatchApp/Info.plist
index 3eea1e6ff090..13de3b357019 100644
--- a/apps/ios/WatchApp/Info.plist
+++ b/apps/ios/WatchApp/Info.plist
@@ -20,9 +20,9 @@
$(OPENCLAW_MARKETING_VERSION)
CFBundleVersion
$(OPENCLAW_BUILD_VERSION)
+ WKApplication
+
WKCompanionAppBundleIdentifier
$(OPENCLAW_APP_BUNDLE_ID)
- WKWatchKitApp
-
diff --git a/apps/ios/WatchExtension/Sources/OpenClawWatchApp.swift b/apps/ios/WatchApp/Sources/OpenClawWatchApp.swift
similarity index 100%
rename from apps/ios/WatchExtension/Sources/OpenClawWatchApp.swift
rename to apps/ios/WatchApp/Sources/OpenClawWatchApp.swift
diff --git a/apps/ios/WatchExtension/Sources/WatchConnectivityReceiver.swift b/apps/ios/WatchApp/Sources/WatchConnectivityReceiver.swift
similarity index 100%
rename from apps/ios/WatchExtension/Sources/WatchConnectivityReceiver.swift
rename to apps/ios/WatchApp/Sources/WatchConnectivityReceiver.swift
diff --git a/apps/ios/WatchExtension/Sources/WatchInboxStore.swift b/apps/ios/WatchApp/Sources/WatchInboxStore.swift
similarity index 100%
rename from apps/ios/WatchExtension/Sources/WatchInboxStore.swift
rename to apps/ios/WatchApp/Sources/WatchInboxStore.swift
diff --git a/apps/ios/WatchExtension/Sources/WatchInboxView.swift b/apps/ios/WatchApp/Sources/WatchInboxView.swift
similarity index 100%
rename from apps/ios/WatchExtension/Sources/WatchInboxView.swift
rename to apps/ios/WatchApp/Sources/WatchInboxView.swift
diff --git a/apps/ios/WatchExtension/Assets.xcassets/Contents.json b/apps/ios/WatchExtension/Assets.xcassets/Contents.json
deleted file mode 100644
index 74d6a722cf39..000000000000
--- a/apps/ios/WatchExtension/Assets.xcassets/Contents.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "info": {
- "author": "xcode",
- "version": 1
- }
-}
diff --git a/apps/ios/WatchExtension/Info.plist b/apps/ios/WatchExtension/Info.plist
deleted file mode 100644
index 873130649456..000000000000
--- a/apps/ios/WatchExtension/Info.plist
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- OpenClaw
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundleShortVersionString
- $(OPENCLAW_MARKETING_VERSION)
- CFBundleVersion
- $(OPENCLAW_BUILD_VERSION)
- NSExtension
-
- NSExtensionAttributes
-
- WKAppBundleIdentifier
- $(OPENCLAW_WATCH_APP_BUNDLE_ID)
-
- NSExtensionPointIdentifier
- com.apple.watchkit
-
-
-
diff --git a/apps/ios/fastlane/Fastfile b/apps/ios/fastlane/Fastfile
index 7a6941eecfc3..40024a9032c7 100644
--- a/apps/ios/fastlane/Fastfile
+++ b/apps/ios/fastlane/Fastfile
@@ -293,6 +293,8 @@ def capture_watch_screenshot
Dir[File.join(output_dir, "Apple Watch*-*.png")].each { |path| FileUtils.rm_f(path) }
FileUtils.rm_rf(derived_data_path)
+ # Single-target watch apps only expose generic simulator build destinations in Xcode.
+ # Keep the selected UDID for install/launch/screenshot below.
sh(
xcodebuild_shell_join([
"xcodebuild",
@@ -303,7 +305,7 @@ def capture_watch_screenshot
"-configuration",
"Debug",
"-destination",
- "platform=watchOS Simulator,id=#{udid}",
+ "generic/platform=watchOS Simulator",
"-derivedDataPath",
derived_data_path,
"build",
@@ -311,10 +313,8 @@ def capture_watch_screenshot
)
UI.user_error!("Watch screenshot build did not produce #{app_path}.") unless File.exist?(app_path)
- extension_path = File.join(app_path, "PlugIns", "OpenClawWatchExtension.appex")
watch_app_identifier = bundle_identifier_for_product(app_path)
- watch_extension_identifier = bundle_identifier_for_product(extension_path)
- screenshot_mode_bundle_identifiers = [watch_app_identifier, watch_extension_identifier]
+ screenshot_mode_bundle_identifiers = [watch_app_identifier]
sh("#{shell_join(["xcrun", "simctl", "boot", udid])} >/dev/null 2>&1 || true")
sh(shell_join(["xcrun", "simctl", "bootstatus", udid, "-b"]))
diff --git a/apps/ios/project.yml b/apps/ios/project.yml
index f3bfc0f6a223..75584d9fea4e 100644
--- a/apps/ios/project.yml
+++ b/apps/ios/project.yml
@@ -88,7 +88,7 @@ targets:
exit 1
fi
swiftformat --lint --config "$SRCROOT/../../config/swiftformat" \
- --unexclude "$SRCROOT/Sources,$SRCROOT/ShareExtension,$SRCROOT/ActivityWidget,$SRCROOT/WatchExtension,$SRCROOT/../shared/OpenClawKit,$SRCROOT/../swabble" \
+ --unexclude "$SRCROOT/Sources,$SRCROOT/ShareExtension,$SRCROOT/ActivityWidget,$SRCROOT/WatchApp,$SRCROOT/../shared/OpenClawKit,$SRCROOT/../swabble" \
--filelist "$SRCROOT/SwiftSources.input.xcfilelist"
- name: SwiftLint
basedOnDependencyAnalysis: false
@@ -251,13 +251,17 @@ targets:
NSExtensionPointIdentifier: com.apple.widgetkit-extension
OpenClawWatchApp:
- type: application.watchapp2
+ type: application
platform: watchOS
deploymentTarget: "11.0"
sources:
- path: WatchApp
+ excludes:
+ - Info.plist
dependencies:
- - target: OpenClawWatchExtension
+ - sdk: AppIntents.framework
+ - sdk: WatchConnectivity.framework
+ - sdk: UserNotifications.framework
configFiles:
Debug: Config/Signing.xcconfig
Release: Config/Signing.xcconfig
@@ -274,6 +278,12 @@ targets:
ENABLE_APP_INTENTS_METADATA_GENERATION: NO
PRODUCT_BUNDLE_IDENTIFIER: "$(OPENCLAW_WATCH_APP_BUNDLE_ID)"
PROVISIONING_PROFILE_SPECIFIER: "$(OPENCLAW_WATCH_APP_PROFILE)"
+ SWIFT_STRICT_CONCURRENCY: complete
+ SWIFT_VERSION: "6.0"
+ configs:
+ Debug:
+ ARCHS: "$(NATIVE_ARCH_ACTUAL)"
+ ONLY_ACTIVE_ARCH: YES
info:
path: WatchApp/Info.plist
properties:
@@ -281,42 +291,7 @@ targets:
CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
WKCompanionAppBundleIdentifier: "$(OPENCLAW_APP_BUNDLE_ID)"
- WKWatchKitApp: true
-
- OpenClawWatchExtension:
- type: watchkit2-extension
- platform: watchOS
- deploymentTarget: "11.0"
- sources:
- - path: WatchExtension/Sources
- - path: WatchExtension/Assets.xcassets
- dependencies:
- - sdk: AppIntents.framework
- - sdk: WatchConnectivity.framework
- - sdk: UserNotifications.framework
- configFiles:
- Debug: Config/Signing.xcconfig
- Release: Config/Signing.xcconfig
- attributes:
- DevelopmentTeam: "$(OPENCLAW_DEVELOPMENT_TEAM)"
- ProvisioningStyle: "$(OPENCLAW_CODE_SIGN_STYLE)"
- settings:
- base:
- 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)"
- PROVISIONING_PROFILE_SPECIFIER: "$(OPENCLAW_WATCH_EXTENSION_PROFILE)"
- info:
- path: WatchExtension/Info.plist
- properties:
- CFBundleDisplayName: OpenClaw
- CFBundleShortVersionString: "$(OPENCLAW_MARKETING_VERSION)"
- CFBundleVersion: "$(OPENCLAW_BUILD_VERSION)"
- NSExtension:
- NSExtensionAttributes:
- WKAppBundleIdentifier: "$(OPENCLAW_WATCH_APP_BUNDLE_ID)"
- NSExtensionPointIdentifier: com.apple.watchkit
+ WKApplication: true
OpenClawTests:
type: bundle.unit-test
diff --git a/scripts/ios-configure-signing.sh b/scripts/ios-configure-signing.sh
index 0ee4e5cd5b74..b5dd1e2b33ef 100755
--- a/scripts/ios-configure-signing.sh
+++ b/scripts/ios-configure-signing.sh
@@ -70,7 +70,6 @@ bundle_base="$(normalize_bundle_id "${bundle_base}")"
share_bundle_id="${OPENCLAW_IOS_SHARE_BUNDLE_ID:-${bundle_base}.share}"
activity_widget_bundle_id="${OPENCLAW_IOS_ACTIVITY_WIDGET_BUNDLE_ID:-${bundle_base}.activitywidget}"
watch_app_bundle_id="${OPENCLAW_IOS_WATCH_APP_BUNDLE_ID:-${bundle_base}.watchkitapp}"
-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}"
@@ -79,7 +78,6 @@ app_profile="${OPENCLAW_IOS_APP_PROFILE:-}"
share_profile="${OPENCLAW_IOS_SHARE_PROFILE:-}"
activity_widget_profile="${OPENCLAW_IOS_ACTIVITY_WIDGET_PROFILE:-}"
watch_app_profile="${OPENCLAW_IOS_WATCH_APP_PROFILE:-}"
-watch_extension_profile="${OPENCLAW_IOS_WATCH_EXTENSION_PROFILE:-}"
tmp_file="$(mktemp "${TMPDIR:-/tmp}/openclaw-ios-configure-signing.XXXXXX")"
cat >"${tmp_file}" <"${tmp_file}" < {
expect(output).toContain(
"OPENCLAW_WATCH_APP_PROFILE = OpenClaw App Store ai.openclawfoundation.app.watchkitapp",
);
- expect(output).toContain(
- "OPENCLAW_WATCH_EXTENSION_PROFILE = OpenClaw App Store ai.openclawfoundation.app.watchkitapp.extension",
- );
+ expect(output).not.toContain("OPENCLAW_WATCH_EXTENSION_PROFILE");
});
it("documents the canonical release signing plan", () => {
@@ -40,9 +38,7 @@ describe("scripts/ios-release-signing.mjs", () => {
expect(output).toContain("Signing repo: git@github.com:openclaw/apps-signing.git");
expect(output).toContain("Signing branch: main");
expect(output).toContain("Signing setup and sync: Fastlane match");
- expect(output).toContain(
- "OpenClawWatchExtension: ai.openclawfoundation.app.watchkitapp.extension",
- );
+ expect(output).not.toContain("OpenClawWatchExtension");
expect(output).toContain("capabilities: PUSH_NOTIFICATIONS");
});
});