Определите на 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тогда разрешение на передачу было предоставлено, в противном случае оно было отклонено. Причина этого заключается в том, что с момента начала процесса удаленной регистрации пользователь имеет возможность только принять или отклонить, при этом начальные настройки принятия - это настройки, которые вы установили в процессе регистрации.
iYorke
источник
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может вернуть 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
wavespread
источник
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;
}

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

MR5
источник
-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!

теплица
источник