WCSession.sendMessage works 50/50

狂风中的少年 提交于 2019-12-18 05:45:49

问题


Lately, I am working on a project is related to Watch/iPhone communication again. But my code works sometimes and doesn’t work sometimes which is kind of weird to me because I think the code should either work or not. It cannot be 50/50. Therefore, I have no idea what goes wrong.

setup WCSession on iPhone:

class WatchCommunicationController: NSObject, WCSessionDelegate {

    var session : WCSession?

    override init(){

        //  super class init
        super.init()

        //  if WCSession is supported
        if WCSession.isSupported() {    //  it is supported

            //  get default session
            session = WCSession.defaultSession()

            //  set delegate
            session!.delegate = self

            //  activate session
            session!.activateSession()

        } else {

            print("iPhone does not support WCSession")
        }
    }

    ... ...
}

similar WCSession setup on Watch:

class PhoneCommunicationController: NSObject, WCSessionDelegate {

    var session : WCSession?

    override init(){

        //  super class init
        super.init()

        //  if WCSession is supported
        if WCSession.isSupported() {    //  it is supported

            //  get default session
            session = WCSession.defaultSession()

            //  set delegate
            session!.delegate = self

            //  activate session
            session!.activateSession()
        } else {

            print("Watch does not support WCSession")
        }
    }

    ... ...
}

send out message on Watch:

func sendGesture(gesture : GKGesture){

//  if WCSession is reachable
if session!.reachable {     //  it is reachable

    //  create the interactive message with gesture
    let message : [String : AnyObject]
    message = [
                "Type":"Gesture",
                "Content":gesture.rawValue
              ]

    //  send message
    session!.sendMessage(message, replyHandler: nil, errorHandler: nil)
    print("Watch send gesture \(gesture)")

} else{                     //  it is not reachable

    print("WCSession is not reachable")
}

}

related enum:

enum GKGesture: Int {
    case Push = 0, Left, Right, Up, Down
}

receive message on iPhone:

func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {

        //retrieve info
        let type = message["Type"] as! String
        let content = message["Content"]

        switch type {

        case "Gesture":
            handleGesture(GKGesture(rawValue: content as! Int)!)
        default:
            print("Received message \(message) is invalid with type of \(type)")
        }

    }

    func handleGesture(gesture : GKGesture){

        print("iPhone receives gesture \(gesture)")

        var notificationName = ""

        switch gesture {

        case .Up:
            notificationName = "GestureUp"
        case .Down:
            notificationName = "GestureDown"
        case .Left:
            notificationName = "GestureLeft"
        case .Right:
            notificationName = "GestureRight"
        case .Push:
            notificationName = "GesturePush"
        }

        NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil)

    }

somehow I can’t debug my Watch app on Xcode, the debug session just won’t attach. I don’t know why. Therefore, I debug one-sided with just the iPhone.

sometimes I got "receives gesture” print out, and sometimes not. And the same for getting the notification.


回答1:


I don't know if Int would be wrapped around to NSNumber while being transfer within WCSession. If it would be, then that must be why when I use Int as the base class of the enum it won't work and works when String is the base class.

Connectivity Known Issue Your app may crash when using NSNumber and NSDate objects with the WCSession API.

Workaround: Convert an NSNumber or NSDate object to a string before calling WCSession APIs. Do the opposite conversion on the receiving side.

Watch OS 2 Beta 4 release note




回答2:


My guess is your call to sendMessage is returning an error in the cases where it fails, but you haven't implemented the error handler!! For now while you are getting up and running you can get away with just printing the error, but if this is shipping code you really ought to handle the appropriate errors:

//  send message
session.sendMessage(message, replyHandler: nil, errorHandler: { (error) -> Void in
    print("Watch send gesture \(gesture) failed with error \(error)")
})
print("Watch send gesture \(gesture)")



回答3:


Your flow is correct but the difficulty is to understand how to debug:

Debug Watch:

  1. Run the iPhone target and when it is done hit the Stop button.
  2. Open the iOS app inside the simulator (run it manually from the simulator and not from Xcode) and let it hang there.
  3. Switch to the Watch target (yourAppName WatchKit App), put the relevant breakpoint and run it.
  4. The iOS app will be put automatically in the background and then you will be able to use sendMessage method (at the Watch target) to send whatever you need and if you have a replayHandler in your iOS app you will even receive the relevant messages inside the sendMessage at your Watch target (i.e InterfaceController)

Small Swift example:

Sending a Dictionary from Watch to iOS app:

    if WCSession.defaultSession().reachable == true {
        let requestValues = ["Send" : "From iWatch to iPhone"]
        let session = WCSession.defaultSession()

        session.sendMessage(requestValues,
            replyHandler: { (replayDic: [String : AnyObject]) -> Void in
                print(replayDic["Send"])

            }, errorHandler: { (error: NSError) -> Void in
                print(error.description)
        })
    }
    else
    {
        print("WCSession isn't reachable from iWatch to iPhone")
    }

Receiving the message from the Watch and sending a replay from the iOS app:

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

      print(message.values)

      var replyValues = Dictionary<String, AnyObject>()

      replyValues["Send"] = "Received from iphone"
      // Using the block to send back a message to the Watch
      replyHandler(replyValues)
     }

Debug iPhone:

The exact opposite of debug watch

Also, the answer by @sharpBaga has an important consideration.



来源:https://stackoverflow.com/questions/31282834/wcsession-sendmessage-works-50-50

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