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