22
votes

Is it possible to differentiate between the cases where

  1. an iOS user has explicitly denied user notification permissions, and
  2. an iOS user has never been prompted for permission?

My situation: In the past, I've prompted for user notification permission, but never kept track of requests myself. Later, I stopped attempting to register any notification settings. Now, I'd like to re-introduce user notifications.

After a significant event in the App, my plan is to display some sort of UI that explains the benefit of opting in to user notifications. However, if the user has already declined, I'd prefer to show a separate UI that can take them into Settings.app.

Currently, I'm using -[UIApplication currentUserNotificationSettings] to grab the current settings, but it appears that this returns UIUserNotificationTypeNone for both of the above described cases.

5

5 Answers

24
votes

Personally I haven't found a way to determine this via a quick query of the iOS SDK.

However I have been able to track this myself recording when -[UIApplication application:didRegisterUserNotificationSettings:] is called.

When iOS calls this method, you can be sure the user has been prompted for user notification permissions and has (importantly) either accepted or denied it.

Storing when this occurs you can later check this value to determine if the prompt has been shown before or not.

Example Code:

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"ABHasPromptedForUserNotification"];
    //... your other notification registration handling... 
}

- (BOOL)hasPromptedForUserNotification {
    return [[NSUserDefaults standardUserDefaults] boolForKey:@"ABHasPromptedForUserNotification"];
}

FYI: I've found it preferable to set "ABHasPromptedForUserNotification" as true in the in -[UIApplication application:didRegisterUserNotificationSettings:] rather than when I call -[UIApplication registerForRemoteNotifications] as in some situations the user can be shown the prompt multiple times. This can happen if the user backgrounds the app, or takes a call. In these cases the prompt will be hidden by iOS, and shown again if next time you call -[UIApplication registerForRemoteNotifications]. Setting this setting in the delegate avoids thinking the user has been prompted before and won't be prompted again in these edge cases.

3
votes

No.

And I believe this is done intentionally. Because usual scenario is to register for remote notifications on every app launch. That means that user should not see permissions dialog each time he opens the app. iOS do this automatically. But if you will show extra screen before requesting permissions Apple can't allow you to know if user denied permissions in the past so you can show screen describing how user can enable his permissions through settings each time you want. This will undo all Apple did to stop irritating users.

In your case you must follow same strategy. Show only one type of explanatory screen on both scenarios and save user choice in NSUserDefaults to know if you must not show it again. Users who denied permissions previosly will not see permissions dialog. Though you'll have one benefit for new users (which is obviously you are trying to achieve): you may keep showing explanatory screen many times if user canceled it.

1
votes

If you support iOS 10 and above the UNUserNotifications framework allows more granularity.

let current = UNUserNotificationCenter.current()
current.getNotificationSettings(completionHandler: { (settings) in
    if settings.authorizationStatus == .notDetermined {
        // Not requested
    }

    if settings.authorizationStatus == .denied {
        // User said Don't allow
    }
})
0
votes

In case someone need to check the old UIUserNotification API for access permission. code below is tried and tested.

- (BOOL)isUserNotificationAllowed {
    UIUserNotificationType types = [[UIApplication sharedApplication] currentUserNotificationSettings].types;
    if(types & UIUserNotificationTypeBadge || types & UIUserNotificationTypeSound || types & UIUserNotificationTypeAlert){
        return YES;
    }
    else {
        return NO;
    }
}
0
votes

Update for iOS 10.0+.
Apple provide this for checking user's push notification permission status:

[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
switch (settings.authorizationStatus) {
  case UNAuthorizationStatusNotDetermined:
    DDLogDebug(@"Not Determined");
    break;
  case UNAuthorizationStatusDenied:
    DDLogDebug(@"Denied");
    break;
  case UNAuthorizationStatusAuthorized:
    DDLogDebug(@"Authorized");
    break;
  case UNAuthorizationStatusProvisional:
    DDLogDebug(@"Provisional");
    break;
}
}];

Check Apple Doc for more information.