Teabyte

Mobile app development for iOS and Swift

Detect watchOS app state changes

2023-02-01

When developing an Apple Watch companion app for your iOS app it can become important to know when something happens to the state of the watch. In one of my last articles we already took a look at how you can share data to the watch. In this small tip, I want to highlight how can observe and react to state changes of the WCSession.

The scenario

Reacting to state changes can be quite fundamental when developing for the Apple Watch. Imagine the following example. The iOS app offers some kind of user authentication. A user has been logged in already and now buys an Apple Watch. They pair it and install the watch companion app to the iOS app. Since they are already being logged in on the phone, users would expect the watch app to be automatically logged in as well without them doing something manually. Here, reacting to state changes come into play.

I will use the following class for further code snippets. This makes it a little bit easier to describe the cases.

WatchConnectivityService.swift
final class WatchConnectivityService: NSObject {
 
    private let session: WCSession
 
    init() {
        guard WCSession.isSupported() else { fatalError() } // In a productive code, this should handled more gracefully
        self.session = WCSession.default
        self.session.delegate = self
        self.session.activate()
    }

The implementation

The WCSessionDelegate offers a very neat method which can be used to react to state changes of your WCSession, called sessionWatchStateDidChange(_ session: WCSession) Apple Documentation. It is available on iOS and can be used to react to any change on the session object. For example we could use it, to automatically update the application context with user information.

WatchConnectivityService.swift
extension WatchConnectivityService: WCSessionDelegate {
    #if os(iOS)
    func sessionWatchStateDidChange(_ session: WCSession) {
        // Only react when the watch app is installed
        guard session.isWatchAppInstalled else { return }
 
        // Update the application context with the user state
        session.updateApplicationContext(["userstate": UserState])
	}
    #endif
}

This small implementation would be triggered, as soon as the watch app is installed. Of course this would also be triggered, if for example the .isPaired property of the session object would change. This is then up to you to decide what to do, based on the context of your app.

I find this method especially helpful for a companion app in the described scenario. I had exactly this case, where I need to exchange the user state with the watch, as soon as it gets installed. This implementation helped me to fulfill the scenario.

Other state observing methods

There are also other methods available which could be helpful when something related to the watch changes:

  • sessionReachabilityDidChange(\_:WCSession)(Apple Documentation) Helpful to detect changes in the reachability property. Should be tracked when you want to see if the counterpart is reachable, available on iOS and watchOS

  • sessionCompanionAppInstalledDidChange(\_:WCSession:)(Apple Documentation) can be used on an independent watch to react to changes to the install state of the companion app on the phone

Conclusion

With this small tip, I wanted to share how you could ensure that your app can react appropriately when it comes to state changes in the used WCSession instance. As it was seen, this can be used to increase the user experience when using a watch app.

If you find any mistake or would like to reach out to me please do so 🙂

See you next time 👋