在iPhone上确定用户是否已启用推送通知


Answers:


300

呼叫enabledRemoteNotificationsTypes并检查面罩。

例如:

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types == UIRemoteNotificationTypeNone) 
   // blah blah blah

iOS8及以上:

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]

19
iOS 5:无论应用程序是否在手机的通知中心内,它都会检查应用程序使用哪种类型的推送通知。我为我的应用程序禁用了推送通知,仍然具有类型==6。在禁用声音和警报样式后,我得到了类型== UIRemoteNotificationTypeNone。
Quantumpotato 2011年

4
正如quantumpotato指出的那样,该答案不再能够处理所有情况,也不是一个完整的解决方案。
DBD 2012年

5
苹果怎么了?我希望我能听到他们对这个问题的回应。我们如何在不了解此类基本信息的情况下开发出色的应用程序?
Oded Regev

15
@ZacBowling- iOS 8和更高版本的解决方案是错误的,因为它仅检查用户是否注册了远程通知。根据文档:This method reflects only the successful completion of the remote registration process that begins when you call the registerForRemoteNotifications method. This method does not reflect whether remote notifications are actually available due to connectivity issues. The value returned by this method takes into account the user’s preferences for receiving remote notifications.
Apan

5
因此,我认为您还应该检查一下[[UIApplication sharedApplication] currentUserNotificationSettings];
Apan 2015年

99

Quantumpotato的问题:

types由哪里给出

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

一个可以使用

if (types & UIRemoteNotificationTypeAlert)

代替

if (types == UIRemoteNotificationTypeNone) 

将仅允许您检查通知是否已启用(不必担心声音,徽章,通知中心等)。如果“ Alert Style”设置为“ Banners”或“ Alerts”,并且如果“ Alert Style”设置为“ None”,则与其他设置无关,types & UIRemoteNotificationTypeAlert将返回第一行代码()。YESNO


这不能解决quantumpotato的问题。他不仅仅关注警报,还指出您无法通过enabledRemoteNotifications辨别用户是打开还是关闭了通知中心设置。
乔伊

8
我的答案可能不会直接回答“如何确定应用程序是否在通知中心中”,但确实提供了一种方法来检查用户是否会收到有关您的应用程序的通知,我认为这是问题的实质。 。我认为无法检查前者。
Tim Camber

2
“ if(types&UIRemoteNotificationTypeAlert)”的技巧非常好。
nembleton 2014年

确保您了解该技巧为何起作用!按位运算符非常有用,并且位掩码在Cocoa中很常见。退房stackoverflow.com/a/3427633/1148702
Tim Camber

2
在Swift2 / XCode7中,按位运算失败,错误为二进制运算符'&'无法应用于两个'UIUserNotificationType'操作数。您可以改用ContainsgrantedSettings.types.contains(notificationType)
Philipp Otto

54

在iOS的最新版本中,不建议使用此方法。要同时支持iOS 7和iOS 8,请使用:

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;
}

2
本地通知呢?iOS 8现在要求用户允许他们。但是,随后如何检查这些文件是否被允许?
弗雷德里克·阿达

@FredA。检查UserNotifications。不幸的是,我现在没有完整的答案。
Mazyod 2015年


3
在Swift中,我无法启用=类型和UIRemoteNotificationTypeAlert。错误:类型
不尽人意

53

更新了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()
}

swift3.0,iOS10的代码

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

从iOS9开始,不推荐使用swift 2.0 UIRemoteNotificationType,请使用以下代码

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.

}

只需检查是否启用了推送通知

    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
    }

33

在下面,您将找到一个涵盖iOS8和iOS7(及更低版本)的完整示例。请注意,在iOS8之前,您无法区分“禁用了远程通知”和“仅启用了在锁定屏幕中查看 ”。

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");

6
userNotificationSettings.types和UIUserNotificationTypeNone始终为false,因为UIUserNotificationTypeNone是空位掩码,其他位均不存在。对于None,您只想检查相等性。
dberwick

25

迅捷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
    }

适用于iOS10 +的RxSwift可观察版本:

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()
        }
    }
}

1
你救了我的一天。:)
Chetan Dobariya

1
谢谢,我正在搜索一个小时。
Chanchal Warde

4
getNotificationSettings(...)是异步的,因此内部的返回将被忽略
shelll

17

在尝试同时支持iOS8和更低版本时,我没有isRegisteredForRemoteNotifications像Kevin所建议的那样运气很好。相反,我使用currentUserNotificationSettings,它在我的测试中效果很好。

+ (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;
}

刚安装该应用程序时,这不适用。该方法将始终返回NO,并且推送通知的弹出权限将永远不会出现。因此,在设备的设置上,如果您想更改该应用程序的通知设置(允许/禁止),则该应用程序将不会出现。任何人都知道如何解决此问题吗?
tyegah123

即使删除应用程序,通知设置也会保留。因此,如果您的应用程序是全新的,则此方法将起作用。如果您的应用已删除但随后重新安装,则权限仍在系统中,Apple不会为您提供重新要求权限的机会。
Shaheen Ghiassy

我看到一些多余的代码:isEnabled = NO;在您的if情况下,由于它已初始化为NO
Jasper

15

