Watch Connectivity

RSS for tag

Implement two-way communication between an iOS app and its paired watchOS app using Watch Connectivity.

Posts under Watch Connectivity tag

63 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Watch-Phone communication when Phone app is in background
There doesn't seem to be a background mode that will allow an iPhone app to run in the background in order to communicate with its watch app, which is running in the foreground on the watch. Have I missed something? Related but not quite the same: say the iPhone app can run in the background to get location updates. But it only wants to do so when the watch app is running. Is there a way that the watch app can wake, or even start, the iPhone app, and for the iPhone app to then enable location updates? (I have previously implemented Bluetooth background modes - I think I could achieve both of the above if I had the watch and the iPhone communicate using my own BTLE protocol, rather than using Watch Connectivity. Is this true?)
0
0
5
47m
Swift 6 concurrency. Apple Watch App target and -disable-dynamic-actor-isolation.
I've got a watch app, still with storyboard, WKInterfaceController and WatchConnectivity. After updating it for swift 6 concurrency I thought I'd keep it for a little while without swift 6 concurrency dynamic runtime check. So I added -disable-dynamic-actor-isolation in OTHER_SWIFT_FLAGS, but it doesn't seem to have an effect for the Apple Watch target. Without manually marking callbacks where needed with @Sendable in dynamic checks seem to be in place. swiftc invocation is as (includes -disable-dynamic-actor-isolation): swiftc -module-name GeoCameraWatchApp -Onone -enforce-exclusivity\=checked ... GeoCameraWatchApp.SwiftFileList -DDEBUG -enable-bridging-pch -disable-dynamic-actor-isolation -D DEBUG -enable-experimental-feature DebugDescriptionMacro -sdk /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS11.2.sdk -target arm64_32-apple-watchos7.0 -g -module-cache-path /Users/stand/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -Xfrontend -serialize-debugging-options -enable-testing -index-store-path /Users/stand/Library/Developer/Xcode/DerivedData/speedo-almhjmryctkitceaufvkvhkkfvdw/Index.noindex/DataStore -enable-experimental-feature OpaqueTypeErasure -Xcc -D_LIBCPP_HARDENING_MODE\=_LIBCPP_HARDENING_MODE_DEBUG -swift-version 6 ... -disable-dynamic-actor-isolation flag seems to be working for the iOS targets, I believe. The flag is described here Am I missing something? Should the flag work for both iOS and Apple Watch targets?
2
0
114
1d
Should WCSession.isPaired be true before checking WCSession.isWatchAppInstalled ?
I have a depended watch app bundled with my iOS app. // ... <key>WKRunsIndependentlyOfCompanionApp</key> <false/> // ... My code: guard WCSession.isSupported() else { return } let session = WCSession.default session.delegate = self session.activate() public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { // ... if (session.activationState == .activated) { let log = Log(isPaired: session.isPaired, isWatchAppInstalled: session.isWatchAppInstalled) uploadLogToServer(log) } // ... } and also: guard WCSession.isSupported() else { return } let session = WCSession.default guard session.activationState == .activated, session.isWatchAppInstalled else { return } do { try session.updateApplicationContext(...) } catch { uploadErrorToServer(error) } What I've observed is that when I query the logs in the server's database, I get entities with isPaired = false and isWatchAppInstalled = true. Also, when I query the errors I see deviceNotPaired errors. So my question is, does Should WCSession.isPaired property be true before accessing WCSession.isWatchAppInstalled property ?
1
0
187
2w
WatchConnectivity Swift 6 - Incorrect actor executor assumption
I am trying to migrate a WatchConnectivity App to Swift6 and I found an Issue with my replyHandler callback for sendMessageData. I am wrapping sendMessageData in withCheckedThrowingContinuation, so that I can await the response of the reply. I then update a Main Actor ObservableObject that keeps track of the count of connections that have not replied yet, before returning the data using continuation.resume. ... @preconcurrency import WatchConnectivity actor ConnectivityManager: NSObject, WCSessionDelegate { private var session: WCSession = .default private let connectivityMetaInfoManager: ConnectivityMetaInfoManager ... private func sendMessageData(_ data: Data) async throws -> Data? { Logger.shared.debug("called on Thread \(Thread.current)") await connectivityMetaInfoManager.increaseOpenSendConnectionsCount() return try await withCheckedThrowingContinuation({ continuation in self.session.sendMessageData( data, replyHandler: { data in Task { await self.connectivityMetaInfoManager .decreaseOpenSendConnectionsCount() } continuation.resume(returning: data) }, errorHandler: { (error) in Task { await self.connectivityMetaInfoManager .decreaseOpenSendConnectionsCount() } continuation.resume(throwing: error) } ) }) } Calling sendMessageData somehow causing the app to crash and display the debug message: Incorrect actor executor assumption. The code runs on swift 5 with SWIFT_STRICT_CONCURRENCY = complete. However when I switch to swift 6 the code crashes. I rebuilt a simple version of the App. Adding bit by bit until I was able to cause the crash. See Broken App Awaiting sendMessageData and wrapping it in a task and adding the @Sendable attribute to continuation, solve the crash. See Fixed App But I do not understand why yet. Is this intended behaviour? Should the compiler warn you about this? Is it a WatchConnectivity issue? I initially posted on forums.swift.org, but was told to repost here.
3
0
403
3w
Workout mode drains battery heavily
I am building a watchOS app with iOS companion app. The watch app needs to track the heart rate during the night or while user is sleeping. And the desired frequency of measurement is 0.2Hz (every 5 seconds) For this I am using the HKWorkout mode with mindAndBody session. While it works fine, One of the main issue is: after about 6-7 hours of usage, the battery on the watch drains between 40% (Series 9) and 100% (series 7, I think) My questions: Are there any other option to track user's heart rate without workout, while the app could be in background? Another side effect of this workout mode is, Even if we choose not to save the workout in HealthKit, the Activity rings gets populated by this mindAndBody session, which makes it when the user is waking up, the bar is already full, This is not desired. Is there any option to specify for ActivityRing skips this? Highly appreciate any help in advance. Cheers - Prakash
5
0
470
Dec ’24
SimpleWatchConnectivity sample - TransferFile fails
When launching the SimpleWatchConnectivity sample in a simulator (iOS 18.2 + watchOS 11.2), almost all the functionality works, but TransferFile does not work. The error is the following: -[WCFileStorage persistOutgoingFileTransfer:] error serializing file transfer <WCSessionFileTransfer: ...> due to Error Domain=NSCocoaErrorDomain Code=4866 "Caught exception during archival: This object may only be encoded by an NSXPCCoder." How can it be fixed or worked around?
1
0
252
Dec ’24
SimpleWatchConnectivity sample - modernizing it
Dear Experts, I have been looking at thr SimpleWatchConnectivity sample code: https://developer.apple.com/documentation/watchconnectivity/transferring-data-with-watch-connectivity There are a couple of things in there that look out of date. Firstly, it uses a WKApplicationDelegate to receive the background tasks. I believe this can probably be entirely removed, and replaced with .backgroundTask(.watchConnectivity) { ... } on the App. Is that true? What do I need something inside the { ... } there? Secondly, it is using NSNotificationCenter to send received data from the WCSessionDelegate to the SwiftUI view hierarchy. Is there a better way to do that? I have spent a while trying to work out how a WCSessionDelegate class can connect to a binding to a SwiftUI @State property, and cause the UI to update in response to received data, but I haven't made it work. Are there any newer examples of how to do this? I'm currently only trying to send some simple applicationContext state from the phone to the watch and have some views update to show the latest values. Thanks, Phil.
3
0
285
Dec ’24
watchOS app crashing on devices running watchOS 11+
We have a watchOS app in TestFlight that is currently crashing on any device running watchOS 11 and up. I have an older Apple Watch SE that's capped at 10.6.1 that can run the app just fine, but the same exact install on a newer device fails. This started happening after I updated my MacBook to macOS Sequoia and Xcode to 16. In order to get the Watch app to run on the 10.6.1 device, I had to change the Swift Optimization Level from -O to -Osize. I already filed Feedback on this (FB15691116). I've tried so many different things and have come up with nothing to show for it. When I look in the IPS file, I see that the crash point in my code on the watchOS 11 device is at KinesiaUOnWatch`@objc SessionDelegator.session(_:activationDidCompleteWith:error:): 0x3a3f48 <+0>: sub sp, sp, #0x60 0x3a3f4c <+4>: stp x26, x25, [sp, #0x10] 0x3a3f50 <+8>: stp x24, x23, [sp, #0x20] 0x3a3f54 <+12>: stp x22, x21, [sp, #0x30] 0x3a3f58 <+16>: stp x20, x19, [sp, #0x40] 0x3a3f5c <+20>: stp x29, x30, [sp, #0x50] 0x3a3f60 <+24>: add x29, sp, #0x50 0x3a3f64 <+28>: mov x19, x4 0x3a3f68 <+32>: mov x23, x2 0x3a3f6c <+36>: mov x22, x0 0x3a3f70 <+40>: mov w0, #0x0 ; =0 0x3a3f74 <+44>: bl 0x89818 ; symbol stub for: type metadata accessor for Swift.MainActor 0x3a3f78 <+48>: mov x24, x0 0x3a3f7c <+52>: adrp x25, 161 0x3a3f80 <+56>: ldr w25, [x25, #0x654] 0x3a3f84 <+60>: mov x20, x0 0x3a3f88 <+64>: bl 0x8980c ; symbol stub for: static Swift.MainActor.shared.getter : Swift.MainActor 0x3a3f8c <+68>: mov x21, x0 0x3a3f90 <+72>: adrp x0, 166 0x3a3f94 <+76>: add x0, x0, #0xc40 ; lazy protocol witness table cache variable for type Swift.MainActor and conformance Swift.MainActor : Swift.Actor in Swift Incident Identifier: 08E2F667-7965-4C86-B85E-9E2F03EAA963 Beta Identifier: AD390666-55CB-43B3-9B14-BD3E70F456EB Hardware Model: Watch6,1 Process: KinesiaUOnWatch [389] Path: /private/var/containers/Bundle/Application/B571E983-F2B0-40EF-9F0D-8C471CAEB3FB/KinesiaUOnWatch.app/KinesiaUOnWatch Identifier: com.glneurotech.kinesiau.watchapp Version: 5.1.0 (510271) AppStoreTools: 16B39 AppVariant: 1:Watch6,1:11 Beta: YES Code Type: ARM64_32 (Native) Role: Foreground Parent Process: launchd [1] Coalition: com.glneurotech.kinesiau.watchapp [464] Date/Time: 2024-12-03 15:12:51.1876 -0500 Launch Time: 2024-12-03 15:12:50.0000 -0500 OS Version: Watch OS 11.1 (22R585) Release Type: User Report Version: 104 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000002053dd4c Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [389] But, as I said, this exact app runs just fine on an older watchOS 10.6.1 device. Has anyone else encountered something like this, or have any ideas on stuff to try?
1
0
296
Dec ’24
WCSessionUserInfoTransfer. isTransferring can not be updated when transfer was completed
Hi, I am new to swift and IOS development, I was developing an app which can be used to communicating between Apple Watch and iPhone. Something strange occurred when I was trying to observe the status of the message(UserInfo) sent by func transferUserInfo(_ userInfo: [String : Any] = [:]) -> WCSessionUserInfoTransfer. I was trying to observe isTransferring(a boolean value) in WCSessionUserInfoTransfer which was returned by the function mentioned above, but it seems cannot be updated even if the message queue was empty, it seems to always be True. Here is my sample code: let transfer = session.transferUserInfo(message) if transfer.isTransferring { Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in print("Queued message count: \(self.session.outstandingUserInfoTransfers.count), isTransferring:\(transfer.isTransferring)") if !transfer.isTransferring { timer.invalidate() // irrelevant codes... } } } else { // other irrelevant codes... } Appreciate if anyone can help me out of this problem. Best wishes.
0
0
319
Nov ’24
Apple Watch 8 OS11.2 not synching my activity (intermittently)
My Apple Watch after the beta update is not syncing the activities sometimes with Apple Health. I just completed a 2.5 km walk, and it showed on Apple Health, yes, but it did not affect my daily goals. This is not the first time this has happened; this is just one of the examples that I'm sharing, other than what has been some problems that I am seeing after the beta update. Additionally, the camera remote app is not working correctly as I cannot see anything on the watch screen like I used to.
0
0
227
Nov ’24
HKWorkoutSession.sendToRemoteWorkoutSession doesn't report success or failure
We are seeing an issue where sending data using the asynchronous method HKWorkoutSession.sendToRemoteWorkoutSession(data: Data) will never return in some cases (no success nor failure). This issue is happening for roughly 5% of Workouts started and will stay broken for the whole workout. The other 95% of the workouts, the connection works flawlessly. This happens on both watchOS 10 and 11, and with phones running iOS 17 or 18. The issue is quite random and not reproducible. Our app has thousands of workouts a day that use the workout session workout data send, with constant messages being send every few seconds. In some of those 5% cases the "sendToRemoteWorkoutSession" will throw way later, like 30+ minutes later, if the watch app is awake long enough to capture a log of a failure. Our code uses the same flow as in the sample project: https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/building_a_multidevice_workout_app Here is some sample code, which is pretty simple. Setup code: let workoutSession = try HKWorkoutSession(healthStore: healthStore, configuration: configuration) workoutSession.delegate = self activeWorkoutSession?.startMirroringToCompanionDevice { success, error in print("Mirroring started on companion device: \(success), error: \(error)") } workoutSession?.prepare() then later we send data using the workout session: do { print("Will send data") try await workoutSession.sendToRemoteWorkoutSession(data: data) print("Successfully sent data") // This nor the error may be called after waiting extensive amounts of time } catch { print("Failed to send data, error: \(error)") // This nor the success may be called after waiting extensive amounts of time } So far, the only fix is to restart the phone and watch at the same time, which is not a great user experience. Is anyone else seeing this issue? or know how to fix this issue?
0
0
307
Nov ’24
Bring iOS app to foreground from Apple Watch app
Exploring Live Activity feature for Apple Watch right now and found that it has this default view with "Open on iPhone" button when you tap Live Activity. That button perfectly brings iOS app to foreground as if you tapped iOS's Live Activity. Is there a way to mimic that behavior from inside Watch app code? From inside WKApplicationDelegate, for example Tried openSystemURL but it seems lile it's only available for tel or sms links
1
0
327
Nov ’24
Standalone watch app design/approach for kids/family/shared watches paired with parents' phones
Hi, so, we grabbed a couple of nice new watches the other week (Ultra for dad, SE for teenage son). Mostly cool and working together (calls, messages, maps, walkie talkies, etc, etc). All good. But then son said, "Dad, why can't I see my sleep stuff like you can..?". He was right, it wasn't working. Looking around a bit, it turns out that there are a bunch of things that are turned off or not available when pairing a kids watch with dad's phone. From the Apple page: "The following features and apps are not available: Medications, respiratory rate, irregular heart rhythm notifications, ECG, AF History, Cycle Tracking, Sleep, Wrist Temperature, Blood Oxygen, Walking Steadiness, Audiobooks, Remote, News, Shortcuts and the double-tap gesture". Now dev-me reacts to this situation with: "Ok, so let's just build a little standalone sleep app for son's watch. There must be lots of parents out there who would like the same thing". And there are also a bunch of other "family sharing" enabled apps that when you try and use them on kid's phone, say "iPhone requireed", i.e, they don't apparently work with just a watch hooked up to mum or dad's phone. So before I dive into that kind of project, which seems like an obvious fix path from a dev and a parents' point of view: does anybody know if this from Apple's point of view is a hardware, a software or a legal/age limitation? What's the basic framework/dev/design issue here? Is it something on the device(s) that prevents sleep data from even being collected on family/kids paired watches? (Therefore don't bother trying to build an app); I assume not becauses it's just a normal SE used by a kid; or Is it "just" that Apple hasn't wanted to make that available without a kids iPhone too (Therefore you could certainly build a standalone app to do what Apple hasn't wanted to do); or Netiher 1 nor 2, but Apple won't even allow Sleep data collection for kids for some legal/health data reason (Therefore don't bother trying to build the app).
0
1
306
Oct ’24
Casting `[String: Any]` to `[String: any Sendable]`
I have a simple wrapper class around WCSession to allow for easier unit testing. I'm trying to update it to Swift 6 concurrency standards, but running into some issues. One of them is in the sendMessage function (docs here It takes [String: Any] as a param, and returns them as the reply. Here's my code that calls this: @discardableResult public func sendMessage(_ message: [String: Any]) async throws -&gt; [String: Any] { return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation&lt;[String: Any], Error&gt;) in wcSession.sendMessage(message) { response in continuation.resume(returning: response) // ERROR HERE } errorHandler: { error in continuation.resume(throwing: error) } } } However, I get this error: Sending 'response' risks causing data races; this is an error in the Swift 6 language mode Which I think is because Any is not Sendable. I tried casting [String: Any] to [String: any Sendable] but then it says: Conditional cast from '[String : Any]' to '[String : any Sendable]' always succeeds Any ideas on how to get this to work?
3
1
647
Oct ’24