[ios] Determine on iPhone if user has enabled push notifications

I'm looking for a way to determine if the user has, via settings, enabled or disabled their push notifications for my application.

This question is related to ios iphone notifications apple-push-notifications push

The answer is


In the latest version of iOS this method is now deprecated. To support both iOS 7 and iOS 8 use:

UIApplication *application = [UIApplication sharedApplication];

BOOL enabled;

// Try to use the newer isRegisteredForRemoteNotifications otherwise use the enabledRemoteNotificationTypes.
if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
    enabled = [application isRegisteredForRemoteNotifications];
}
else
{
    UIRemoteNotificationType types = [application enabledRemoteNotificationTypes];
    enabled = types & UIRemoteNotificationTypeAlert;
}

To complete the answer, it could work something like this...

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
switch (types) {
   case UIRemoteNotificationTypeAlert:
   case UIRemoteNotificationTypeBadge:
       // For enabled code
       break;
   case UIRemoteNotificationTypeSound:
   case UIRemoteNotificationTypeNone:
   default:
       // For disabled code
       break;
}

edit: This is not right. since these are bit-wise stuff, it wont work with a switch, so I ended using this:

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
UIRemoteNotificationType typesset = (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge);
if((types & typesset) == typesset)
{
    CeldaSwitch.chkSwitch.on = true;
}
else
{
    CeldaSwitch.chkSwitch.on = false;
}

re:

this is correct

if (types & UIRemoteNotificationTypeAlert)

but following is correct too ! (as UIRemoteNotificationTypeNone is 0 )

if (types == UIRemoteNotificationTypeNone) 

see the following

NSLog(@"log:%d",0 & 0); ///false
NSLog(@"log:%d",1 & 1); ///true
NSLog(@"log:%d",1<<1 & 1<<1); ///true
NSLog(@"log:%d",1<<2 & 1<<2); ///true
NSLog(@"log:%d",(0 & 0) && YES); ///false
NSLog(@"log:%d",(1 & 1) && YES); ///true
NSLog(@"log:%d",(1<<1 & 1<<1) && YES); ///true
NSLog(@"log:%d",(1<<2 & 1<<2) && YES); ///true

In trying to support both iOS8 and lower, I didn't have much luck using isRegisteredForRemoteNotifications as Kevin suggested. Instead I used currentUserNotificationSettings, which worked great in my testing.

+ (BOOL)notificationServicesEnabled {
    BOOL isEnabled = NO;

    if ([[UIApplication sharedApplication] respondsToSelector:@selector(currentUserNotificationSettings)]){
        UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];

        if (!notificationSettings || (notificationSettings.types == UIUserNotificationTypeNone)) {
            isEnabled = NO;
        } else {
            isEnabled = YES;
        }
    } else {
        UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
        if (types & UIRemoteNotificationTypeAlert) {
            isEnabled = YES;
        } else{
            isEnabled = NO;
        }
    }

    return isEnabled;
}

Full easy copy and paste code built from @ZacBowling's solution (https://stackoverflow.com/a/1535427/2298002)

this will also bring the user to your app settings and allow them to enable immediately

I also added in a solution for checking if location services is enabled (and brings to settings as well)

// check if notification service is enabled
+ (void)checkNotificationServicesEnabled
{
    if (![[UIApplication sharedApplication] isRegisteredForRemoteNotifications])
    {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Notification Services Disabled!"
                                                            message:@"Yo don't mess around bro! Enabling your Notifications allows you to receive important updates"
                                                           delegate:self
                                                  cancelButtonTitle:@"Cancel"
                                                  otherButtonTitles:@"Settings", nil];

        alertView.tag = 300;

        [alertView show];

        return;
    }
}

// check if location service is enabled (ref: https://stackoverflow.com/a/35982887/2298002)
+ (void)checkLocationServicesEnabled
{
    //Checking authorization status
    if (![CLLocationManager locationServicesEnabled] || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied)
    {

        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Location Services Disabled!"
                                                            message:@"You need to enable your GPS location right now!!"
                                                           delegate:self
                                                  cancelButtonTitle:@"Cancel"
                                                  otherButtonTitles:@"Settings", nil];

        //TODO if user has not given permission to device
        if (![CLLocationManager locationServicesEnabled])
        {
            alertView.tag = 100;
        }
        //TODO if user has not given permission to particular app
        else
        {
            alertView.tag = 200;
        }

        [alertView show];

        return;
    }
}

