Determinar no iPhone se o usuário ativou as notificações push

207

Estou procurando uma maneira de determinar se, por meio de configurações, o usuário ativou ou desativou as notificações por push do meu aplicativo.

Kevin
fonte

Respostas:

300

Ligue enabledRemoteNotificationsTypese verifique a máscara.

Por exemplo:

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

iOS8 e superior:

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]
Zac Bowling
fonte
19
iOS 5: verifica o tipo de notificações por push que o aplicativo usa, independentemente do tempo em que está no centro de notificações do telefone ou não. Desativei as notificações por push do meu aplicativo e ainda obtive os tipos == 6. Ao desativar o estilo de som e alerta, obtive os tipos == UIRemoteNotificationTypeNone.
Quantumpotato 19/10/11
4
Como quantumpotato apontou, esta resposta não lida mais com todos os casos e não é uma solução completa.
DBD
5
O que está acontecendo com a Apple? Gostaria de ouvir a resposta deles sobre esse assunto. Como podemos desenvolver ótimos aplicativos sem conhecer essas informações básicas?
Oded Regev
15
@ZacBowling - a solução para versões iOS 8superiores e superiores está errada porque verifica apenas se o usuário se registrou para notificação remota. De acordo com a documentação: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
Então, na minha opinião, você também deve verificar[[UIApplication sharedApplication] currentUserNotificationSettings];
Apan
99

questão de quantumpotato:

Onde typesé dado por

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

pode-se usar

if (types & UIRemoteNotificationTypeAlert)

ao invés de

if (types == UIRemoteNotificationTypeNone) 

permitirá que você verifique apenas se as notificações estão ativadas (e não se preocupe com sons, selos, central de notificações etc.). A primeira linha do código ( types & UIRemoteNotificationTypeAlert) retornará YESse "Estilo de alerta" estiver definido como "Banners" ou "Alertas" e NOse "Estilo de alerta" estiver definido como "Nenhum", independentemente de outras configurações.

Tim Camber
fonte
isso não trata da questão de quantumpotato. Ele não se preocupa apenas com alertas, mas mostra que você não pode discernir através de enabledRemoteNotifications se o usuário ativou ou desativou a configuração da Central de Notificações.
Joey
8
Minha resposta pode não responder diretamente "como determinar se o aplicativo está na Central de Notificações", mas oferece uma maneira de verificar se o usuário receberá ou não notificações para o seu aplicativo , o que eu acho que é uma resposta no espírito da pergunta . Eu não acho que é possível verificar o primeiro.
precisa
2
O truque de "if (types & UIRemoteNotificationTypeAlert)" é muito bom.
Nembleton 22/07
Certifique-se de entender por que o truque funciona! Operadores bit a bit são muito úteis e máscaras de bit são comuns no cacau. Verifique stackoverflow.com/a/3427633/1148702
Tim Camber
2
No Swift2 / XCode7, a operação bit a bit falha com o erro O operador binário '&' não pode ser aplicado a dois operandos 'UIUserNotificationType' . Você pode usar contém em vez dissograntedSettings.types.contains(notificationType)
Philipp Otto
54

Na versão mais recente do iOS, este método está obsoleto. Para oferecer suporte ao iOS 7 e iOS 8, use:

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;
}
Kevin Sylvestre
fonte
2
E as notificações locais? O iOS 8 agora exige que o usuário permita. Mas então como verificar mais tarde se estes foram permitidos ou não?
Frédéric Adda
@FredA. Verifique UserNotifications. Infelizmente não tenho uma resposta completa agora.
Mazyod 07/01
3
no Swift, não consigo fazer enabled = types e UIRemoteNotificationTypeAlert. Erro: types não é bool
grandagile 14/05
53

Código atualizado para 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()
}

Código para swift3.0, iOS10

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

No iOS9, o swift 2.0 UIRemoteNotificationType está obsoleto, use o seguinte código

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.

}

basta verificar se as notificações push estão ativadas

    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
    }
ViJay Avhad
fonte
33

Abaixo, você encontrará um exemplo completo que abrange iOS8 e iOS7 (e versões inferiores). Observe que, antes do iOS8, não é possível distinguir entre "notificações remotas desativadas" e "apenas a Visualização no bloqueio de tela ativada".

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");
tilo
fonte
6
userNotificationSettings.types & UIUserNotificationTypeNone sempre será falso, pois UIUserNotificationTypeNone é uma máscara de bit vazia, é a ausência dos outros bits. para Nenhum, você só deseja verificar a igualdade.
dberwick
25

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
    }

