IOS7 и iOS8: как определить, когда пользователь указал "Нет" на запрос для push-уведомлений
Я создаю приложение, которое предназначено для iOS7 и iOS8. Я прошу у пользователя разрешения на отправку push-уведомлений. Но по какой-то причине ни iOS7, ни iOS8 никогда не назовет моего обработчика application:didFailToRegisterForRemoteNotificationsWithError
, если я нажму "No", когда вас попросят разрешить push.
Мой вопрос:, как я узнаю, как на iOS7, так и на iOS8, когда пользователь отклонил запрос на push-уведомления - и как узнать, отклонили ли они запрос?
Я посмотрел на кучу ответов StackOverflow и реализовал то, что они предлагают, но он не работает как документированный:
- iOS7: если пользователь одобряет запрос, система вызывает мой обработчик
application:didRegisterForRemoteNotificationsWithDeviceToken:
. Поэтому я могу сказать, что они одобрили это. Но если пользователь отказывает в запросе, тогда я не получаю обратный вызов application:didFailToRegisterForRemoteNotificationsWithError
. Это похоже на ошибку, и я не могу сказать, что пользователь отказал в запросе.
- iOS8: если пользователь одобряет или отклоняет запрос, система вызывает мой обработчик
application:didRegisterUserNotificationSettings
. Я могу посмотреть параметр notificationSettings
, чтобы убедиться, что пользователь одобрил или отклонил мой запрос, так что это удобно. Однако, если я впоследствии вызову isRegisteredForRemoteNotifications()
(например, когда приложение станет активным позже), он всегда возвращает true, даже если пользователь отказал в запросе. Поэтому я получаю ложный результат. Это похоже на ошибку, и я вижу, что другие тоже это заметили. Обновление: если я впоследствии позвоню let settings = UIApplication.sharedApplication().currentUserNotificationSettings()
, я могу проверить settings.types
чтобы узнать, разрешены ли предупреждения. Итак, для iOS8, похоже, я все настроен.
Я использую NSUserDefaults
boolean для отслеживания того, спросил ли я пользователя о предоставлении разрешения.
Я использую аппаратные устройства для тестирования (iPhone 4S с iOS7 и iPhone 5 с iOS8), а не симулятор.
Я сброс моего устройства после каждого теста, чтобы он снова показывал запрос.
Здесь, как я регистрирую для push-уведомлений. Ветвь if
берется на iOS8, а ветвь else
берется на iOS7:
let application = UIApplication.sharedApplication()
if (application.respondsToSelector("registerUserNotificationSettings:")) {
let settings = UIUserNotificationSettings(forTypes: .Badge | .Alert | .Sound,
categories: nil )
application.registerUserNotificationSettings(settings)
} else {
application.registerForRemoteNotificationTypes(.Badge | .Alert | .Sound)
}
(В iOS8, когда вызывается application:didRegisterUserNotificationSettings:
, я вызываю application.registerForRemoteNotifications()
).
Ответы
Ответ 1
Ваш метод didFailToRegisterForRemoteNotificationsWithError
не вызывается, потому что регистрация не сработала - его даже не пытались, потому что пользователь отклонил запрос.
На iOS7 вы можете сделать несколько вещей:
- Предположим, что удаленные уведомления недоступны до тех пор, пока
didRegisterForRemoteNotificationsWithDeviceToken
не будет вызван
- Проверьте значение
enabledRemoteNotificationTypes
объекта UIApplication
Ответ 2
Я пытался найти способ обойти эту же проблему.
Когда отображается разрешение push-уведомления UIAlert, оно отображается за пределами моего приложения. После того, как пользователь выбрал "Не разрешать" или "ОК", мое приложение снова становится активным.
У меня есть контроллер представлений, который я представляю, прежде чем запрашивать у пользователя разрешения Push. В этом представлении контроллера я слушаю UIApplicationDidBecomeActiveNotification
, а затем отключаю свой контроллер представления.
Это работает очень хорошо, тогда как все другие решения, которые я видел, не работали для меня вообще.
Ответ 3
Предполагая, что вы компилируете iOS8 или новее, вы можете использовать следующий метод делегата:
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
print("Notifications status: \(notificationSettings)")
}
то на вашем didFinishLaunching (или где подходит для ваших нужд) вы должны вызывать:
let app = UIApplication.sharedApplication()
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
app.registerUserNotificationSettings(settings)
app.registerForRemoteNotifications()
На этом этапе вашим пользователям будет предложено типичное сообщение "Разрешить/не разрешать". Независимо от вашего выбора пользователя вы получите вызов вышеописанного метода, который позволяет получить мелкую конфигурацию вашего приложения. Результатом будет что-то вроде:
Notification Status: <UIUserNotificationSettings: 0x7fa261701da0; types: (none);>
Notification Status: <UIUserNotificationSettings: 0x7ff032e21dd0; types: (UIUserNotificationTypeAlert UIUserNotificationTypeBadge UIUserNotificationTypeSound);>
В первом случае вы заметите, что пользователь отклонил уведомления. Второй вариант - вариант разрешить.