Определите на iPhone, если пользователь включил push-уведомления


Ответы:


300

Позвони enabledRemoteNotificationsTypesи проверь маску.

Например:

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

iOS8 и выше:

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]

19
iOS 5: проверяет, какие виды push-уведомлений использует приложение, независимо от того, находится приложение в центре уведомлений вашего телефона или нет. Я отключил push-уведомления для своего приложения и все еще получил типы == 6. После отключения звука и стиля оповещения я получил типы == UIRemoteNotificationTypeNone.
Quantumpotato

4
Как отметил Quantumpotato, этот ответ больше не обрабатывает все случаи и не является полным решением.
DBD

5
Что происходит с Apple? Хотелось бы услышать их ответ по этому вопросу. Как мы можем разрабатывать отличные приложения, не зная такой базовой информации?
Одед Регев

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.
Апан

5
Так что, по моему мнению, вы также должны проверить[[UIApplication sharedApplication] currentUserNotificationSettings];
Апан

99

проблема кванумпумато:

Где typesдано

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

можно использовать

if (types & UIRemoteNotificationTypeAlert)

вместо того

if (types == UIRemoteNotificationTypeNone) 

позволит вам проверять только, включены ли уведомления (и не беспокоиться о звуках, значках, центре уведомлений и т. д.). Первая строка кода ( types & UIRemoteNotificationTypeAlert) вернется, YESесли для «Alert Style» установлено значение «Banners» или «Alerts», а для NO«Alert Style» установлено значение «None», независимо от других настроек.


это не решает проблему QuantumPato. Он не беспокоится только о предупреждениях, но указывает, что вы не можете определить с помощью enabledRemoteNotifications, включил ли пользователь настройку Центра уведомлений или нет.
Джои

8
Мой ответ может не отвечать непосредственно «как определить, находится ли приложение в Центре уведомлений», но он предлагает способ проверить, будет ли пользователь получать уведомления для вашего приложения , что, я думаю, является ответом в духе вопроса , Я не думаю, что можно проверить первое.
Тим Кэмбер

2
Уловка «if (types & UIRemoteNotificationTypeAlert)» очень хороша.
Нэмблтон

Убедитесь, что вы понимаете, почему трюк работает! Битовые операторы очень полезны, а битовые маски распространены в Какао. Проверьте stackoverflow.com/a/3427633/1148702
Тим Кэмбер

2
В Swift2 / XCode7 побитовая операция завершается с ошибкой. Двоичный оператор «&» не может быть применен к двум операндам «UIUserNotificationType» . Вместо этого вы можете использовать содержитgrantedSettings.types.contains(notificationType)
Филипп Отто

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. У меня нет полного ответа сейчас, к сожалению.
Мазёд


3
в Swift я не могу сделать enabled = types & UIRemoteNotificationTypeAlert. Ошибка: типы не bool
grandagile

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.

}

просто проверьте, включены ли Push-уведомления

    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 всегда будет ложным, так как UIUserNotificationTypeNone - пустая битовая маска, это отсутствие других битов. Ни для кого вы просто не хотите проверить равенство.
Дерберик

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
    }

Наблюдаемая версия 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()
        }
    }
}

1
ты спас мой день. :)
Четан Добария

1
Спасибо, я искал это в течение часа.
Chanchal Warde

4
getNotificationSettings(...)является асинхронным, поэтому возвращение внутрь будет игнорироваться
shelll

17

Пытаясь поддерживать iOS8 и ниже, мне не очень повезло, 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;
}

Это не относится к новым приложениям. Метод всегда возвращает NO, а всплывающее разрешение для push-уведомлений никогда не появится. Таким образом, в настройках устройства приложение не будет отображаться, если вы хотите изменить настройки уведомлений для этого приложения (разрешить / запретить). У кого-нибудь есть идеи, как обойти эту проблему?
tyegah123

Настройки уведомлений сохраняются даже при удалении приложения. Так что, если ваше приложение полностью новое, тогда этот метод будет работать. Если ваше приложение было удалено, но затем переустановлено, то разрешения остаются в системе, и Apple не предоставит вам возможность повторно запросить разрешения.
Шахин Гиасси

Я вижу некоторый избыточный код: isEnabled = NO;в ваших ifслучаях он не нужен, так как он был инициализирован какNO
Jasper

15

К сожалению, ни одно из этих решений не решило проблему, потому что в конце концов API не хватает, когда дело доходит до предоставления соответствующей информации. Вы можете сделать несколько предположений, однако использование currentUserNotificationSettings(iOS8 +) просто не достаточно в его текущей форме, чтобы действительно ответить на вопрос. Хотя многие решения здесь, кажется, предполагают, что либо это, либо isRegisteredForRemoteNotificationsскорее окончательный ответ, на самом деле это не так.

Учти это:

с isRegisteredForRemoteNotificationsдокументацией гласит:

Возвращает YES, если приложение в настоящее время зарегистрировано для удаленных уведомлений, принимая во внимание любые системные настройки ...

Однако, если вы просто NSLogдобавляете делегата в свое приложение для наблюдения за поведением, становится ясно, что это не так, как мы ожидаем, это будет работать. Это на самом деле относится непосредственно к удаленным уведомлениям, активированным для этого приложения / устройства. После первого включения это всегда будет возвращаться YES. Даже отключение их в настройках (уведомлениях) все равно приведет к этому возвращению, YESпотому что, начиная с iOS8, приложение может регистрироваться для удаленных уведомлений и даже отправлять на устройство, если у пользователя не включены уведомления, они просто могут не делать оповещения, Значки и звук без включения пользователя. Тихие уведомления являются хорошим примером того, что вы можете продолжать делать даже с отключенными уведомлениями.

Насколько currentUserNotificationSettingsэто указывает на одну из четырех вещей:

Предупреждения включены Значки включены Звук включен Ни один не включен.

Это не дает вам абсолютно никаких указаний относительно других факторов или самого переключателя уведомлений.

Пользователь может на самом деле отключить значки, звук и оповещения, но все равно будет отображаться на экране блокировки или в центре уведомлений. Этот пользователь все еще должен получать push-уведомления и иметь возможность видеть их как на экране блокировки, так и в центре уведомлений. У них включено уведомление. НО 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;
}

Я считал (для моей ситуации) звуковые уведомления
отключенными

5

Для iOS7 и прежде вы должны действительно использовать enabledRemoteNotificationTypesи проверить, равно ли оно (или не равно в зависимости от того, что вы хотите) UIRemoteNotificationTypeNone.

Однако для iOS8 не всегда достаточно проверять только isRegisteredForRemoteNotificationsстолько состояний, сколько указано выше. Вы также должны проверить, application.currentUserNotificationSettings.typesравно ли (или не равно в зависимости от того, что вы хотите) UIUserNotificationTypeNone!

isRegisteredForRemoteNotificationsможет вернуть true, даже если currentUserNotificationSettings.typesвозвращается 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");
}

Здесь мы получаем UIRemoteNotificationType из UIApplication. Он представляет состояние push-уведомлений этого приложения в настройках, чем вы можете легко проверить его тип


3
пожалуйста, объясните, что делает этот код, написание кода не просто отвечает на вопрос.
Бэтти

4

Я пытаюсь поддерживать iOS 10 и выше, используя решение, предоставленное @Shaheen Ghiassy, ​​но нахожу проблему депривации 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. Потому что enabledRemoteNotificationTypes устарел с iOS 8 и выше. Для 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

Re:

это верно

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!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.