Bare Minimum for Apple Watch Communication

Bare Minimum for Apple Watch Communication

Summary

When recently starting to add an Apple Watch companion app to an existing iOS app, I wanted to get communication working between the phone and watch as fast as possible since the rest of the Apple Watch app’s functionality depended on the inter-app communication.

Like other critical path features, this key part of the implementation needed to be assessed for strengths and weaknesses at the beginning, or the rest of the Watch app would be at risk of being fundamentally flawed — potentially lots of wasted time.

There is a lot of great material out there about getting started with Apple Watch development / communication to other devices, but I wanted to help supplement that with the bare minimum implementation to help other people, like me, get up and running as quickly as possible!

A few things to note:


The Bare Minimum Implementation

Throw the communication logic directly where it will be used!

Initially I wanted to send some information between Apple Watch app and iPhone app so the iPhone app could perform an action. There are many ways to overthink the implementation of this feature, but forget all that and put the communication logic right where you need it! Then, after things are working, clean this up (like separate out the communication logic). Or, if you aren’t looking for anything more sophisticated, you are done 😜.

Main app’s implementation (iPhone app in my case)

// 1
import WatchConnectivity

// `ReceivingEntity` is the class where you want to receive communication
final class ReceivingEntity: NSObject {
    override init() {
        super.init()
        . . .
        // 2
        if WCSession.isSupported() {
            let session = WCSession.default
            session.delegate = self
            session.activate()
        }
    }

// 3
extension ReceivingEntity: WCSessionDelegate {
    public func session(_: WCSession, activationDidCompleteWith _: WCSessionActivationState, error: Error?) {
        if let e = error {
            print("Completed activation with error: \(e.localizedDescription)")
        } else {
            print("Completed activation!")
        }
    }

    public func sessionDidBecomeInactive(_: WCSession) { print("session did become inactive") }
    public func sessionDidDeactivate(_: WCSession) { print("session did deactivate") }

    // 4
    public func session(_: WCSession,
                        didReceiveMessage message: [String: Any],
                        replyHandler: @escaping ([String: Any]) -> Void) {
        print("message received! - \(message)")

        // 5
        guard let m = message as? [String: String] else {
            // 6
            replyHandler([
                "response": "poorly formed message",
                "originalMessage": message,
            ])
            return
        }

        // 7
        replyHandler([
            "response": "properly formed message!",
            "originalMessage": m,
        ])

        // 8
        if m["someKey"] == "someValue" {
            // do stuff
        }
        . . .
    }
}
  1. Make sure to import the watch connectivity framework.
  2. You should check to see if watch communication is supported.
    • If supported, you need to set yourself as the delegate to receive communication.
    • Don’t forget to activate the session. Without this, no communication will work!
  3. Conform to the WCSessionDelegate to receive communication from the Watch app and to receive information about the session activation.
  4. Use this delegate method to receive messages from the Watch app.
    • Although there are other delegate methods to receive messages in slightly different ways, I initially chose this one due to the flexibility of dictionaries and because the reply handler helps when debugging.
  5. Expect the incoming message to be [String: String].
  6. If not [String: String], send a helpful message back in the reply handler.
  7. If we have [String: String], reply to the Watch app so it knows the message was formed well.
  8. Pull values out of the message and do what you want based off of that!

The Apple Watch’s implementation

Similar to the above iPhone session setup, update your Apple Watch’s Watch Extension’s ExtensionDelegate.swift to include:

import WatchConnectivity
import WatchKit

// 1
final class ExtensionDelegate: NSObject, WKExtensionDelegate {
    func applicationDidFinishLaunching() {
        if WCSession.isSupported() {
            let session = WCSession.default
            session.delegate = self
            session.activate()
        }
    }
}

extension ExtensionDelegate: WCSessionDelegate {
    func session(_: WCSession, activationDidCompleteWith _: WCSessionActivationState, error: Error?) {
        if let e = error {
            print("Completed activation with error: \(e.localizedDescription)")
        } else {
            print("Completed activation!")
        }
    }
}
  1. I chose to put the communication initialization setup work here since it should be early in the lifecycle of the Watch app in order to receive and support sending communication to the main app (iPhone app in my case). Later on, you will likely want to move this out of the ExtensionDelegate, but fine for an initial pass to get thing working.

And wherever you want to send a message to the main app

// 1
import WatchConnectivity

func sendMessage() {
    // 2
    guard WCSession.default.isReachable else { return }

    // 3
    WCSession.default.sendMessage(
        ["messageKey": "messageValue"],
        replyHandler: { reply in print(reply) },
        errorHandler: { e in
            print("Error sending the message: \(e.localizedDescription)")
    })
}
  1. Make sure to import the connectivity framework.
  2. Check to see if the iPhone is reachable before trying to send a message.
  3. Sending a message is as simple as calling the sendMessage function.

Note: To see this being used, check out these lines from Baby Patterns.


Feel free to reach out on Twitter — cheers!

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora