swiftwatchkitwcsession

Apple Watch WCConnectionDelegate, sending message in activationDidComplete fails occasionally?


I am having an issue where, when sending a message through WCConnection, the session.sendMessage fails sometimes if called in the delegate method activationDidCompleteWith. The issue is not repeatable every time (in fact, it works most of the time).

But forcing a session.sendMessage by using a button in my UI (calling the identical loading code) has a successful session communication immediately, so I know the issue is not in the session itself or the master app.

Is it unsafe to assume the session is ready to accept communication in activationDidCompleteWith? Is there a better place to be calling my initial communication?


Solution

  • In my experience watch OS is pretty finicky, especially when using older model watches. That being said I think the answer to the question: "Is it unsafe to assume the session is ready to accept communication in activationDidCompleteWith?" is yes, it is unsafe to assume that.

    In my own app I have a very similar case to yours and I solved it by sending a message until a response is received.

        // false until a response is received from the phone
        let receivedResponse: Bool = false 
    
        // function that sends the message
        func requestResponse() {
            guard WCSession.default.isReachable else {
                print("Phone not reachable")
                return
            }
    
            // callback that handles response
            let responseHandler: ([String: Any]) -> () = { response in
                receivedResponse = true
                callback(response)
            }
    
            WCSession.default.sendMessage(["Request": "Response"],
                                          replyHandler: responseHandler) { error in
                print(error.localizedDescription)
            }
        }
    
        // timer that calls the request function repeatedly
        let retryTimer = Timer.scheduledTimer(withTimeInterval: 1,
                                              repeats: true) { timer in
            if receivedResponse {
                // we know we got a response so clean up timer
                timer.invalidate()
            }
            requestResponse()
        }