【发布时间】:2010-12-04 20:36:03
【问题描述】:
我正在寻找一种方法来确定用户是否通过设置启用或禁用了我的应用程序的推送通知。
【问题讨论】:
标签: ios iphone notifications apple-push-notifications push
我正在寻找一种方法来确定用户是否通过设置启用或禁用了我的应用程序的推送通知。
【问题讨论】:
标签: ios iphone notifications apple-push-notifications push
量子土豆的问题:
types 由以下给出
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
可以使用
if (types & UIRemoteNotificationTypeAlert)
而不是
if (types == UIRemoteNotificationTypeNone)
将只允许您检查通知是否已启用(不必担心声音、徽章、通知中心等)。如果“警报样式”设置为“横幅”或“警报”,第一行代码 (types & UIRemoteNotificationTypeAlert) 将返回 YES,如果“警报样式”设置为“无”,则返回 NO,无论其他设置。
【讨论】:
grantedSettings.types.contains(notificationType)
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;
}
}];
【讨论】:
更新了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
}
【讨论】:
我尝试使用 @Shaheen Ghiassy 提供的解决方案支持 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";
希望它也能帮助其他人:) 编码愉快。
【讨论】:
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
}
适用于 iOS10+ 的 RxSwift Observable 版本:
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()
}
}
}
【讨论】:
getNotificationSettings(...) 是异步的,所以里面的返回会被忽略
致电enabledRemoteNotificationsTypes并检查口罩。
例如:
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types == UIRemoteNotificationTypeNone)
// blah blah blah
iOS8 及以上:
[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]
【讨论】:
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.
[[UIApplication sharedApplication] currentUserNotificationSettings];
在 Xamarin 中,上述所有解决方案都不适合我。 这是我改用的:
public static bool IsRemoteNotificationsEnabled() {
return UIApplication.SharedApplication.CurrentUserNotificationSettings.Types != UIUserNotificationType.None;
}
在您更改“设置”中的通知状态后,它也会获得实时更新。
【讨论】:
这是在 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 方法。
【讨论】:
这个 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")
}
}
【讨论】:
从@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!
【讨论】:
不幸的是,所提供的这些解决方案都没有真正解决问题,因为归根结底,在提供相关信息方面,API 严重缺乏。您可以做出一些猜测,但是使用 currentUserNotificationSettings (iOS8+) 以目前的形式不足以真正回答这个问题。尽管这里的许多解决方案似乎都表明,或者isRegisteredForRemoteNotifications 是一个更明确的答案,但实际上并非如此。
考虑一下:
isRegisteredForRemoteNotifications 文档说明:
如果应用程序当前注册了远程通知,则返回 YES,考虑到任何系统范围的设置...
但是,如果您将一个简单的 NSLog 扔到您的应用程序委托中以观察行为,很明显这不会按照我们预期的方式运行。它实际上与已为此应用程序/设备激活的远程通知直接相关。首次激活后,它将始终返回 YES。即使在设置(通知)中关闭它们仍然会导致返回 YES 这是因为,从 iOS8 开始,应用程序可能会注册远程通知,甚至在用户未启用通知的情况下发送到设备,他们可能不会无需用户打开警报、徽章和声音。静默通知是一个很好的例子,即使通知关闭,您也可以继续执行。
就currentUserNotificationSettings而言,它表示以下四件事之一:
警报已开启 徽章已开启 声音已开启 没有开启。
这绝对不会让您知道其他因素或通知开关本身。
用户实际上可能会关闭徽章、声音和警报,但仍会在锁屏或通知中心显示。该用户应该仍会收到推送通知,并且能够在锁定屏幕和通知中心看到它们。他们打开了通知开关。但currentUserNotificationSettings 将返回:UIUserNotificationTypeNone 在这种情况下。这并不代表用户的实际设置。
可以做出一些猜测:
isRegisteredForRemoteNotifications 是NO,那么您可以假设此设备从未成功注册远程通知。application:didRegisterUserNotificationSettings:,其中包含用户通知设置,因为这是用户第一次注册,设置应该表明什么根据权限请求选择的用户。如果设置等于:UIUserNotificationTypeNone 以外的任何设置,则授予推送权限,否则拒绝。这样做的原因是,从您开始远程注册过程的那一刻起,用户只能接受或拒绝,接受的初始设置就是您在注册过程中设置的设置。【讨论】:
您将在下面找到一个涵盖 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;
}
【讨论】:
isEnabled = NO; 在您的if 案例中不需要,因为它已被初始化为NO
对于 iOS7 及之前的版本,您确实应该使用 enabledRemoteNotificationTypes 并检查它是否等于(或不等于,取决于您想要的)UIRemoteNotificationTypeNone。
但是对于 iOS8 来说,不总是足以只检查isRegisteredForRemoteNotifications 上面的许多状态。您还应该检查 application.currentUserNotificationSettings.types 是否等于(或不等于,取决于您想要的)UIUserNotificationTypeNone!
isRegisteredForRemoteNotifications 可能返回 true,即使 currentUserNotificationSettings.types 返回 UIUserNotificationTypeNone。
【讨论】:
虽然 Zac 的答案在 iOS 7 之前是完全正确的,但自从 iOS 8 到来后它已经发生了变化。因为 enabledRemoteNotificationTypes 从 iOS 8 开始已被弃用。对于 iOS 8 及更高版本,您需要使用 isRegisteredForRemoteNotifications。
【讨论】:
在最新版本的 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;
}
【讨论】:
UserNotifications。很遗憾,我现在没有完整的答案。
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types & UIRemoteNotificationTypeAlert)
// blah blah blah
{
NSLog(@"Notification Enabled");
}
else
{
NSLog(@"Notification not enabled");
}
这里我们从 UIApplication 获取 UIRemoteNotificationType。它代表设置中此应用的推送通知状态,您可以轻松检查其类型
【讨论】:
要完成答案,它可以像这样工作......
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;
}
【讨论】:
回复:
这是正确的
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
【讨论】: