Локальные уведомления не отменяются, когда iPhone получает сообщение от сопряженных Apple Watch (иногда)

У меня есть приложение 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
            }
        )
    }
}

В AppDelegate на iPhone я реализовал метод делегата 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)

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), который показал мне, как решить эту проблему!

Другие вопросы по тегам