1

イベントをログに記録するためにタップできるボタンを備えた Apple Watch アプリがあります。イベントがログに記録されたら、アプリ内の保留中のローカル通知をすべてキャンセルしたいと考えています。問題は、ローカル通知がキャンセルされる場合とキャンセルされない場合があることです。

Watch アプリのコードは次のとおりです。ボタンがタップされると、iPhone アプリにメッセージを送信します。

func buttonTapped() {

    // check to make sure the session is reachable, so a message can be sent
    if session.reachable == true {

        // a dict containing the date of the event to be sent to the iPhone
        let dict = ["date" : NSDate()]

        // send the dict and specify the replyHandler
        session.sendMessage(dict, replyHandler: { (reply) in

                if reply["success"] as? Bool == true {

                    print("notifications were cancelled")
                }

            }, errorHandler: { (error) in

                // some kind of error has occurred
            }
        )
    }
}

iPhone の AppDelegate では、メッセージを受信するために WatchConnectivity デリゲート メソッドを実装しました。ここで通知がクリアされます。次に、replyHandler が呼び出され、メッセージが正常に受信および処理されたことを Watch アプリに示します。

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

    if message["date"] != nil {

        dispatch_async(dispatch_get_main_queue()){

            let reply = ["success" : true]

            UIApplication.sharedApplication().cancelAllLocalNotifications()

            // send the reply to the Watch to confirm all this has happened
            replyHandler(reply)
        }
    }
}

正常な応答が Watch に返されたのを確認しても、ローカル通知が実際にはキャンセルされないことがあります。

これは iOS または watchOS のバグであり、私が回避できるものではないのでしょうか? アプリがバックグラウンドで起動されている場合、特定の API へのアクセスが保証されていない可能性がありますか? (これは、WatchConnectivity でメッセージを送信するときに何が起こるかのようです)

4

1 に答える 1

1

このように AppDelegate でメッセージが受信されると、アプリはバックグラウンドで起動されます (マルチタスク画面に表示されなくても)。しかし、iOS にバックグラウンド タイムを明示的に要求していなかったので、私のコードdidReceiveMessageが常に完全に実行されているとは限りませんでした。

解決策は、バックグラウンド時間を具体的に尋ねることでした。これを機能させるために変更didReceiveMessageした方法は次のとおりです。

// initialize a background task identifier
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid

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

    if message["date"] != nil {

        dispatch_async(dispatch_get_main_queue()){

            // begin the background task
            self.backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithName("CancelNotifications", expirationHandler: {

                // this expirationHandler will be called to end and invalidate the background task in case it doesn't have enough time to complete

                UIApplication.sharedApplication().endBackgroundTask(self.backgroundTask)
                self.backgroundTask = UIBackgroundTaskInvalid
            })

            let reply = ["success" : true]

            UIApplication.sharedApplication().cancelAllLocalNotifications()

            // send the reply to the Watch to confirm all this has happened
            replyHandler(reply)

            // let iOS know the background task is done
            UIApplication.sharedApplication().endBackgroundTask(self.backgroundTask)
            self.backgroundTask = UIBackgroundTaskInvalid
        }
    }
}

この問題を解決する方法を教えてくれた、HeartWatch (素晴らしい Apple Watch と iPhone のアプリ) の作成者であるDavid Walsh に大いに感謝します!

于 2016-06-08T16:13:42.033 に答える