// handle bringing user to settings for each
+ (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{

    if(buttonIndex == 0)// Cancel button pressed
    {
        //TODO for cancel
    }
    else if(buttonIndex == 1)// Settings button pressed.
    {
        if (alertView.tag == 100)
        {
            //This will open ios devices location settings
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=LOCATION_SERVICES"]];
        }
        else if (alertView.tag == 200)
        {
            //This will open particular app location settings
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
        }
        else if (alertView.tag == 300)
        {
            //This will open particular app location settings
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
        }
    }
}

GLHF!


Below you'll find a complete example that covers both iOS8 and iOS7 (and lower versions). Please note that prior to iOS8 you can't distinguish between "remote notifications disabled" and "only View in lockscreen enabled".

BOOL remoteNotificationsEnabled = false, noneEnabled,alertsEnabled, badgesEnabled, soundsEnabled;

if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
    // iOS8+
    remoteNotificationsEnabled = [UIApplication sharedApplication].isRegisteredForRemoteNotifications;

    UIUserNotificationSettings *userNotificationSettings = [UIApplication sharedApplication].currentUserNotificationSettings;

    noneEnabled = userNotificationSettings.types == UIUserNotificationTypeNone;
    alertsEnabled = userNotificationSettings.types & UIUserNotificationTypeAlert;
    badgesEnabled = userNotificationSettings.types & UIUserNotificationTypeBadge;
    soundsEnabled = userNotificationSettings.types & UIUserNotificationTypeSound;

} else {
    // iOS7 and below
    UIRemoteNotificationType enabledRemoteNotificationTypes = [UIApplication sharedApplication].enabledRemoteNotificationTypes;

    noneEnabled = enabledRemoteNotificationTypes == UIRemoteNotificationTypeNone;
    alertsEnabled = enabledRemoteNotificationTypes & UIRemoteNotificationTypeAlert;
    badgesEnabled = enabledRemoteNotificationTypes & UIRemoteNotificationTypeBadge;
    soundsEnabled = enabledRemoteNotificationTypes & UIRemoteNotificationTypeSound;
}

if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
    NSLog(@"Remote notifications enabled: %@", remoteNotificationsEnabled ? @"YES" : @"NO");
}

NSLog(@"Notification type status:");
NSLog(@"  None: %@", noneEnabled ? @"enabled" : @"disabled");
NSLog(@"  Alerts: %@", alertsEnabled ? @"enabled" : @"disabled");
NSLog(@"  Badges: %@", badgesEnabled ? @"enabled" : @"disabled");
NSLog(@"  Sounds: %@", soundsEnabled ? @"enabled" : @"disabled");

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types & UIRemoteNotificationTypeAlert)
    // blah blah blah
{
    NSLog(@"Notification Enabled");
}
else
{
    NSLog(@"Notification not enabled");
}

Here we get the UIRemoteNotificationType from UIApplication. It represents the state of push notification of this app in the setting, than you can check on its type easily


For iOS7 and before you should indeed use enabledRemoteNotificationTypes and check if it equals (or doesn't equal depending on what you want) to UIRemoteNotificationTypeNone.

However for iOS8 it is not always enough to only check with isRegisteredForRemoteNotifications as many state above. You should also check if application.currentUserNotificationSettings.types equals (or doesn't equal depending on what you want) UIUserNotificationTypeNone!

isRegisteredForRemoteNotifications might return true even though currentUserNotificationSettings.types returns UIUserNotificationTypeNone.


Updated code for swift4.0 , iOS11

import UserNotifications

UNUserNotificationCenter.current().getNotificationSettings { (settings) in
   print("Notification settings: \(settings)")
   guard settings.authorizationStatus == .authorized else { return }

   //Not authorised 
   UIApplication.shared.registerForRemoteNotifications()
}

Code for swift3.0 , iOS10

    let isRegisteredForRemoteNotifications = UIApplication.shared.isRegisteredForRemoteNotifications
    if isRegisteredForRemoteNotifications {
        // User is registered for notification
    } else {
        // Show alert user is not registered for notification
    }

From iOS9 , swift 2.0 UIRemoteNotificationType is deprecated, use following code

let notificationType = UIApplication.shared.currentUserNotificationSettings!.types
if notificationType == UIUserNotificationType.none {
        // Push notifications are disabled in setting by user.
    }else{
  // Push notifications are enabled in setting by user.

}

simply check whether Push notifications are enabled

    if notificationType == UIUserNotificationType.badge {
        // the application may badge its icon upon a notification being received
    }
    if notificationType == UIUserNotificationType.sound {
        // the application may play a sound upon a notification being received

    }
    if notificationType == UIUserNotificationType.alert {
        // the application may display an alert upon a notification being received
    }

Swift 3+

    if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { (settings: UNNotificationSettings) in
            // settings.authorizationStatus == .authorized
        })
    } else {
        return UIApplication.shared.currentUserNotificationSettings?.types.contains(UIUserNotificationType.alert) ?? false
    }