不幸的是,提供的这些解决方案中没有一个能够真正解决问题,因为最终在提供相关信息时API严重不足。您可以做出一些猜测,但是使用currentUserNotificationSettings(iOS8 +)只是目前的形式还不足以真正回答问题。尽管这里的许多解决方案似乎都暗示了这个isRegisteredForRemoteNotifications答案,或者实际上是一个明确的答案,但实际上并非如此。

考虑一下:

具有isRegisteredForRemoteNotifications文档状态:

如果当前已为远程通知注册了应用程序,则返回YES,并考虑到系统范围内的任何设置...

但是,如果您将一个简单的对象NSLog放入应用程序委托中以观察行为,则很明显,这与我们预期的行为不符。实际上,它直接与此应用/设备已激活的远程通知有关。首次激活后,它将始终返回YES。即使在设置(通知)中将其关闭,这仍然会返回YES此结果,这是因为自iOS8起,一个应用可能会注册远程通知,甚至在用户未启用通知的情况下发送到设备,他们可能不会执行提醒,徽章和声音,而无需用户打开。无提示通知是即使关闭通知后您仍可以继续执行的操作的一个很好的示例。

currentUserNotificationSettings它指示的四件事之一:

警报处于启用状态徽章处于启用状态声音处于启用状态。

这绝对不会给您任何有关其他因素或通知开关本身的指示。

用户实际上可以关闭徽章,声音和警报,但仍在锁屏或通知中心中显示。该用户应该仍在接收推送通知,并且能够在锁定屏幕和通知中心中看到它们。他们打开了通知开关。但currentUserNotificationSettings将返回:UIUserNotificationTypeNone在这种情况下。这并不能真正表明用户的实际设置。

可以做出一些猜测:

  • 如果isRegisteredForRemoteNotifications是,NO则可以假定该设备从未成功注册过远程通知。
  • 在第一次注册远程通知之后,application:didRegisterUserNotificationSettings:由于这是第一次注册用户,因此此时将进行一次包含用户通知设置的回调,该设置指示用户根据权限请求选择的内容。如果设置等于:以外的任何其他设置,UIUserNotificationTypeNone则将授予推送权限,否则将被拒绝。这样做的原因是,从您开始远程注册过程的那一刻起,用户仅具有接受或拒绝的能力,接受的初始设置是您在注册过程中设置的设置。

8

为了完成答案,它可以像这样工作...

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

编辑:这是不对的。由于这些都是按位操作,因此无法与开关配合使用,因此我结束了以下操作:

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

我认为(针对我的情况)未启用声音通知(因为我需要文本才能考虑将其用于我的应用程序功能)
pojomx

5

对于iOS7及更高版本,您确实应该使用enabledRemoteNotificationTypes并检查它是否等于(或取决于您想要的东西而不同)UIRemoteNotificationTypeNone

但是,对于iOS8 ,仅检查上面的状态并不总是足够的isRegisteredForRemoteNotifications。您还应该检查是否application.currentUserNotificationSettings.types等于(或不等于取决于您想要的)UIUserNotificationTypeNone

isRegisteredForRemoteNotifications即使currentUserNotificationSettings.types返回也可能返回true UIUserNotificationTypeNone


5

iOS8 +(目标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;
    }
}];

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

在这里,我们从UIApplication获取UIRemoteNotificationType。它表示该应用在设置中的推送通知状态,因此您可以轻松检查其类型


3
请解释此代码的作用,编写代码并不能简单地回答问题。
巴蒂2014年

4

我尝试使用@Shaheen Ghiassy提供的解决方案来支持iOS 10及更高版本,但发现存在剥夺问题enabledRemoteNotificationTypes。因此,我找到了通过使用的解决方案,isRegisteredForRemoteNotifications而不是enabledRemoteNotificationTypes在iOS 8中弃用的解决方案。以下是我更新的解决方案,对我来说非常理想:

- (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;
}

我们可以轻松地调用此函数并访问其Bool值,并可以通过以下方式将其转换为字符串值:

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

希望它也会对其他人有所帮助:)祝您编程愉快。


3

尽管Zac的答案在iOS 7之前是完全正确的,但自iOS 8到来以来,答案已经改变。因为从iOS 8开始不推荐使用enabledRemoteNotificationTypes。对于iOS 8及更高版本,您需要使用isRegisteredForRemoteNotifications

  • 对于iOS 7及更高版本->使用enabledRemoteNotificationTypes
  • 对于iOS 8及更高版本->使用isRegisteredForRemoteNotifications。

2

这个Swifty解决方案对我来说非常有效(iOS8 +),

方法

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)
        }
    }
}

用法

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

参考


0

回覆:

这是对的

if (types & UIRemoteNotificationTypeAlert)

但是跟随也是正确的!(因为UIRemoteNotificationTypeNone为0)

if (types == UIRemoteNotificationTypeNone) 

见以下

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

0

这是在Xamarin.ios中执行此操作的方法。

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

如果您支持iOS 10+,则只能使用UNUserNotificationCenter方法。


0

在Xamarin中,以上所有解决方案均不适用于我。这是我改用的:

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

在“设置”中更改通知状态后,它还会实时更新。


-1

从@ZacBowling解决方案(https://stackoverflow.com/a/1535427/2298002)构建的完全简单的复制和粘贴代码

这还将使用户进入您的应用设置,并允许他们立即启用

我还添加了一个解决方案,用于检查是否启用了位置服务(以及设置)

// 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!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.