3

I am trying to wake up the iOS parent app by sending a message from watchkit extension.

This though does only work when below sendMessage function is called from the watchApp / ViewController. When it is called from ComplicationController, the message is sent, but the iOS parent app does now wake up.

Any advice appreciated. (please any code reference in Swift)

Here the simplified code:

In AppDelegate and ExtensionDelegate:

override init() {
    super.init()
    setupWatchConnectivity()
}

private func setupWatchConnectivity() {
    if WCSession.isSupported() {
        let session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()
    }
}

In ExtensionDelegate: (no problem here, message is successfully sent)

func sendMessage(){
        let session = WCSession.defaultSession()
        let applicationData:[String:AnyObject] = ["text":"test", "badgeValue": 100 ]

        session.sendMessage(applicationData, replyHandler: {replyMessage in
            print("reply received from iphone")
            }, errorHandler: {(error ) -> Void in
                // catch any errors here
                print("no reply message from phone")
        })
    }
    print("watch sent message")

}

In AppDelegate: (not received when iOS app not running / not in foreground)

func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
    let text = message["text"] as! String
    let badgeValue = message["badgeValue"] as! Int

    dispatch_async(dispatch_get_main_queue()) { () -> Void in

        print("iphone received message from watch App")
        self.sendNotification(text, badgeValue: badgeValue)
        let applicationDict = ["wake": "nowAwake"]
        replyHandler(applicationDict as [String : String])

    }

}

this is how the function is called from Complication Controller (which does send the message but not awake the parent app):

  func requestedUpdateDidBegin(){

        dispatch_async(dispatch_get_main_queue()) { () -> Void in

            let extensionDelegate = ExtensionDelegate()
            extensionDelegate.loadData()

        }
    }
TPeter
  • 463
  • 3
  • 15
  • 1
    I just tested your code on Simulators and on iPhone / Watch. It wakes the app up even if I never opened it. It works when the app is running, when the app is in the background and when the app is completely killed. – joern Nov 05 '15 at 15:33
  • What makes you think that the app is not woken up? – joern Nov 05 '15 at 15:33
  • 1
    thank you Joern for your effort. Really appreciated. Just tested the same with exclusively above code and you are correct. Really odd. It seems the issue is not in above code but in how I call it. In my app, I am calling sendMessage (which is in ExtensionDelegate) from the ComplicationController, in which case the message is sent but parent app does not awake. If I instead trigger sendMessage from the app / from ViewController, the message is sent and parent app does indeed wake up. (how I know is by reply received or not by watch) – TPeter Nov 05 '15 at 16:00
  • So, I guess this is related to the Complication specific code. Unfortunately I do not have much experience with complications so I cannot be of much help on this one. – joern Nov 05 '15 at 16:11
  • I updated the question above with the relation to calling this function from ComplicationController – TPeter Nov 05 '15 at 22:27
  • I am having this issue as well. In your requestedUpdateDidBegin() method, I assume the code should be extensionDelegate.sendMessage(). And did you ever get this working? – mginn May 01 '16 at 00:12

1 Answers1

1

The main problem is that you're trying to include (nested) asynchronous calls within your complication data source. However, your requested update will have reached the end of its method, and no timeline update will actually take place (since you didn't reload or extend the timeline, and even if you had, no new data would have been received in time for the current update).

Since no new data would be available for the scheduled update, you'd have to perform a second update to use the new data once it was received. Performing two back-to-back updates is not only unnecessary, it wastes more of your daily complication budget.

Apple recommends that you fetch and cache the data in advance of the update, so the complication data source can directly return the requested data to the complication server.

The job of your data source class is to provide ClockKit with any requested data as quickly as possible. The implementations of your data source methods should be minimal. Do not use your data source methods to fetch data from the network, compute values, or do anything that might delay the delivery of that data. If you need to fetch or compute the data for your complication, do it in your iOS app or in other parts of your WatchKit extension, and cache the data in a place where your complication data source can access it. The only thing your data source methods should do is take the cached data and put it into the format that ClockKit requires.

How can you update the complication?

Both of these approaches have the advantage of only needing one update to occur.

Community
  • 1
  • 1
  • Doesn't something like transferUserInfo only complete when the Watch app is opened? – mginn May 01 '16 at 14:49
  • 1
    `transferUserInfo` [transfers the information in the background, even if the app or extension is suspended or terminated](http://stackoverflow.com/a/34796886/4151918), so the transfer itself will be completed. The data will be waiting, and `didReceiveUserInfo` will get called when the app is opened. This generally provides a better user experience, as the user doesn't have to wait for the watch to request and receive the data. By caching the most recent data, it will be on hand for the next scheduled timeline update. –  May 01 '16 at 17:34
  • The only problem is if the user never opens the app, so I'm using `transferCurrentComplicationUserInfo` instead. – mginn May 01 '16 at 17:44
  • That's the preferred way to update a complication, but your watch extension can still receive other transferred data, even if the app itself is not open. –  May 01 '16 at 17:56