Brian Morearty Brian Morearty - 5 months ago 34
Swift Question

iOS7 and iOS8: how to detect when user said No to a request for push notifications

I am building an app that targets iOS7 and iOS8. I ask the user for permission to send push notifications. But for some reason, neither iOS7 nor iOS8 ever calls my

application:didFailToRegisterForRemoteNotificationsWithError
handler if I click "No" when asked for push permission.

My question: how do I know, on both iOS7 and iOS8, when the user has dismissed the request for push notifications--and how do I know if they denied the request?

I've looked at a bunch of StackOverflow answers and have implemented what they suggest, but it's not working as documented:


  • iOS7: if the user approves the request, the system does call my
    application:didRegisterForRemoteNotificationsWithDeviceToken:
    handler. So I can tell that they approved it. But if the user denies the request then I don't get a callback to
    application:didFailToRegisterForRemoteNotificationsWithError
    . This seems like a bug, and I can't tell that the user denied the request.

  • iOS8: if the user approves or denies the request, the system does call my
    application:didRegisterUserNotificationSettings
    handler. I can look at the
    notificationSettings
    parameter to see if the user approved or denied my request, so that's handy. However, if I subsequently call
    isRegisteredForRemoteNotifications()
    (e.g., when the app becomes active later on), it always returns true--even if the user had denied the request. So I get a false positive. This seems like a bug and I see that others have noticed this as well.
    Update: if I subsequently call
    let settings = UIApplication.sharedApplication().currentUserNotificationSettings()
    , I can check
    settings.types
    to see if alerts are allowed. So for iOS8, it looks like I'm all set.



I'm using an
NSUserDefaults
boolean to keep track of whether I've already asked the user to grant permission.

I am using hardware devices for testing (iPhone 4S with iOS7 and iPhone 5 with iOS8), not a simulator.

I am resetting my device after each test, to make it show the request alert again.

Here's how I register for push notifications. The
if
branch is taken on iOS8 and the
else
branch is taken on 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)
}


(In iOS8, when
application:didRegisterUserNotificationSettings:
is called, I then call
application.registerForRemoteNotifications()
).

Answer

Your didFailToRegisterForRemoteNotificationsWithError method isn't called, because the registration didn't fail - it was never even attempted because the user denied the request.

On iOS7 you can do a couple of things:

  1. Assume that remote notifications aren't available until didRegisterForRemoteNotificationsWithDeviceToken is called
  2. Check the value enabledRemoteNotificationTypes on the UIApplication object
Comments