Versão observável do RxSwift para 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()
        }
    }
}
Adam Smaka
fonte
1
Você salva meu dia. :)
Chetan Dobariya
1
Obrigado, eu estava procurando isso por uma hora.
Chanchal Warde
4
getNotificationSettings(...)é assíncrona para que o interior de retorno será ignorar
shelll
17

Ao tentar oferecer suporte ao iOS8 e inferior, não tive muita sorte usando o isRegisteredForRemoteNotificationsque Kevin sugeriu. Em vez disso, usei currentUserNotificationSettings, o que funcionou muito bem nos meus testes.

+ (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;
}
Shaheen Ghiassy
fonte
Isso não se aplica quando o aplicativo é instalado recentemente. O método sempre retornará NÃO e a permissão pop-up para notificações push nunca aparecerá. Assim, nas configurações do dispositivo, o aplicativo não aparecerá se você desejar alterar as configurações de notificação para esse aplicativo (permitir / não permitir). Alguém tem alguma idéia de como solucionar esse problema?
Tyegah123
As configurações de notificação são mantidas mesmo quando um aplicativo é excluído. Portanto, se seu aplicativo for totalmente novo, esse método funcionará. Se seu aplicativo foi excluído, mas depois reinstalado, as permissões ainda estão no sistema e a Apple não fornecerá a oportunidade de solicitar novamente permissões.
Shaheen Ghiassy
Eu vejo algum código redundante: isEnabled = NO;em seus ifcasos não é necessário, uma vez que foi inicializado comoNO
Jasper
15

Infelizmente, nenhuma dessas soluções realmente resolveu o problema, porque no final das contas as APIs estão seriamente ausentes quando se trata de fornecer as informações pertinentes. Você pode fazer algumas suposições, no entanto, o uso do currentUserNotificationSettingsiOS8 + não é suficiente em sua forma atual para realmente responder à pergunta. Embora muitas das soluções aqui pareçam sugerir que isso ouisRegisteredForRemoteNotifications é é uma resposta definitiva, na verdade não é.

Considere isto:

com os isRegisteredForRemoteNotificationsestados da documentação:

Retorna SIM se o aplicativo estiver registrado no momento para notificações remotas, levando em consideração todas as configurações do sistema ...

No entanto, se você incluir um NSLogdelegado simplesmente no seu aplicativo para observar o comportamento, é claro que isso não se comporta da maneira que esperamos que funcione. Na verdade, ele diz respeito diretamente às notificações remotas ativadas para este aplicativo / dispositivo. Uma vez ativado pela primeira vez, isso sempre retornará YES. Mesmo desativá-los nas configurações (notificações) ainda resultará nesse retorno YES, porque, a partir do iOS8, um aplicativo pode se registrar para receber notificações remotas e até mesmo enviar para um dispositivo sem que o usuário tenha as notificações ativadas, elas simplesmente não podem fazer alertas, Emblemas e sons sem o usuário ativá-lo. As notificações silenciosas são um bom exemplo de algo que você pode continuar fazendo, mesmo com as notificações desativadas.

Na medida em currentUserNotificationSettingsque indica uma das quatro coisas:

Os alertas estão ativados Os emblemas estão ativados O som está ativado Nenhum está ativado.

Isso não fornece absolutamente nenhuma indicação sobre os outros fatores ou sobre a própria opção de notificação.

De fato, um usuário pode desativar crachás, sons e alertas, mas ainda assim aparecer na tela de bloqueio ou no centro de notificações. Esse usuário ainda deve estar recebendo notificações por push e pode vê-las na tela de bloqueio e no centro de notificações. Eles estão com a notificação ativada. MAS currentUserNotificationSettingsretornará: UIUserNotificationTypeNonenesse caso. Isso não é realmente indicativo das configurações reais dos usuários.

Algumas suposições podem ser feitas:

  • se isRegisteredForRemoteNotificationsfor NO, você pode assumir que este dispositivo nunca foi registrado com êxito para notificações remotas.
  • após a primeira vez que se registra para notificações remotas, application:didRegisterUserNotificationSettings:é feito um retorno de chamada contendo configurações de notificação do usuário no momento, já que é a primeira vez que um usuário é registrado, as configurações devem indicar o que o usuário selecionou em termos de solicitação de permissão. Se as configurações equivalerem a algo diferente de: a UIUserNotificationTypeNonepermissão push foi concedida, caso contrário, ela foi recusada. A razão para isso é que, a partir do momento em que você inicia o processo de registro remoto, o usuário só pode aceitar ou recusar, com as configurações iniciais de uma aceitação sendo as que você define durante o processo de registro.
