In this episode, Conrad Stoll joins us once again to talk about how to use WCSession to pass data back & forth between our watchOS app and our iOS app. We'll use this power for the ultimate good, of course, by ordering a beer straight from our watch.
This episode was authored by Conrad Stoll. Episode Links Source Code WatchConnectivity Framework Reference WatchConnectivity WWDC Talk MMWormhole Natasha The Robot - WCSession WatchConnectivity Background Delivery Sample Project Using WCSession to Send Data import WatchConnectivity let session = WCSession.default() session.delegate = self if session.activationState != .activated { session.activate() return } var context = session.applicationContext context["beers"] = arrayOfBeerDictionaries() do { try session.updateApplicationContext(context) } catch let error { print(error) } Monitoring Session Activation State public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { if activationState == .activated { // Send Data If Necessary } } Using WCSessionDelegate to Receive Data func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) { if let arrayOfDictionaries = applicationContext["key"] as? [[String : AnyObject]] { } } Handling Background Delivery on watchOS App func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) { for task in backgroundTasks { if let watchConnectivityBackgroundTask = task as? WKWatchConnectivityRefreshBackgroundTask { handleWatchConnectivityBackgroundTask(watchConnectivityBackgroundTask) } else { handleRefreshTask(task) } } completeAllTasksIfReady() } Handling Background WatchConnectivity Task Completion Correctly var watchConnectivityBackgroundTasks: [WKWatchConnectivityRefreshBackgroundTask] = [] override init() { super.init() let session = WCSession.default() // https://developer.apple.com/library/content/samplecode/QuickSwitch/Listings/QuickSwitch_WatchKit_Extension_ExtensionDelegate_swift.html session.addObserver(self, forKeyPath: "activationState", options: [], context: nil) session.addObserver(self, forKeyPath: "hasContentPending", options: [], context: nil) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { DispatchQueue.main.async { self.completeAllTasksIfReady() } } func completeAllTasksIfReady() { let session = WCSession.default() // the session's properties only have valid values if the session is activated, so check that first if session.activationState == .activated && !session.hasContentPending { watchConnectivityBackgroundTasks.forEach { $0.setTaskCompleted() } watchConnectivityBackgroundTasks.removeAll() } } Schedule a Future Background Refresh WKExtension.shared().scheduleBackgroundRefresh(withPreferredDate: Date(timeIntervalSinceNow: 60 * 5), userInfo: nil) { (error) in } Building a Watch App Request/Response System let session = WCSession.default() session.sendMessage(["message" : "refreshRequest"], replyHandler: { (items : [String : Any]) in if let array = items["beers"] as? [[String : AnyObject]] { self.handleArrayOfBeers(array: array) } }) { (_) in } Handling Request and Sending Response on iPhone App func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) { if let message = message["message"] as? String, message == "refreshRequest" { replyHandler(["beers" : arrayOfBeerDictionaries()]) } }