RxSwift Observable Version for iOS10+:

import UserNotifications
extension UNUserNotificationCenter {
    static var isAuthorized: Observable<Bool> {
        return Observable.create { observer in
            DispatchQueue.main.async {
                current().getNotificationSettings(completionHandler: { (settings: UNNotificationSettings) in
                    if settings.authorizationStatus == .authorized {
                        observer.onNext(true)
                        observer.onCompleted()
                    } else {
                        current().requestAuthorization(options: [.badge, .alert, .sound]) { (granted, error) in
                            observer.onNext(granted)
                            observer.onCompleted()
                        }
                    }
                })
            }
            return Disposables.create()
        }
    }
}

Though Zac's answer was perfectly correct till iOS 7, it has changed since iOS 8 arrived. Because enabledRemoteNotificationTypes has been deprecated from iOS 8 onwards. For iOS 8 and later, you need to use isRegisteredForRemoteNotifications.

  • for iOS 7 and before --> Use enabledRemoteNotificationTypes
  • for iOS 8 and later --> Use isRegisteredForRemoteNotifications.

iOS8+ (OBJECTIVE C)

#import <UserNotifications/UserNotifications.h>


[[UNUserNotificationCenter currentNotificationCenter]getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {

    switch (settings.authorizationStatus) {
          case UNAuthorizationStatusNotDetermined:{

            break;
        }
        case UNAuthorizationStatusDenied:{

            break;
        }
        case UNAuthorizationStatusAuthorized:{

            break;
        }
        default:
            break;
    }
}];

In Xamarin, all above solution does not work for me. This is what I use instead:

public static bool IsRemoteNotificationsEnabled() {
    return UIApplication.SharedApplication.CurrentUserNotificationSettings.Types != UIUserNotificationType.None;
}

It's getting a live update also after you've changed the notification status in Settings.


I try to support iOS 10 and above using solution provide by @Shaheen Ghiassy but find deprivation issue enabledRemoteNotificationTypes. So, the solution I find by using isRegisteredForRemoteNotifications instead of enabledRemoteNotificationTypes which deprecated in iOS 8. Below is my updated solution that worked perfectly for me:

- (BOOL)notificationServicesEnabled {
    BOOL isEnabled = NO;
    if ([[UIApplication sharedApplication] respondsToSelector:@selector(currentUserNotificationSettings)]){
        UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];

        if (!notificationSettings || (notificationSettings.types == UIUserNotificationTypeNone)) {
            isEnabled = NO;
        } else {
            isEnabled = YES;
        }
    } else {

        if ([[UIApplication sharedApplication] isRegisteredForRemoteNotifications]) {
            isEnabled = YES;
        } else{
            isEnabled = NO;
        }
    }
    return isEnabled;
}

And we can call this function easily and be accessing its Bool value and can convert it into the string value by this:

NSString *str = [self notificationServicesEnabled] ? @"YES" : @"NO";

Hope it will help others too :) Happy coding.


This Swifty solution worked well for me (iOS8+),

Method:

func isNotificationEnabled(completion:@escaping (_ enabled:Bool)->()){
    if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { (settings: UNNotificationSettings) in
            let status =  (settings.authorizationStatus == .authorized)
            completion(status)
        })
    } else {
        if let status = UIApplication.shared.currentUserNotificationSettings?.types{
            let status = status.rawValue != UIUserNotificationType(rawValue: 0).rawValue
            completion(status)
        }else{
            completion(false)
        }
    }
}

Usage:

isNotificationEnabled { (isEnabled) in
            if isEnabled{
                print("Push notification enabled")
            }else{
                print("Push notification not enabled")
            }
        }

Ref


Here's how to do this in Xamarin.ios.

public class NotificationUtils
{
    public static bool AreNotificationsEnabled ()
    {
        var settings = UIApplication.SharedApplication.CurrentUserNotificationSettings;
        var types = settings.Types;
        return types != UIUserNotificationType.None;
    }
}

If you are supporting iOS 10+ only go with the UNUserNotificationCenter method.


quantumpotato's issue:

Where types is given by

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

one can use

if (types & UIRemoteNotificationTypeAlert)

instead of

if (types == UIRemoteNotificationTypeNone) 

