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

我正在寻找一种方法来确定用户是否有,通过设置,启用或禁用他们的推送通知我的应用程序。

124484 次浏览

调用enabledRemoteNotificationsTypes并检查掩码。

例如:

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

iOS8及以上:

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]

quantumpotato的问题:

其中types

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

可以使用

if (types & UIRemoteNotificationTypeAlert)

而不是

if (types == UIRemoteNotificationTypeNone)

将允许你只检查通知是否启用(不用担心声音,徽章,通知中心等)。如果“Alert Style”设置为“banner”或“Alerts”,第一行代码(types & UIRemoteNotificationTypeAlert)将返回YES,如果“Alert Style”设置为“None”,则返回NO,无论其他设置如何。

再保险:

这是正确的

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

为了完成这个答案,它可以这样工作……

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;
}
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types & UIRemoteNotificationTypeAlert)
// blah blah blah
{
NSLog(@"Notification Enabled");
}
else
{
NSLog(@"Notification not enabled");
}

这里我们从UIApplication获得UIRemoteNotificationType。它代表了这个应用程序在设置中的推送通知的状态,然后你可以很容易地检查它的类型

在最新版本的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;
}

尽管Zac的答案在iOS 7之前是完全正确的,但自从iOS 8到来后,它就发生了变化。因为enabledRemoteNotificationTypes从iOS 8起已弃用。对于iOS 8及更高版本,你需要使用isRegisteredForRemoteNotifications

  • —>使用enabledRemoteNotificationTypes
  • >使用isregisteredforremotenotifizations。

对于iOS7和之前,你确实应该使用enabledRemoteNotificationTypes并检查它是否等于(或不等于取决于你想要什么)UIRemoteNotificationTypeNone

然而,对于iOS8, 总是足够只检查isRegisteredForRemoteNotifications如上所述的许多状态。你还应该检查application.currentUserNotificationSettings.types是否等于(或不等于取决于你想要什么)UIUserNotificationTypeNone!

即使currentUserNotificationSettings.types返回UIUserNotificationTypeNoneisRegisteredForRemoteNotifications也可能返回true。

下面是一个完整的例子,涵盖了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");

在尝试同时支持iOS8和更低版本时,我并没有像Kevin建议的那样使用isRegisteredForRemoteNotifications。相反,我使用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;
}

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
}

不幸的是,这些解决方案都没有解决这个问题,因为在一天结束时,api严重缺乏提供相关的信息。你可以做一些猜测,但是使用currentUserNotificationSettings (iOS8+)在目前的形式下还不足以真正回答这个问题。虽然这里的许多解决方案似乎表明,要么isRegisteredForRemoteNotifications是一个更明确的答案,但它真的不是。

考虑一下:

isRegisteredForRemoteNotifications文档声明:

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

然而,如果你在你的应用委托中抛出一个简单的NSLog来观察它的行为,很明显它的行为并不像我们预期的那样。它实际上直接属于该应用程序/设备已激活的远程通知。一旦第一次激活,它将总是返回YES。即使在设置(通知)中关闭它们,仍然会导致这个返回YES,这是因为,从iOS8开始,一个应用程序可能会注册远程通知,甚至在用户未启用通知的情况下发送到设备,他们只是可能不会在用户未启用通知的情况下执行警报、徽章和声音。无声通知就是一个很好的例子,即使关闭通知,你也可以继续做一些事情。

currentUserNotificationSettings而言,它表示以下四种情况之一:

警报打开 徽章都戴上了 声音开着

这完全没有给你任何关于其他因素或通知开关本身的指示。

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

我们可以做一些猜测:

  • 如果isRegisteredForRemoteNotificationsNO,则可以假设该设备从未成功注册远程通知。
  • 在第一次为远程通知注册后,将回调到application:didRegisterUserNotificationSettings:,其中包含用户通知设置,因为这是用户第一次注册,设置应该指示用户根据权限请求选择了什么。如果设置等同于:UIUserNotificationTypeNone以外的任何内容,则授予推送权限,否则将拒绝。原因是,从您开始远程注册过程的那一刻起,用户只有接受或拒绝的能力,接受的初始设置是您在注册过程中设置的设置。

完全容易复制和粘贴代码构建从@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 !

斯威夫特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可观察的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()
}
}
}

这个中高阶层解决方案很适合我(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")
}
}

< a href = " https://stackoverflow.com/a/39664778/3411787 " > Ref < / >

下面是如何在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方法。

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

在Xamarin,所有上述解决方案都不适合我。 这就是我所使用的:

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

当你在设置中更改通知状态后,它也会得到实时更新。

我尝试使用@Shaheen ghassy提供的解决方案支持iOS 10及以上,但发现剥夺问题enabledRemoteNotificationTypes。所以,我找到的解决方案是使用isRegisteredForRemoteNotifications而不是在iOS 8中弃用的enabledRemoteNotificationTypes。下面是我最新的解决方案,对我来说非常有效:

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

希望它也能帮助其他人:) 快乐的编码。< / p >