David Robertson
David Robertson

Reputation: 1581

Issues with sendMessage - WatchConnectivity

I've been using NatashaTheRobot singleton for the WCSession, but can't get the sendMessage to work properly.

My goal is to send a message from Watch app to the iOS app and transfer a dictionary from iOS app to watch app.

Here's my code in the ExtensionDelegate

import WatchKit
import WatchConnectivity

class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate {

var session:WCSession!
var boolCheck = Int()

func applicationDidFinishLaunching() {

    WatchSessionManager.sharedManager.startSession()
    print("Here i am")
}

func applicationDidBecomeActive() {
    print("I AWOKE")
}

func applicationWillResignActive() {

}

}

class WatchSessionManager: NSObject, WCSessionDelegate {

static let sharedManager = WatchSessionManager()
private override init() {
    super.init()
}

private let session: WCSession = WCSession.defaultSession()

func startSession() {
    session.delegate = self
    session.activateSession()
    if WCSession.isSupported(){
        self.session.sendMessage(["b":"peek"], replyHandler: nil, errorHandler: nil)
        print("works")
    } else {
        print("don't work")
    }

func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
    let sweetN = message["b"]! as? String
    dispatch_async(dispatch_get_main_queue(), {
        if sweetN == "insertData1" {
            NSNotificationCenter.defaultCenter().postNotificationName("sweetData1", object: nil)
    })
}
func sendMessage(message: [String : AnyObject],
    replyHandler: (([String : AnyObject]) -> Void)? = nil,
    errorHandler: ((NSError) -> Void)? = nil)
{
    session.sendMessage(message, replyHandler: replyHandler, errorHandler: errorHandler)
    print("this is message \(replyHandler)")
    var pretty = replyHandler
}

Here's my code in the WCSingleton in the iOS app (separate from the AppDelegate)

import WatchConnectivity

@available(iOS 9.0, *)
class WatchSessionManager: NSObject, WCSessionDelegate {

static let sharedManager = WatchSessionManager()
private override init() {
    super.init()
}

private let session: WCSession? = WCSession.isSupported() ? WCSession.defaultSession() : nil

private var validSession: WCSession? {

    if let session = session where session.paired && session.watchAppInstalled {
        return session
    }
    return nil
}

func startSession() {
    session?.delegate = self
    session?.activateSession()
}
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
    //receieve messages from watch
    print(message["b"]! as? String)
    let sweetN = message["b"]! as? String
    dispatch_async(dispatch_get_main_queue(), {
        if sweetN == "peek"{
            NSNotificationCenter.defaultCenter().postNotificationName("giveMeInfo", object: nil)
        }
     }
    })
}

@available(iOS 9.0, *)
extension WatchSessionManager {

func sendMessage(message: [String : AnyObject],
    replyHandler: (([String : AnyObject]) -> Void)? = nil,
    errorHandler: ((NSError) -> Void)? = nil)
{
    session!.sendMessage(message, replyHandler: replyHandler, errorHandler: errorHandler)
}

}

and here's the method i use in the ViewController (fired from NSNotificationCenter). However this part of code never gets executed (which is strange, because when i use applicationContext it works perfectly).

func giveMeInfo(){
        let linesAdd1 = linesAdd as! AnyObject
        WatchSessionManager.sharedManager.sendMessage(["a":linesAdd1])
}

Any insights of how to get all those parts working together are very welcome!

Upvotes: 1

Views: 1822

Answers (1)

Appyx
Appyx

Reputation: 1185

Your Code is a bit confusing to me and looks right but you will run into troubles with this approach for the following reasons:

  • if you receive the notification in the ViewController and the Watch changes into the inactive state, the sendMessage() method will not work to send data back:

    Calling this method from your WatchKit extension while it is active and running wakes up the corresponding iOS app in the background and makes it reachable. Calling this method from your iOS app does not wake up the corresponding WatchKit extension. If you call this method and the counterpart is unreachable (or becomes unreachable before the message is delivered), the errorHandler block is executed with an appropriate error. The errorHandler block may also be called if the message parameter contains non property list data types.

  • if you want to get data back, then you should use a reply block. But in your configuration these blocks will not be called because:

sendMessage(reply==nil) --> didReceiveMessage(... message: )

sendMessage(reply!=nil) --> didReceiveMessage(... message: replyHandler:)

  • on the other hand if you use the contextMethod:

    Use this method to transfer a dictionary of data items to the counterpart app. The system sends context data when the opportunity arises, with the goal of having the data ready to use by the time the counterpart wakes up. The counterpart’s session delivers the data to the session:didReceiveUpdate: method of its delegate. A counterpart can also retrieve the data from the receivedApplicationContext property of its session.

I hope this helps ;)

Upvotes: 3

Related Questions