Determinar en iPhone si el usuario ha habilitado las notificaciones push

Respuestas:

300

Llamada enabledRemoteNotificationsTypes y revisa la máscara.

Por ejemplo:

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

iOS8 y superior:

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]
Zac Bowling
fuente
19
iOS 5: Esto verifica qué tipo de notificaciones push utiliza la aplicación, independientemente del clima que la aplicación esté en el centro de notificaciones de su teléfono o no. Inhabilité las notificaciones automáticas para mi aplicación y aún obtuve tipos == 6. Al deshabilitar el sonido y el estilo de alerta, obtuve tipos == UIRemoteNotificationTypeNone.
quantumpotato
44
Como Quantumpotato señaló, esta respuesta ya no maneja todos los casos y no es una solución completa.
DBD
55
¿Qué está pasando con Apple? Ojalá pudiera escuchar su respuesta sobre este tema. ¿Cómo podemos desarrollar excelentes aplicaciones sin conocer esa información básica?
Oded Regev
15
@ZacBowling: la solución para versiones iOS 8superiores es incorrecta porque solo se verifica si el usuario se registró para recibir notificaciones remotas. De acuerdo con la documentación: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
55
Entonces, en mi opinión, también deberías comprobarlo[[UIApplication sharedApplication] currentUserNotificationSettings];
Apan
99

problema de quantumpotato:

¿Dónde typesestá dado por

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

uno puede usar

if (types & UIRemoteNotificationTypeAlert)

en vez de

if (types == UIRemoteNotificationTypeNone) 

le permitirá verificar solo si las notificaciones están habilitadas (y no se preocupe por los sonidos, las insignias, el centro de notificaciones, etc.). La primera línea de código ( types & UIRemoteNotificationTypeAlert) volverá YESsi "Estilo de alerta" está configurado como "Banners" o "Alertas", y NOsi "Estilo de alerta" está configurado como "Ninguno", independientemente de otras configuraciones.

Tim Camber
fuente
esto no aborda el problema de quantumpotato. No solo le interesan las alertas, sino que señala que no se puede discernir a través de EnableRemoteNotifications si el usuario ha activado o desactivado la configuración del Centro de notificaciones.
Joey
8
Es posible que mi respuesta no responda directamente "cómo determinar si la aplicación está en el Centro de notificaciones", pero ofrece una forma de verificar si el usuario recibirá o no notificaciones para su aplicación , lo que creo que es una respuesta en el espíritu de la pregunta . No creo que sea posible verificar lo primero.
Tim Camber
2
El truco de "if (types & UIRemoteNotificationTypeAlert)" es muy bueno.
nembleton
¡Asegúrate de entender por qué funciona el truco! Los operadores bit a bit son muy útiles, y las máscaras de bit son comunes en Cocoa. Echa un vistazo a stackoverflow.com/a/3427633/1148702
Tim Camber
2
En Swift2 / XCode7, la operación bit a bit falla con el error El operador binario '&' no se puede aplicar a dos operandos 'UIUserNotificationType' . Puede usar contiene en su lugargrantedSettings.types.contains(notificationType)
Philipp Otto
54

En la última versión de iOS, este método ahora está en desuso. Para admitir el uso de iOS 7 y 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;
}
Kevin Sylvestre
fuente
2
¿Qué pasa con las notificaciones locales? iOS 8 ahora requiere que el usuario lo permita. Pero entonces, ¿cómo comprobar más tarde si estos estaban permitidos o no?
Frédéric Adda
@FredA. Compruebe UserNotifications. No tengo una respuesta completa ahora, desafortunadamente.
Mazyod
3
en Swift no puedo hacer enabled = types & UIRemoteNotificationTypeAlert. Error: los tipos no son bool
grandagile
53

Código actualizado 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
    }

Desde iOS9, Swift 2.0 UIRemoteNotificationType está en desuso, use el siguiente 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.

}

simplemente verifique si las notificaciones Push están habilitadas

    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
fuente
33

A continuación encontrará un ejemplo completo que cubre tanto iOS8 como iOS7 (y versiones inferiores). Tenga en cuenta que antes de iOS8 no puede distinguir entre "notificaciones remotas deshabilitadas" y "solo Ver en pantalla de bloqueo habilitada".

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
fuente
66
userNotificationSettings.types & UIUserNotificationTypeNone siempre será falso, ya que UIUserNotificationTypeNone es una máscara de bits vacía, es la ausencia de los otros bits. para Ninguno solo desea verificar la igualdad.
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
    }

