0. 環境
[OS] Mac OS X 10.11.6
[IDE] Xcode 8.1
[Swift] 3.0
1. 問題
WCSession#sendMessage()を使ってAppleWatchからiPhoneアプリへメッセージを送っても、30秒ほどしないと通知されない。
AppleWatch側
@IBAction func tapButton() { let message = [ "fromChild": "AppleWatchからのメッセージ" ] WCSession.default().sendMessage( message , replyHandler: { reply in } , errorHandler: { error in } ) }
iPhone側
func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) { if let watchMessage = message["fromChild"] as? String { print(watchMessage) } else{ print("error") } }
2. 対策
replyHandlerを設定するなど、いろいろ情報はあったのですが、結局 sendMessage() を諦め、updateApplicationContext() を使うことにしました。
ただ updateApplicationContext() は状態が変わった際に通知するためのメソッドなので、二回目以降の値が変わらないとiPhone側のメソッドが呼び出されません。
API仕様書には明記されていませんがそのような動きをしています。(「3. 参考ページ」参照)
ですので、sendMessage() と同じように使いたい場合は、毎回変わる値をダミーとして設定すると実現できます。(多少強引ですが、下記例では時間を設定しています)
AppleWatch側
@IBAction func tapButton() { let dateFormatter = DateFormatter() dateFormatter.locale = Locale(identifier: "ja_JP") dateFormatter.timeStyle = .medium dateFormatter.dateStyle = .medium let item: Dictionary<String, String> = [ "message": "AppleWatchからのメッセージ" , "date": dateFormatter.string(from: NSDate() as Date)] let message = [ "fromChild": item ] do{ try WCSession.default().updateApplicationContext(message) }catch{ print(error) } }
iPhone側
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) { DispatchQueue.main.async { () -> Void in if let watchMessage = applicationContext["fromChild"] as? Dictionary<String, String> { self.label.text = watchMessage["message"]! as String } } return }