will allow you to check only whether notifications are enabled (and don't worry about sounds, badges, notification center, etc.). The first line of code (types & UIRemoteNotificationTypeAlert) will return YES if "Alert Style" is set to "Banners" or "Alerts", and NO if "Alert Style" is set to "None", irrespective of other settings.


Unfortunately none of these solutions provided really solve the problem because at the end of the day the APIs are seriously lacking when it comes to providing the pertinent information. You can make a few guesses however using currentUserNotificationSettings (iOS8+) just isn't sufficient in its current form to really answer the question. Although a lot of the solutions here seem to suggest that either that or isRegisteredForRemoteNotifications is more of a definitive answer it really is not.

Consider this:

with isRegisteredForRemoteNotifications documentation states:

Returns YES if the application is currently registered for remote notifications, taking into account any systemwide settings...

However if you throw a simply NSLog into your app delegate to observe the behavior it is clear this does not behave the way we are anticipating it will work. It actually pertains directly to remote notifications having been activated for this app/device. Once activated for the first time this will always return YES. Even turning them off in settings (notifications) will still result in this returning YES this is because, as of iOS8, an app may register for remote notifications and even send to a device without the user having notifications enabled, they just may not do Alerts, Badges and Sound without the user turning that on. Silent notifications are a good example of something you may continue to do even with notifications turned off.

As far as currentUserNotificationSettings it indicates one of four things:

Alerts are on Badges are on Sound is on None are on.

This gives you absolutely no indication whatsoever about the other factors or the Notification switch itself.

A user may in fact turn off badges, sound and alerts but still have show on lockscreen or in notification center. This user should still be receiving push notifications and be able to see them both on the lock screen and in the notification center. They have the notification switch on. BUT currentUserNotificationSettings will return: UIUserNotificationTypeNone in that case. This is not truly indicative of the users actual settings.

A few guesses one can make:

  • if isRegisteredForRemoteNotifications is NO then you can assume that this device has never successfully registered for remote notifications.
  • after the first time of registering for remote notifications a callback to application:didRegisterUserNotificationSettings: is made containing user notification settings at this time since this is the first time a user has been registered the settings should indicate what the user selected in terms of the permission request. If the settings equate to anything other than: UIUserNotificationTypeNone then push permission was granted, otherwise it was declined. The reason for this is that from the moment you begin the remote registration process the user only has the ability to accept or decline, with the initial settings of an acceptance being the settings you setup during the registration process.

Examples related to ios

Adding a UISegmentedControl to UITableView Crop image to specified size and picture location Undefined Symbols error when integrating Apptentive iOS SDK via Cocoapods Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Autoresize View When SubViews are Added Warp \ bend effect on a UIView? Speech input for visually impaired users without the need to tap the screen make UITableViewCell selectable only while editing Xcode 12, building for iOS Simulator, but linking in object file built for iOS, for architecture arm64

Examples related to iphone

Detect if the device is iPhone X Xcode 8 shows error that provisioning profile doesn't include signing certificate Access files in /var/mobile/Containers/Data/Application without jailbreaking iPhone Certificate has either expired or has been revoked Missing Compliance in Status when I add built for internal testing in Test Flight.How to solve? cordova run with ios error .. Error code 65 for command: xcodebuild with args: "Could not find Developer Disk Image" Reason: no suitable image found iPad Multitasking support requires these orientations How to insert new cell into UITableView in Swift

Examples related to notifications

NotificationCompat.Builder deprecated in Android O No notification sound when sending notification from firebase in android Android Push Notifications: Icon not displaying in notification, white square shown instead How to display multiple notifications in android Actionbar notification count icon (badge) like Google has How to display count of notifications in app launcher icon Android notification is not showing How to create a notification with NotificationCompat.Builder? Open application after clicking on Notification How to fix "no valid 'aps-environment' entitlement string found for application" in Xcode 4.3?

Examples related to apple-push-notifications

How to use Apple's new .p8 certificate for APNs in firebase console This certificate has an invalid issuer Apple Push Services registerForRemoteNotificationTypes: is not supported in iOS 8.0 and later Generate .pem file used to set up Apple Push Notifications Will iOS launch my app into the background if it was force-quit by the user? Detect if the app was launched/opened from a push notification Missing Push Notification Entitlement How to fix "no valid 'aps-environment' entitlement string found for application" in Xcode 4.3? Get device token for push notification iOS application: how to clear notifications?

Examples related to push

Best way to "push" into C# array Firebase: how to generate a unique numeric ID for key? Why does Git tell me "No such remote 'origin'" when I try to push to origin? Unknown SSL protocol error in connection Git push rejected "non-fast-forward" How to add multiple files to Git at the same time git push to specific branch Declare an empty two-dimensional array in Javascript? What does '--set-upstream' do? fatal: 'origin' does not appear to be a git repository