iYorke
fonte
8

Para completar a resposta, poderia funcionar algo como isto ...

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

editar: isso não está certo. como essas são coisas pouco inteligentes, ele não funcionará com um switch, então acabei usando isso:

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
UIRemoteNotificationType typesset = (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge);
if((types & typesset) == typesset)
{
    CeldaSwitch.chkSwitch.on = true;
}
else
{
    CeldaSwitch.chkSwitch.on = false;
}
pojomx
fonte
I considerado (para a minha situação) notificações sonoras como não habilitada (Desde que requerem texto para considerá-los habilitado para o meu funcionalidade app)
pojomx
5

Para iOS7 e versões anteriores, você deve realmente usar enabledRemoteNotificationTypese verificar se é igual (ou não, dependendo do que você deseja) UIRemoteNotificationTypeNone.

No entanto, para o iOS8, nem sempre é suficiente verificar apenas com o isRegisteredForRemoteNotificationsestado acima. Você também deve verificar se application.currentUserNotificationSettings.typesé igual (ou não é igual, dependendo do que você quiser) UIUserNotificationTypeNone!

isRegisteredForRemoteNotificationspode retornar verdadeiro mesmo que currentUserNotificationSettings.typesretorne UIUserNotificationTypeNone.

Peter Verhage
fonte
5

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

Aqui temos o UIRemoteNotificationType de UIApplication. Ele representa o estado da notificação por push deste aplicativo na configuração, do que você pode verificar seu tipo facilmente

Hossam Ghareeb
fonte
3
por favor, explique o que esse código faz, escrever código não responde simplesmente à pergunta.
extravagantemente
4

Eu tento dar suporte ao iOS 10 e superior usando a solução fornecida por @Shaheen Ghiassy, ​​mas encontro um problema de privação enabledRemoteNotificationTypes. Portanto, a solução que eu encontrei usando em isRegisteredForRemoteNotificationsvez de enabledRemoteNotificationTypesque foi preterida no iOS 8. Abaixo está minha solução atualizada que funcionou perfeitamente para mim:

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

E podemos chamar essa função facilmente e estar acessando seu Boolvalor e podemos convertê-lo no valor da string por este:

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

Espero que ajude os outros também :) Feliz codificação.

Irfan
fonte
3

Embora a resposta de Zac estivesse perfeitamente correta até o iOS 7, ela mudou desde que o iOS 8 chegou. Como enabledRemoteNotificationTypes foi descontinuado do iOS 8 em diante. Para o iOS 8 e posterior, você precisa usar isRegisteredForRemoteNotifications .

  • para iOS 7 e versões anteriores -> Usar enabledRemoteNotificationTypes
  • para iOS 8 e posterior -> Use isRegisteredForRemoteNotifications.
Rashmi Ranjan mallick
fonte
2

Esta solução Swifty funcionou bem para mim ( iOS8 + ),

Método :

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

Uso :

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

Ref.

Mohammad Zaid Pathan
fonte
0

ré:

isto está certo

if (types & UIRemoteNotificationTypeAlert)

mas seguir também está correto! (como UIRemoteNotificationTypeNone é 0)

if (types == UIRemoteNotificationTypeNone) 

veja o seguinte

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
espalhado
fonte
0

Veja como fazer isso no Xamarin.ios.

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

Se você suporta o iOS 10 ou superior, use apenas o método UNUserNotificationCenter.

Sune Kjærgård
fonte
0

No Xamarin, todas as soluções acima não funcionam para mim. Isto é o que eu uso em vez disso:

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

Ele também recebe uma atualização ao vivo depois que você altera o status da notificação em Configurações.

mr5
fonte
-1

Código fácil de copiar e colar, completo, criado a partir da solução da @ ZacBowling ( https://stackoverflow.com/a/1535427/2298002 )

isso também trará o usuário às configurações do seu aplicativo e permitirá que ele ative imediatamente

Também adicionei uma solução para verificar se os serviços de localização estão ativados (e também traz configurações)

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

estufa
fonte