Noticing Changes in Pairing State Between the iOS and Watch Apps - Apple Watch - iOS 9 Swift Programming Cookbook (2015)

iOS 9 Swift Programming Cookbook (2015)

Chapter 2. Apple Watch

2.2 Noticing Changes in Pairing State Between the iOS and Watch Apps

Problem

You want to know, both on the watch and in your companion iOS app, whether there is connectivity between them and whether you can send messages between them. Specifically, you want to find out whether one devic can receive a signal sent from the other.

Solution

Import the WatchConnectivity framework on both projects. Then use the WCSession’s delegate of type WCSessionDelegate to implement the sessionWatchStateDidChange(_:) method on your iOS side and the sessionReachabilityDidChange(_:) method on the watch side. These methods get called by WatchConnectivity whenever the state of the companion app is changed (whether that is on the iOS side or on the watchOS side).

Discussion

Both devices contain a flag called reachability that indicates whether the device can connect to the other. This is represented by a property on WCSession called reachable, of type Bool. On the iOS side, if you check this flag, it tells you whether your companion watch app is reachable, and if you check it on the watchOS side, it tells you whether your companion iOS app is reachable.

The idea here is to use the WCSession object to listen for state changes. Before doing that, we need to find out whether the session is actually supported. We do that using the isSupported() class function of WCWCSession. Once you know that sessions are supported, you have to do the followings on the iOS app side:

1. Obtain your session with WCSession.defaultSession().

2. Set the delegate property of your session.

3. Become the delegate of your session, of type WCSessionDelegate.

4. Implement the sessionWatchStateDidChange(_:) function of your session delegate and in there, check the reachable flag of the session.

5. Call the activateSession() method of your session.

Make sure that you do this in a function that can be called even if your app is launched in the background.

On the watch side, do the exact same things as you did on the iOS side, but instead of implementing the sessionWatchStateDidChange(_:) method, implement the sessionReachabilityDidChange(_:) method.

NOTE

The sessionWatchStateDidChange(_:) delegate method is called on the iOS side when at least one of the properties of the session change. These properties include paired, watchAppInstalled, complicationEnabled, and watchDirectoryURL, all of type Bool. In contrast, the sessionReachabilityDidChange(_:) method is called on the watch only when thereachable flag of the companion iOS app is changed, as the name of the delegate method suggests.

So on the iOS side, let’s implement an extension on WCSession that can print all its relevant states, so that when the sessionWatchStateDidChange(_:) method is called, we can print the session’s information:

import UIKit

import WatchConnectivity

extension WCSession{

public func printInfo(){

//paired

print("Paired: ", appendNewline: false)

print(self.paired ? "Yes" : "No")

//watch app installed

print("Watch app installed: ", appendNewline: false)

print(self.watchAppInstalled ? "Yes" : "No")

//complication enabled

print("Complication enabled: ", appendNewline: false)

print(self.complicationEnabled ? "Yes" : "No")

//watch directory

print("Watch directory url", appendNewline: false)

print(self.watchDirectoryURL)

}

}

Make your app delegate the delegate of the session as well:

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {

var window: UIWindow?

...

Now start listening for state and reachablity changes:

func sessionReachabilityDidChange(session: WCSession) {

print("Reachable: ", appendNewline: false)

print(session.reachable ? "Yes" : "No")

}

func sessionWatchStateDidChange(session: WCSession) {

print("Watch state is changed")

session.printInfo()

}

Last but not least, on the iOS side, set up the session and start listening to its events:

guard WCSession.isSupported() else {

print("Session is not supported")

return

}

let session = WCSession.defaultSession()

session.delegate = self

session.activateSession()

Now on the watch side, in the ExtensionDelegate class, import WatchConnectivity and become the session delegate as well:

import WatchKit

import WatchConnectivity

class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate {

...

And listen for reachablity changes:

func sessionReachabilityDidChange(session: WCSession) {

print("Reachablity changed. Reachable?", appendNewLine: false)

print(session.reachable ? "Yes" : "No")

}

Then in the applicationDidFinishLaunching() function of our extension delegate, set up the session:

guard WCSession.isSupported() else {

print("Session is not supported")

return

}

let session = WCSession.defaultSession()

session.delegate = self

session.activateSession()

See Also