Versión observable de 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
fuente
1
Me salvas el día. :)
Chetan Dobariya
1
Gracias, estuve buscando esto por una hora.
Chanchal Warde
44
getNotificationSettings(...)es asíncrono, por lo que se ignorará el retorno en el interior
shelll
17

Al tratar de admitir tanto iOS8 como versiones anteriores, no tuve mucha suerte usando isRegisteredForRemoteNotificationscomo sugirió Kevin. En cambio, lo usé currentUserNotificationSettings, lo que funcionó muy bien en mis pruebas.

+ (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
fuente
Esto no se aplica cuando la aplicación está recién instalada. El método siempre devolverá NO, y el permiso emergente para notificaciones push nunca aparecerá. Por lo tanto, en la configuración del dispositivo, la aplicación no aparecerá si desea cambiar la configuración de notificación para esa aplicación (permitir / no permitir). ¿Alguien tiene alguna idea de cómo solucionar este problema?
tyegah123
La configuración de las notificaciones persiste incluso cuando se elimina una aplicación. Entonces, si su aplicación es completamente nueva, entonces este método funcionará. Si su aplicación fue eliminada pero luego reinstalada, entonces los permisos aún están en el sistema y Apple no le dará la oportunidad de volver a solicitar permisos.
Shaheen Ghiassy
Veo un código redundante: isEnabled = NO;en sus ifcasos no es necesario, ya que se ha inicializado comoNO
Jasper
15

Desafortunadamente, ninguna de estas soluciones proporcionadas realmente resuelve el problema porque, al final del día, las API carecen seriamente cuando se trata de proporcionar la información pertinente. Puede hacer algunas conjeturas, sin embargo, usar currentUserNotificationSettings(iOS8 +) simplemente no es suficiente en su forma actual para responder realmente la pregunta. Aunque muchas de las soluciones aquí parecen sugerir que eso oisRegisteredForRemoteNotifications es una respuesta más definitiva, realmente no lo es.

Considera esto:

con isRegisteredForRemoteNotificationsestados de documentación:

Devuelve SÍ si la aplicación está actualmente registrada para notificaciones remotas, teniendo en cuenta cualquier configuración de todo el sistema ...

Sin embargo, si agrega un NSLogdelegado simplemente a su aplicación para observar el comportamiento, está claro que esto no se comporta de la manera que anticipamos que funcionará. En realidad, pertenece directamente a las notificaciones remotas que se han activado para esta aplicación / dispositivo. Una vez activado por primera vez, esto siempre volverá YES. Incluso si se desactivan en la configuración (notificaciones), el resultado será que YESesto se debe a que, a partir de iOS8, una aplicación puede registrarse para recibir notificaciones remotas e incluso enviarla a un dispositivo sin que el usuario tenga las notificaciones habilitadas, es posible que no hagan Alertas, Insignias y sonido sin que el usuario lo active. Las notificaciones silenciosas son un buen ejemplo de algo que puede seguir haciendo incluso con las notificaciones desactivadas.

En la medida en currentUserNotificationSettingsque indica una de cuatro cosas:

Las alertas están activadas Las insignias están activadas El sonido está activado Ninguna activada.

Esto no le da absolutamente ninguna indicación sobre los otros factores o el cambio de notificación en sí.

De hecho, un usuario puede desactivar las insignias, el sonido y las alertas, pero aún así se muestra en la pantalla de bloqueo o en el centro de notificaciones. Este usuario aún debería recibir notificaciones automáticas y poder verlas tanto en la pantalla de bloqueo como en el centro de notificaciones. Tienen el interruptor de notificación activado. PEROcurrentUserNotificationSettings volverá: UIUserNotificationTypeNoneen ese caso. Esto no es realmente indicativo de la configuración real de los usuarios.

Algunas conjeturas que uno puede hacer:

  • Si isRegisteredForRemoteNotifications es NOasí, puede suponer que este dispositivo nunca se ha registrado correctamente para notificaciones remotas.
  • después de la primera vez que se registra para notificaciones remotas, se realiza una devolución de llamada que application:didRegisterUserNotificationSettings:contiene la configuración de notificación del usuario en este momento, ya que esta es la primera vez que se registra a un usuario, la configuración debe indicar lo que el usuario seleccionó en términos de la solicitud de permiso. Si la configuración equivale a otra cosa que no sea: UIUserNotificationTypeNonese otorgó el permiso de inserción, de lo contrario, se rechazó. La razón de esto es que desde el momento en que comienza el proceso de registro remoto, el usuario solo tiene la capacidad de aceptar o rechazar, y la configuración inicial de una aceptación es la configuración que configura durante el proceso de registro.
iYorke
fuente
8

Para completar la respuesta, podría funcionar algo como esto ...

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: Esto no está bien. Dado que estas son cosas de bits, no funcionará con un interruptor, así que terminé de usar esto:

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
UIRemoteNotificationType typesset = (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge);
if((types & typesset) == typesset)
{
    CeldaSwitch.chkSwitch.on = true;
}
else
{
    CeldaSwitch.chkSwitch.on = false;
}
pojomx
fuente
Consideré (para mi situación) las notificaciones de sonido como no habilitadas (ya que requiero texto para considerarlas habilitadas para la funcionalidad de mi aplicación)
pojomx
5

Para iOS7 y anteriores, debe usar enabledRemoteNotificationTypesy verificar si es igual (o no igual, según lo que desee) UIRemoteNotificationTypeNone.

Sin embargo, para iOS8 no siempre es suficiente verificar solo con isRegisteredForRemoteNotificationstantos estados anteriores. ¡También debe verificar si application.currentUserNotificationSettings.typeses igual (o no es igual dependiendo de lo que desee) UIUserNotificationTypeNone!

isRegisteredForRemoteNotificationspodría regresar verdadero aunque currentUserNotificationSettings.typesregrese UIUserNotificationTypeNone.

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

Aquí obtenemos el UIRemoteNotificationType de UIApplication. Representa el estado de las notificaciones automáticas de esta aplicación en la configuración, de lo que puede verificar su tipo fácilmente

Hossam Ghareeb
fuente
3
explique qué hace este código; escribir código no responde simplemente a la pregunta.
Batty
4

Intento admitir iOS 10 y superior utilizando la solución proporcionada por @Shaheen Ghiassy pero encuentro un problema de privación enabledRemoteNotificationTypes. Entonces, la solución que encuentro usando en isRegisteredForRemoteNotificationslugar de la enabledRemoteNotificationTypesque se desactivó en iOS 8. A continuación se muestra mi solución actualizada que funcionó perfectamente para mí:

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

Y podemos llamar a esta función fácilmente y acceder a su Boolvalor y podemos convertirlo en el valor de cadena de esta manera:

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

Espero que ayude a otros también :) Feliz codificación.

