Error: "Message reply took too long" - WCSession Watch OS2

2.1k Views Asked by At

So I am using Watch Connectivity to request an array from the iPhone to the Watch.

The idea was to sendMessage from the watch, and the iPhone will reply with the array within the didReceiveMessage method.

However the iPhone does not seem to be responding, I thought the iPhone would open the application when I send the message from the Watch. I have tried even opening the application when I sendMessage but still no luck. When I wait long enough I get the following error message:

Error Domain=WCErrorDomain Code=7012 "Message reply took too long." UserInfo={NSLocalizedDescription=Message reply took too long., NSLocalizedFailureReason=Reply timeout occured.}

Does anybody know where I may be going wrong ?

Apple Watch

import WatchKit
import Foundation
import CoreData
import WatchConnectivity

class BookmarkedInterfaceController: WKInterfaceController, WCSessionDelegate {

var session : WCSession!
var objects: [AnyObject]!

@IBOutlet var table: WKInterfaceTable!

override func willActivate() {
    super.willActivate()
    //Check if session is supported and Activate
    if (WCSession.isSupported()) {
        session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()
    }
    sendMessageToIphone()
}
func sendMessageToIphone() {
    if WCSession.defaultSession().reachable {

        print("WCSession is reachabe")

        let messageDict = ["Request": "iPhone Can You Give Me The Array"]
        WCSession.defaultSession().sendMessage(messageDict, replyHandler: { (replyDict) -> Void in
            print(replyDict)
            }, errorHandler: { (error) -> Void in
                print(error)
        })
    }
}

func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
   //recieving message from iphone
    print("recieved message from iphone \(message)")

    objects.append(message["Array"]!)

    print("Objects array = \(objects)")        
}

The console outputs

WCSession is reachabe Array nil

iPhone App Delegate

import UIKit
import CoreData
import WatchConnectivity

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {

var window: UIWindow?
var session : WCSession!

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    //Check if session is supported and Activate
    if (WCSession.isSupported()) {
        session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()
    }
}

func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {

    print("did recieve message from Watch")

    let applicationData = ["Array":["One", "Two", "Three"]]

    replyHandler(applicationData)

}

Nothing from the iPhone is being executed. Even when I manually open the app.

2

There are 2 best solutions below

2
On

If you want the reply to the message the watch sent to contain the requested data, you should change your code to the following:

Watch

func sendMessageToIphone() {
    if WCSession.defaultSession().reachable {

        print("WCSession is reachabe")

        let messageDict = ["Request": "iPhone Can You Give Me The Array"]
        WCSession.defaultSession().sendMessage(messageDict, replyHandler: { (replyDict) -> Void in
            print("Array \(replyDict["array"])")
            }, errorHandler: { (error) -> Void in
                print(error)
        })
    }
}

Phone

func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {

    print("did recieve message from Watch")

    let applicationData = ["Array":["One", "Two", "Three"]]

    //If identifier from recievedMessage is for Objects

    replyHandler(applicationData)

}

And separately, the reason why the sendMessage from the phone is not received by the watch is because you've implemented the wrong delegate method for the sendMessage invocation you are using.

If you call sendMessage with a nil replyHandler then this delegate method will be invoked on the receiving side: func session(session: WCSession, didReceiveMessage message: [String : AnyObject])

If you call sendMessage with a non-nil replyHandler then this delegate method will be invoked on the receiving side: func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void)

2
On

You must activate the session before sending the message .Also you must set the delegate before you activate the session because you may lose some pending messages.

iphone side :

import UIKit
import WatchConnectivity

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {

var window: UIWindow?
var session : WCSession!

func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {

    print("did recieve message from Watch")
    let applicationData = ["Array":["One", "Two", "Three"]]

    //If identifier from recievedMessage is for Objects
    session.sendMessage(applicationData, replyHandler: { reply in
        print("Got reply: \(reply)")
        }, errorHandler: { error in
            print("error: \(error)")
    })
}

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    session = WCSession.defaultSession()
    session.delegate = self
    session.activateSession()
    return true
}
}

iWatch extension InterfaceController You must activate the session in the interface controller willactivate method.

import WatchKit
import Foundation
import WatchConnectivity

class InterfaceController: WKInterfaceController, WCSessionDelegate {

var session : WCSession!
var objects: [AnyObject]!

override func awakeWithContext(context: AnyObject?) {
    super.awakeWithContext(context)

    // Configure interface objects here.
}
override func willActivate() {
    // This method is called when watch view controller is about to be visible to user
    super.willActivate()
    session = WCSession.defaultSession()
    session.delegate = self
    session.activateSession()
    objects = []
    sendMessageToIphone()
}

override func didDeactivate() {
    // This method is called when watch view controller is no longer visible
    super.didDeactivate()
}

func sendMessageToIphone() {
    if WCSession.defaultSession().reachable{

        print("WCSession is reachabe")

        let messageDict = ["Request": "iPhone Can You Give Me The Array"]
        WCSession.defaultSession().sendMessage(messageDict, replyHandler: { (replyDict) -> Void in
            print(replyDict)
            }, errorHandler: { (error) -> Void in
                print(error)
        })
    }
}

func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
    //recieving message from iphone
    print("recieved message from iphone \(message)")

    objects.append(message["Array"]!)

    print("Objects array = \(objects)")
}
}

Note. Run the iphone application first. Then Run the extension and keep the iphone app in foreground.