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"