watchOS is the operating system for Apple Watch.

watchOS Documentation

Posts under watchOS tag

415 Posts
Sort by:
Post not yet marked as solved
3 Replies
1k Views
With the new interactive widgets brought by iOS 17, is it possible to indicate that an action (button tap or toggle use) has been triggered by firing an Haptic feedback to the user?
Posted
by Clem23.
Last updated
.
Post not yet marked as solved
0 Replies
139 Views
I noticied that my workout session is sometimes being killed by apple when the app is in the background and it seems that the func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) { is only being called when the app comes back into the foreground. I wonder if there is a way for us to get notified when the workout is about to die or has already been killed. Thanks
Posted Last updated
.
Post not yet marked as solved
1 Replies
1.9k Views
I recently raised this post explaining how I couldn't seem to get watchOS 9 complications to work, and I've figured out a partial fix. The original post details the issues with complications - and some are still valid - but this fix applies to both my complications and Home Screen / Lock Screen widgets. I was following the various WWDC 2020/2022 videos and the Emoji Rangers sample code, adding bits here and there, and assuming they were completely valid. Sadly, this bit of code in the widget's dynamic intents IntentTimelineProvider getTimeline really just banjaxed everything: // Create entries for one day, 15 minutes apart let currentDate = Date() for minuteOffset in stride(from: 0, to: 60 * 60 * 24, by: 15) { let entryDate = Calendar.current.date(byAdding: .minute, value: minuteOffset, to: currentDate)! entries.append(EventEntry(date: entryDate, event: event)) } If I remove that, and generate a different timeline with specific dates and times (for example: now, in 10 mins, in 2 hours, in a day, etc.) the complications appear correctly, as do Home Screen and Lock Screen widgets. The outstanding issues with complications are: The previews all use the same data, but getSnapshot() is supposed to return the data specific to that event from the configuration, i.e. if let theId = configuration.event?.identifier. "Christmas" is correct, but "Gallery Opening" is using Christmas's data. Once I've selected the event I want to use in a complication the edit screen shows it as totally blank, not even a placeholder: I hope this little fix works for you guys. And, if you know how to fix the above issues, let me know. (iOS 16.1 beta 1, Xcode 14.1 beta 1)
Posted
by darkpaw.
Last updated
.
Post not yet marked as solved
2 Replies
240 Views
Hi, I have a watchOS app that records audio for an extended period of time and because the mic is active, continues to record in background mode when the watch face is off. However, when a call comes in or Siri is activated, recording stops because of an audio interruption. Here is my code for setting up the session: private func setupAudioSession() { let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(.playAndRecord, mode: .default, options: [.overrideMutedMicrophoneInterruption]) try audioSession.setActive(true, options: .notifyOthersOnDeactivation) } catch { print("Audio Session error: \(error)") } } Before this I register an interruption handler that holds a reference to my AudioEngine (which I start and stop each time recording is activated by the user): _audioInterruptionHandler = AudioInterruptionHandler(audioEngine: _audioEngine) And here is how this class implements recovery: fileprivate class AudioInterruptionHandler { private let _audioEngine: AVAudioEngine public init(audioEngine: AVAudioEngine) { _audioEngine = audioEngine // Listen to interrupt notifications NotificationCenter.default.addObserver(self, selector: #selector(handleAudioInterruption(notification:)), name: AVAudioSession.interruptionNotification, object: nil) } @objc private func handleAudioInterruption(notification: Notification) { guard let userInfo = notification.userInfo, let interruptionTypeRawValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt, let interruptionType = AVAudioSession.InterruptionType(rawValue: interruptionTypeRawValue) else { return } switch interruptionType { case .began: print("[AudioInterruptionHandler] Interruption began") case .ended: print("[AudioInterruptionHandler] Interruption ended") print("Interruption ended") do { try AVAudioSession.sharedInstance().setActive(true) } catch { print("[AudioInterruptionHandler] Error resuming audio session: \(error.localizedDescription)") } default: print("[AudioInterruptionHandler] Unknown interruption: \(interruptionType.rawValue)") } } } Unfortunately, it fails with: Error resuming audio session: Session activation failed Is this even possible to do on watchOS? This code worked for me on iOS. Thank you, -- B.
Posted
by trzy.
Last updated
.
Post not yet marked as solved
3 Replies
614 Views
Hello I have been using apple products for quite some time now and am also updating my phone with latest beta software updates for watch, airpods 2 etc. Recently, I have started facing an irritating issue - I am unable to control the volume via my apple watch crown for music playing on youtube music / spotify etc. Earlier while operating the watch crown, I could lower/increase the volume of the music/videos on the "Now Playing" screen on the watch. But with recent updates its not happening. Please advise. TIA! Software versions: iphone - ios 17.4 apple watch 8 - watchOS 10.4
Posted Last updated
.
Post not yet marked as solved
2 Replies
278 Views
Good morning, I come to you for a question: When I install my application on my iPhone for the first time, and I install the watch application from the native "Watch" application, the Watch Connectivity function does not work, I have to do the installation from Xcode to the watch for this function to work. Is this normal? if yes, the problem will not arise during a publication? I have the same problem when using watch and iPhone simulators, WatchConnectivity does not work. I am this error code in Xcode: -[WCSession handleIncomingUserInfoWithPairingID:]_block_invoke delegate (null) does not implement session:didReceiveUserInfo:, discarding incoming content Here is the code for the iPhone and the watch: In my iPhone app: import WatchConnectivity let userDefaultsDataVenantWatch = UserDefaults.standard class PhoneDataModel : NSObject, WCSessionDelegate, ObservableObject { static let shared = PhoneDataModel() let session = WCSession.default @Published var TableauSynchroIphoneVersWatch : [String:String] = ["0":"0"] @Published var dataWatchVersIphone: [String:String] = ["":""] override init() { super.init() if WCSession.isSupported() { session.delegate = self session.activate() } else { print("ERROR: Watch session not supported") } } func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { if let error = error { print("session activation failed with error: \(error.localizedDescription)") return } } func sessionDidBecomeInactive(_ session: WCSession) { session.activate() } func sessionDidDeactivate(_ session: WCSession) { session.activate() } func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any]) { guard let newCount = userInfo["TableauSynchroIphoneWatch"] as? [String:String] else { print("ERROR: unknown data received from Watch TableauSynchroIphoneWatch") return } DispatchQueue.main.async { print(newCount) } } } In my Watch app: import WatchConnectivity let userDefaultsDataVenantIphone = UserDefaults.standard var TableauVenantIphone:[String:String] = ["":""] class WatchDataModel : NSObject, WCSessionDelegate, ObservableObject { static let shared = WatchDataModel() let session = WCSession.default @Published var TableauSynchroIphoneWatch : [String:String] = ["0":"0"] override init() { super.init() if WCSession.isSupported() { session.delegate = self session.activate() } else { print("ERROR: Watch session not supported") } } func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { if let error = error { print("session activation failed with error: \(error.localizedDescription)") return } } func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any]) { guard let newCount = userInfo["TableauSynchroIphoneVersWatch"] as? [String:String] else { print("ERROR: unknown data received from Watch TableauSynchroIphoneWatch") return } DispatchQueue.main.async { print(newCount) } } } Thank for your answers !
Posted
by MaximeHae.
Last updated
.
Post not yet marked as solved
0 Replies
196 Views
I'm building complications using WidgetKit and SwiftUI. The complications work, but the previews don't appear right away when applying the .watchface. How can I ensure the complication previews show up immediately when a user adds the watch face? Any guidance is appreciated.
Posted Last updated
.
Post not yet marked as solved
4 Replies
442 Views
XCode 15.3, watchOS 10.4 SDK Our health-related app is exploring adding an additional feature that would make use of extended runtime sessions to guide users through an activity. A user starts a session by tapping a button on the watchOS app's interface. If a session is already running, pressing that button should cause the current session to invalidate, and a new session should be created so we can start again from the beginning. TLDR: Running new sessions works as expected on the simulator but not on a real device. Why? We currently have a barebones implementation that includes logging in the extended runtime session delegate functions, on the button push, and when the new session is about to start. Here's what our logging output for the simulator looks like when we try to invalidate the current session and run another one: Invalidating extended session Optional("<WKExtendedRuntimeSession: 0x60000262d7a0> state=2, sessionID=4894EB1D-96F7-4921-8263-378E304E719F, expirationDate=2024-03-20 13:01:10 +0000") at 12:01:21 PM Extended runtime session <WKExtendedRuntimeSession: 0x60000262d7a0> state=3, sessionID=4894EB1D-96F7-4921-8263-378E304E719F, expirationDate=2024-03-20 13:01:10 +0000 invalidated for reason WKExtendedRuntimeSessionInvalidationReason(rawValue: 0) with error nil at 12:01:21 PM Requesting new extended session in application state 0 at 12:01:22 PM Starting new extended session Optional("<WKExtendedRuntimeSession: 0x600002644540> state=0, sessionID=B34ECCFF-A0DA-45C1-9FD1-FD0F335FBE02, expirationDate=(null)") in application state 0 at 12:01:23 PM Did start extended session <WKExtendedRuntimeSession: 0x600002644540> state=2, sessionID=B34ECCFF-A0DA-45C1-9FD1-FD0F335FBE02, expirationDate=2024-03-20 13:01:23 +0000 at 12:01:23 PM As you can see, we successfully invalidate a running session, a button press requests a new one, and then we create and start a new runtime session instance which ends in the running (2) state. We can repeat this over and over without issue. The exact same code running on an actual device produces this: Invalidating extended session Optional(\"<WKExtendedRuntimeSession: 0x15db5750> state=2, sessionID=889FE2E8-0FDA-4826-9094-4D48094FEBED, expirationDate=2024-03-20 12:53:55 +0000\") at 11:56:04AM Extended runtime session <WKExtendedRuntimeSession: 0x15db5750> state=3, sessionID=889FE2E8-0FDA-4826-9094-4D48094FEBED, expirationDate=2024-03-20 12:53:55 +0000 invalidated for reason WKExtendedRuntimeSessionInvalidationReason(rawValue: 0) with error nil at 11:56:04AM Requesting new extended session in application state 0 at 11:56:05AM Starting new extended session Optional(\"<WKExtendedRuntimeSession: 0x15e0aba0> state=0, sessionID=D5020337-D20B-48BE-B2EE-EE44BE580AEC, expirationDate=(null)\") in application state 0 at 11:56:06AM Extended runtime session <WKExtendedRuntimeSession: 0x15e0aba0> state=3, sessionID=D5020337-D20B-48BE-B2EE-EE44BE580AEC, expirationDate=(null) invalidated for reason WKExtendedRuntimeSessionInvalidationReason(rawValue: 1) with error nil at 11:56:06AM The difference is in the last line: starting the session was unsuccessful and it was immediately invalidated, with the reason WKExtendedRuntimeSessionInvalidationReason(rawValue: 1) which maps to the enum sessionInProgress. This is surprising, since we just invalidated and dereferenced the old runtime session. What else can we do to tear down this session? In fact, no other extended runtime sessions can be created and started successfully until the device is rebooted. One note is that on the simulator we do get the following warning right after invalidating the running session: -[WKExtendedRuntimeSession _invalidateWithError:]_block_invoke_2:527: Got error Error Domain=com.apple.CarouselServices.SessionErrorDomain Code=3 "Session not running <CSLSession: 0x600003b4eca0; pid: 8833; dismissed: NO; ended: YES; duration: 3600.0; autoEnd: NO; launchable: NO; mutuallyExclusive: YES; managed: YES; persisted: NO; requiresFGActiveInitiation: YES; lastForeground: 2024-03-20 12:01:21 +0000> |CSLSSession = { | sessionID: 4894EB1D-96F7-4921-8263-378E304E719F; bundleID: com.bundle; type: "physical therapy"; running: NO; paused: NO; expirationDate: 2024-03-20 13:01:10 +0000; supportsAOT: NO; lastStartWasScheduled: NO; remote: NO; |}" UserInfo={NSLocalizedDescription=Session not running <CSLSession: 0x600003b4eca0; pid: 8833; dismissed: NO; ended: YES; duration: 3600.0; autoEnd: NO; launchable: NO; mutuallyExclusive: YES; managed: YES; persisted: NO; requiresFGActiveInitiation: YES; lastForeground: 2024-03-20 12:01:21 +0000> |CSLSSession = { | sessionID: 4894EB1D-96F7-4921-8263-378E304E719F; bundleID: com.bundle; type: "physical therapy"; running: NO; paused: NO; expirationDate: 2024-03-20 13:01:10 +0000; supportsAOT: NO; lastStartWasScheduled: NO; remote: NO; |}} This appears to be thrown by some part of Carousel, for which no public documentation exists, and it clearly doesn't disrupt the expected behavior on the simulator. I don't know if this is being thrown on the device, since our logging wouldn't be able to pick it up. Please let me know if we are approaching this incorrectly or if there are any known solutions to this issue.
Posted
by bcappdev.
Last updated
.
Post not yet marked as solved
5 Replies
415 Views
It's not just me that the watch doesn't show up in Xcode 15.3, Watch 10.4, iOS 17.4.1, right? In Xcode, the Mac and iPhone are connected and displayed, but only the watch is not working. And when I run the complication app, oddly enough, it prompts to install the app on the iPhone device's watch app? It's really strange, isn't it? But the installation doesn't actually happen. It seems like a funny thing with Apple. Does anyone know when this will be fixed?
Posted
by DongSik.
Last updated
.
Post not yet marked as solved
0 Replies
254 Views
I understand that the Nearby Interaction framework is available on watchOS 8+, and I want to make a watch app that displays distance estimation between multiple watches (not iPhones) using UWB through Nearby Interactions. I see in the documentation that an iPhone can discover multiple device "discovery tokens" and create NISessions with them using the Multipeer Connectivity framework, but it looks like the Multipeer Connectivity framework is not available on watchOS? So, how might I make an independent watch app that can discover multiple nearby watches and setup NISessions with them? Thanks!
Posted
by milst.
Last updated
.
Post not yet marked as solved
6 Replies
1.1k Views
Our app is pushed to supervised iPhones through our MDM. We have a watchOS companion app that we install to paired Apple Watches as well. Our watches are NOT enrolled in the MDM using the new watchOS 10 MDM features, and are just paired normally to the supervised phones. Historically (the past 2 years), the watchOS companion app has been installed automatically after our iOS app has been pushed by our MDM (through VPP) and the Watch has been paired. NEW IN iOS 17.4/watchOS 10.4, the watchOS companion app is NOT installed automatically and when we press “Install” in the Watch app on the iPhone, we see a spinner for about 1 second and then a silent failure, with the button reverting back to “Install”. This is occurring with other apps purchased through VPP. We purchased the CityMapper app through VPP, assigned it to a supervised iPhone, and attempted to install CityMapper's watchOS companion app and got the same failed result. This is NOT occurring on a clean & reset supervised iPhone and its paired watch running iOS 17.3.1 / watchOS 10.3. On a personal unsupervised device running iOS 17.4/watchOS 10.4 with a copy of our app purchased through the App Store, installing the watchOS companion app is not an issue. I filed radar FB13687404 but in 10 years of developing for iOS, I have never ever ever heard of Apple responding to one of those. Posting here in the hope that other users/developers can share their issues or solutions.
Posted
by bcappdev.
Last updated
.
Post not yet marked as solved
2 Replies
173 Views
Could you please provide clarification on whether WatchOS currently supports the real-time or on-demand measurement of skin temperature and ambient temperature? If so, Could you also guide us on the relevant APIs or resources available for incorporating these features into out applications?
Posted
by Snkr006.
Last updated
.
Post not yet marked as solved
0 Replies
255 Views
When I connect a speed and cadence sensor to my Apple Watch in Bluetooth settings I expect to see the following HKQuantity types in workoutBuilder:(HKLiveWorkoutBuilder *)workoutBuilder didCollectDataOfTypes HKQuantityTypeIdentifierCyclingSpeed, HKQuantityTypeIdentifierDistanceCycling, and HKQuantityTypeIdentifierCyclingCadence. However, after starting an HKWorkoutSession I only get updates for HKQuantityTypeIdentifierDistanceCycling. I know that these metrics are being updated because the Apple Workout app displays them. I have authorized my app to read and write these quantity types, so what could I be missing here? Are these quantities only available to the workout app, as I haven't found a third-party app that sees these metrics when the sensors are connected this way?
Posted Last updated
.
Post not yet marked as solved
1 Replies
438 Views
Hi there, I think I may have caught a bug in the iOS system. Please confirm. Problem Newly installed Watch-Only and Independent apps on the Apple Watch do not have a network connection when paired with an iPhone until the iPhone is rebooted. Please see the attached screenshot; the iPhone indicates 'WiFi and Cellular policy: kDeny'. Use Case For our end-users, they will install the Watch-Only app directly from the App Store on the Apple Watch, and of course, their watch is paired with their iPhone. In this case, the Watch-Only app has no network connection at all after installation. The user has to reboot the iPhone once, and then the Watch-Only app can access the network. It is unacceptable for the end-users. System Info WatchOS: 10.1.1 Watch Model: A2770, Apple Watch Series 8 (GPS only) iOS Version: 17.4.1 iPhone Model: iPhone 15 XCode: 15.3 How to reproduce Please download the very simple sample code attached. It features the official URLSession Demo Code, which initiates a default URLSession to access https://www.example.com. ContentView.swift Prepare an iPhone and an Apple Watch, then connect the watch to the iPhone and ensure they are paired correctly. Ensure that your iPhone properly connects to a working WiFi network. Now, connect both your Apple Watch and iPhone to Xcode and run the code on the watch. Xcode will then install the Watch-Only app on your watch. After installation, click the 'Click' button on the watch app, and you will receive an error message stating 'The Internet connection appears to be offline...' Now, check the Console output of your iPhone and filter by 'wifi policy'. You will see logs stating 'Adding CU Policy: Bundle IDs: (the-bundle-id) Wifi policy: kDeny Cellular policy: kDeny'. Now, reboot your iPhone and wait for it to reconnect to the WiFi network. Check the Control Center on your watch to ensure the little green iPhone icon is displayed, indicating that your watch is now paired correctly with the iPhone. Click the 'Click' button again on the watch app, and this time it will work perfectly. To repeat the process, simply uninstall the watch app from your watch, and run the sample code again. Xcode will reinstall the app onto the watch. This time, the app will not work until you reboot the iPhone again. References Proxy Through iPhone https://developer.apple.com/documentation/watchos-apps/keeping-your-watchos-app-s-content-up-to-date#Test-your-update-code-with-different-configurations Sample Code struct ContentView: View { @State var txt = "Hello World!" var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text(txt) Button("Click") { startLoad() } }.padding() } func startLoad() { let config = URLSessionConfiguration.default config.waitsForConnectivity = false config.allowsCellularAccess = true config.allowsExpensiveNetworkAccess = true config.allowsConstrainedNetworkAccess = true let sesh = URLSession(configuration: config) let url = URL(string: "https://www.example.com")! sesh.dataTask(with: url) { data, response, error in if let error = error { self.txt = error.localizedDescription // self.handleClientError(error) return } guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { self.txt = response.debugDescription // self.handleServerError(response) return } if let mimeType = httpResponse.mimeType, mimeType == "text/html", let data = data, let string = String(data: data, encoding: .utf8) { DispatchQueue.main.async { self.txt = string // self.webView.loadHTMLString(string, baseURL: url) } } }.resume() } } #Preview { ContentView() }
Posted
by BillHoo.
Last updated
.
Post not yet marked as solved
3 Replies
274 Views
Hello, I have a TabView containing multiple views where one of them contains a list of items. The digital crown on the apple watch does not allow me to scroll the items in the tabview but only scrolls the list of items. Is there any way to disable that the scrolling of the list is done by the wheel or even a way to prioritize the digital crown to scroll the tabView and not the list? Thanks
Posted Last updated
.
Post not yet marked as solved
0 Replies
284 Views
This page describes the procedure to create deep links in iOS. I was able to launch an IOS Companion app (name of the app in my case) using its deep link. But the same is not working in AppleWatch. This is my plist to register a custom scheme - Companion: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleURLTypes</key> <array> <dict> <!-- <key>CFBundleTypeRole</key> <string>Viewer</string> --> <key>CFBundleURLName</key> <string><some unique ID></string> <key>CFBundleURLSchemes</key> <array> <string>Companion</string> </array> </dict> </array> </dict> </plist> I have implemented onOpenURL(perform:) to handle app launches using a deep link (url). var body: some Scene { WindowGroup { ContentView() .onOpenURL(perform: { (link: URL) in Log(String(format: "Link = %@", link.absoluteString)) // Use then deep link }) } } In iOS, I tested deep links in two ways: Wrote the full deep link in Notes app and tapped it. Created another app called AppLauncher with a Button saying 'Launch using Deep link'.... which when clicked opens the deep link using open(_:options:completionHandler:). Both the approaches work in iOS, but in watchOS, I can only try 2 because Notes app is not available for AppleWatch. So, I created another watchOS app called AppLauncher, which displays a SwiftUI Button saying 'Launch using Deep link', which when tapped, tries to open the link using openSystemURL(_:). But as mentioned in the documentation (linked earlier), Opens the specified system URL. this API only works for links associated with System apps i.e., Apple's call and message apps. So, how else can I use deep link to launch another app? I believe it's possible to launch an app using its deep link because the info.plist keys required to define a deep link scheme association (CFBundleURLTypes, CFBundleURLSchemes etc) is valid for watchOS too.
Posted
by GangOrca.
Last updated
.