diff --git a/apps/ios/Sources/Bridge/BridgeConnectionController.swift b/apps/ios/Sources/Bridge/BridgeConnectionController.swift
index 6d56ba515..75b1162bb 100644
--- a/apps/ios/Sources/Bridge/BridgeConnectionController.swift
+++ b/apps/ios/Sources/Bridge/BridgeConnectionController.swift
@@ -115,7 +115,7 @@ final class BridgeConnectionController {
self.didAutoConnect = true
let endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(manualHost), port: port)
- self.startAutoConnect(endpoint: endpoint, token: token, instanceId: instanceId)
+ self.startAutoConnect(endpoint: endpoint, bridgeStableID: nil, token: token, instanceId: instanceId)
return
}
@@ -132,7 +132,11 @@ final class BridgeConnectionController {
guard let target = self.bridges.first(where: { $0.stableID == targetStableID }) else { return }
self.didAutoConnect = true
- self.startAutoConnect(endpoint: target.endpoint, token: token, instanceId: instanceId)
+ self.startAutoConnect(
+ endpoint: target.endpoint,
+ bridgeStableID: target.stableID,
+ token: token,
+ instanceId: instanceId)
}
private func updateLastDiscoveredBridge(from bridges: [BridgeDiscoveryModel.DiscoveredBridge]) {
@@ -171,7 +175,12 @@ final class BridgeConnectionController {
"bridge-token.\(instanceId)"
}
- private func startAutoConnect(endpoint: NWEndpoint, token: String, instanceId: String) {
+ private func startAutoConnect(
+ endpoint: NWEndpoint,
+ bridgeStableID: String?,
+ token: String,
+ instanceId: String)
+ {
guard let appModel else { return }
Task { [weak self] in
guard let self else { return }
@@ -192,7 +201,10 @@ final class BridgeConnectionController {
service: "com.clawdbot.bridge",
account: self.keychainAccount(instanceId: instanceId))
}
- appModel.connectToBridge(endpoint: endpoint, hello: self.makeHello(token: resolvedToken))
+ appModel.connectToBridge(
+ endpoint: endpoint,
+ bridgeStableID: bridgeStableID,
+ hello: self.makeHello(token: resolvedToken))
} catch {
await MainActor.run {
appModel.bridgeStatusText = "Bridge error: \(error.localizedDescription)"
diff --git a/apps/ios/Sources/Info.plist b/apps/ios/Sources/Info.plist
index 63f2cc5c7..d194430b8 100644
--- a/apps/ios/Sources/Info.plist
+++ b/apps/ios/Sources/Info.plist
@@ -35,10 +35,10 @@
Clawdbot can capture photos or short video clips when requested via the bridge.
NSLocalNetworkUsageDescription
Clawdbot discovers and connects to your Clawdbot bridge on the local network.
- NSLocationWhenInUseUsageDescription
- Clawdbot uses your location when you allow location sharing.
NSLocationAlwaysAndWhenInUseUsageDescription
Clawdbot can share your location in the background when you enable Always.
+ NSLocationWhenInUseUsageDescription
+ Clawdbot uses your location when you allow location sharing.
NSMicrophoneUsageDescription
Clawdbot needs microphone access for voice wake.
NSSpeechRecognitionUsageDescription
diff --git a/apps/ios/Sources/Model/NodeAppModel.swift b/apps/ios/Sources/Model/NodeAppModel.swift
index 080b10f16..2e61d0be4 100644
--- a/apps/ios/Sources/Model/NodeAppModel.swift
+++ b/apps/ios/Sources/Model/NodeAppModel.swift
@@ -204,12 +204,14 @@ final class NodeAppModel {
func connectToBridge(
endpoint: NWEndpoint,
+ bridgeStableID: String? = nil,
hello: BridgeHello)
{
self.bridgeTask?.cancel()
self.bridgeServerName = nil
self.bridgeRemoteAddress = nil
- self.connectedBridgeID = BridgeEndpointID.stableID(endpoint)
+ let id = (bridgeStableID ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
+ self.connectedBridgeID = id.isEmpty ? BridgeEndpointID.stableID(endpoint) : id
self.voiceWakeSyncTask?.cancel()
self.voiceWakeSyncTask = nil
diff --git a/apps/ios/Sources/Settings/SettingsTab.swift b/apps/ios/Sources/Settings/SettingsTab.swift
index fd37c8d5d..c1af2632c 100644
--- a/apps/ios/Sources/Settings/SettingsTab.swift
+++ b/apps/ios/Sources/Settings/SettingsTab.swift
@@ -425,6 +425,7 @@ struct SettingsTab: View {
self.appModel.connectToBridge(
endpoint: bridge.endpoint,
+ bridgeStableID: bridge.stableID,
hello: BridgeHello(
nodeId: self.instanceId,
displayName: self.displayName,
@@ -499,6 +500,7 @@ struct SettingsTab: View {
self.appModel.connectToBridge(
endpoint: endpoint,
+ bridgeStableID: nil,
hello: BridgeHello(
nodeId: self.instanceId,
displayName: self.displayName,
diff --git a/apps/ios/Tests/BridgeConnectionControllerTests.swift b/apps/ios/Tests/BridgeConnectionControllerTests.swift
index fd9422ff0..b78844b70 100644
--- a/apps/ios/Tests/BridgeConnectionControllerTests.swift
+++ b/apps/ios/Tests/BridgeConnectionControllerTests.swift
@@ -175,7 +175,6 @@ private func withKeychainValues(
}
@Test @MainActor func makeHelloBuildsCapsAndCommands() {
- let defaults = UserDefaults.standard
let voiceWakeKey = VoiceWakePreferences.enabledKey
withKeychainValues([instanceIdEntry: nil, preferredBridgeEntry: nil, lastBridgeEntry: nil]) {
diff --git a/apps/ios/project.yml b/apps/ios/project.yml
index 7d10f5ed0..8341cde48 100644
--- a/apps/ios/project.yml
+++ b/apps/ios/project.yml
@@ -5,6 +5,10 @@ options:
iOS: "17.0"
xcodeVersion: "16.0"
+settings:
+ base:
+ SWIFT_VERSION: "6.0"
+
packages:
ClawdbotKit:
path: ../shared/ClawdbotKit
@@ -68,11 +72,15 @@ targets:
PRODUCT_BUNDLE_IDENTIFIER: com.clawdbot.ios
PROVISIONING_PROFILE_SPECIFIER: "com.clawdbot.ios Development"
SWIFT_VERSION: "6.0"
+ SWIFT_STRICT_CONCURRENCY: complete
+ ENABLE_APPINTENTS_METADATA: NO
info:
path: Sources/Info.plist
properties:
CFBundleDisplayName: Clawdbot
CFBundleIconName: AppIcon
+ CFBundleShortVersionString: "2026.1.9"
+ CFBundleVersion: "20260109"
UILaunchScreen: {}
UIApplicationSceneManifest:
UIApplicationSupportsMultipleScenes: false
@@ -84,8 +92,20 @@ targets:
NSBonjourServices:
- _clawdbot-bridge._tcp
NSCameraUsageDescription: Clawdbot can capture photos or short video clips when requested via the bridge.
+ NSLocationWhenInUseUsageDescription: Clawdbot uses your location when you allow location sharing.
+ NSLocationAlwaysAndWhenInUseUsageDescription: Clawdbot can share your location in the background when you enable Always.
NSMicrophoneUsageDescription: Clawdbot needs microphone access for voice wake.
NSSpeechRecognitionUsageDescription: Clawdbot uses on-device speech recognition for voice wake.
+ UISupportedInterfaceOrientations:
+ - UIInterfaceOrientationPortrait
+ - UIInterfaceOrientationPortraitUpsideDown
+ - UIInterfaceOrientationLandscapeLeft
+ - UIInterfaceOrientationLandscapeRight
+ UISupportedInterfaceOrientations~ipad:
+ - UIInterfaceOrientationPortrait
+ - UIInterfaceOrientationPortraitUpsideDown
+ - UIInterfaceOrientationLandscapeLeft
+ - UIInterfaceOrientationLandscapeRight
ClawdbotTests:
type: bundle.unit-test
@@ -96,13 +116,17 @@ targets:
- target: Clawdbot
- package: Swabble
product: SwabbleKit
+ - sdk: AppIntents.framework
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: com.clawdbot.ios.tests
SWIFT_VERSION: "6.0"
+ SWIFT_STRICT_CONCURRENCY: complete
TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Clawdbot.app/Clawdbot"
BUNDLE_LOADER: "$(TEST_HOST)"
info:
path: Tests/Info.plist
properties:
CFBundleDisplayName: ClawdbotTests
+ CFBundleShortVersionString: "2026.1.9"
+ CFBundleVersion: "20260109"