“Message reply took too long.” - Watch Connectivity Issues with Watch OS 3

做~自己de王妃 提交于 2019-12-02 21:44:19
  1. You should not send or receive custom class objects from one target(iOS) to second target(watchOS) instead you should send/receive data in dictionary format such as [String: Any] and this dictionary should contain array of your custom objects required properties in key value pair in simple dictionary. This could easily be decodable at watch side.

  2. You should make a decoupled class extending WCSessionDelegate such as below so that this class could be used not only in ExtensionDelegate but also in any WKInterfaceController.

    class WatchSessionManager: NSObject, WCSessionDelegate {
    
        static let sharedManager = WatchSessionManager()
    
        private override init() {
            super.init()
            self.startSession()
        }
    
        private let session: WCSession = WCSession.default
    
        func startSession() {
            session.delegate = self
            session.activate()
        }
    
        func tryWatchSendMessage(message: [String: Any], completion: (([String: Any]) -> Void)? = nil) {
            print("tryWatch \(message)")
            weak var weakSelf = self
            if #available(iOS 9.3, *) {
                if weakSelf?.session.activationState == .activated {
                    if weakSelf?.session.isReachable == true {
                        weakSelf?.session.sendMessage(message,
                                                      replyHandler: { [weak self]  ( response )  in
                                                        guard let slf = self else {return}
                                                        //Get the objects from response dictionary
                                                        completion?(response)
                            },
                                                      errorHandler: { [weak self] ( error )  in
                                                        guard let slf = self else {return}
                                                        print ( "Error sending message: % @ " ,  error )
                                                        // If the message failed to send, queue it up for future transfer
                                                        slf.session.transferUserInfo(message)
                        })
                    } else {
                        self.session.transferUserInfo(message)
                    }
                }else{
                    self.session.activate()
                    self.session.transferUserInfo(message)
                }
            } else {
                // Fallback on earlier versions
                if self.session.activationState == .activated {
                    if self.session.isReachable == true {
                        self.session.sendMessage(message,
                                                 replyHandler: {  ( response )  in
                                                    //Get the objects from response dictionary
                                                    completion?(response)
                        },
                                                 errorHandler: {  ( error )  in
                                                    print ( "Error sending message: % @ " ,  error )
                                                    // If the message failed to send, queue it up for future transfer
                                                    self.session.transferUserInfo(message)
                        })
                    } else {
                        self.session.transferUserInfo(message)
                    }
                }else{
                    self.session.activate()
                    self.session.transferUserInfo(message)
                }
            }
        }
    
    
    }
    

Now you could easily send a message to your iOS app to wake up and get data from there (e.g from CoreData) using the above function in any WKInterfaceController and the completion block will have your required data such as

let dict: [String: Any] = ["request": "FirstLoad"]
WatchSessionManager.sharedManager.tryWatchSendMessage(message: dict,completion:{ (data) in print(data)})

Same way you should use this WatchSessionManager on iOS side and receive the request and as per the requested key you should take data from core storage/db and send list of custom objects in simple key-value Dictionary pattern within replyHandler of didreceiveMessage function such as below.

 func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
 var dict: [String: Any] = [String: Any]()
 replyHandler(dict) //This dict will contain your resultant array to be sent to watchApp.
}

Some time iOS App(Killed state) is not reachable to WatchApp, for solving that problem you should call "tryWatchSendMessage" within Timer of around 3 sec interval. And when you get connection from watchApp then you should invalidate the timer.

The sendMessage functionality of WatchConnectivity is so powerful to wake your app up. You should use it in optimized manner.

I have just dealt with my WatchOS app. And there was a situation when I received "Message reply took too long".

Then I added background task handler to my iOS app and started to send messages every second to WatchOS app. The message contained UIApplication.shared.backgroundTimeRemaining. So i get: 45sec, 44sec, ..., 6sec, 5sec, ... If the timer runs below 5 sec no messages will be delivered to/from iOS app and we will get "Message reply took too long". The easiest solution was to send blank messages from watch to phone each time the timer goes below 15 sec. The backgroundTimeRemaining will be updated to 45 seconds again: 45, 44, 43, ..., 17, 16, 15, (blank message), 45, 44, 43, ...

Hope it helps someone

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!