Irfan
fuente
3

Aunque la respuesta de Zac fue perfectamente correcta hasta iOS 7, ha cambiado desde que llegó iOS 8. Debido a que enabledRemoteNotificationTypes ha quedado en desuso desde iOS 8 en adelante. Para iOS 8 y versiones posteriores, debe usar isRegisteredForRemoteNotifications .

  • para iOS 7 y anteriores -> Usar enabledRemoteNotificationTypes
  • para iOS 8 y posterior -> Use isRegisteredForRemoteNotifications.
Rashmi Ranjan mallick
fuente
2

Esta solución Swifty funcionó bien para mí ( 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")
            }
        }

Árbitro

Mohammad Zaid Pathan
fuente
0

re:

esto es correcto

if (types & UIRemoteNotificationTypeAlert)

¡pero seguir también es correcto! (como UIRemoteNotificationTypeNone es 0)

if (types == UIRemoteNotificationTypeNone) 

ver lo siguiente

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
extensión de onda
fuente
0

Aquí se explica cómo hacerlo en Xamarin.ios.

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

Si es compatible con iOS 10+, solo use el método UNUserNotificationCenter.

Sune Kjærgård
fuente
0

En Xamarin, toda la solución anterior no funciona para mí. Esto es lo que uso en su lugar:

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

Recibirá una actualización en vivo también después de que haya cambiado el estado de la notificación en Configuración.

mr5
fuente
-1

Código completo de copiar y pegar fácil creado a partir de la solución de @ ZacBowling ( https://stackoverflow.com/a/1535427/2298002 )

esto también llevará al usuario a la configuración de su aplicación y le permitirá habilitarlo de inmediato

También agregué una solución para verificar si los servicios de ubicación están habilitados (y también la configuración)

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

invernadero
fuente