Solicite permiso de usuario para recibir notificaciones UILocal en iOS 8

115

He configurado notificaciones locales en el delegado de la aplicación usando esto:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    UILocalNotification *notification = [[UILocalNotification alloc]init];
    [notification setAlertBody:@"Watch the Latest Episode of CCA-TV"];
    [notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:5]];
    [notification setTimeZone:[NSTimeZone defaultTimeZone]];
    [application setScheduledLocalNotifications:[NSArray arrayWithObject:notification]];
}

Cuando ejecuto la aplicación y luego la salgo, recibo un error que dice:

2014-06-07 11: 14: 16.663 CCA-TV [735: 149070] Intentando programar una notificación local {fecha de incendio = sábado, 7 de junio de 2014 a las 11:14:21 hora de verano del Pacífico, zona horaria = América / Los_Angeles (PDT) offset -25200 (luz del día), intervalo de repetición = 0, recuento de repetición = UILocalNotificationInfiniteRepeatCount, próxima fecha de incendio = sábado, 7 de junio de 2014 a las 11:14:21 hora de verano del Pacífico, información del usuario = (nulo)} con una alerta pero no he recibido permiso del usuario para mostrar alertas

¿Cómo puedo obtener el permiso necesario para mostrar las alertas?

dannysandler
fuente
1
Creo que la aplicación ha rechazado el permiso una vez, puede intentar habilitarlo desde Configuración. Pero, por cierto, UILocalNotification no necesita permiso del usuario ..
iphonic
Prueba registerUserNotificationSettings. Si hubiera sido iOS 8, este hilo habría respondido a su pregunta. Pero, adelante, echa un vistazo - stackoverflow.com/questions/24006998/…
raurora

Respuestas:

237

Dado que iOS 8 debe pedir permiso al usuario para mostrar notificaciones de su aplicación, esto se aplica tanto para notificaciones remotas / push como locales. En Swift puedes hacerlo así,

Actualización para Swift 2.0

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    // Override point for customization after application launch.
    if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:")))
    {
        let notificationCategory:UIMutableUserNotificationCategory = UIMutableUserNotificationCategory()
        notificationCategory.identifier = "INVITE_CATEGORY"
        notificationCategory.setActions([replyAction], forContext: UIUserNotificationActionContext.Default)

        //registerting for the notification.
        application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes:[.Sound, .Alert, .Badge], categories: nil))
    }
    else
    {
       //do iOS 7 stuff, which is pretty much nothing for local notifications.
    }
    return true
}

Swift 3.2

if(UIApplication.instancesRespond(to: #selector(UIApplication.registerUserNotificationSettings(_:)))){
     let notificationCategory:UIMutableUserNotificationCategory = UIMutableUserNotificationCategory()
     notificationCategory.identifier = "INVITE_CATEGORY"
     notificationCategory.setActions([replyAction], forContext: UIUserNotificationActionContext.Default)

     //registerting for the notification.
        application.registerUserNotificationSettings(UIUserNotificationSettings(types:[.sound, .alert, .badge], categories: nil))
}
else{
        //do iOS 7 stuff, which is pretty much nothing for local notifications.
    }

La sintaxis de Objective C también es muy similar.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]){
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
    }
    // Override point for customization after application launch.
    return YES;
}

Para verificar los tipos de notificación registrados actualmente, puede usar el método de la clase UIApplication,

- (UIUserNotificationSettings *)currentUserNotificationSettings

Entonces, si el usuario ha dicho que no a su aplicación, esta función debería devolver una configuración sin ningún tipo en ella.

He escrito un tutorial sobre esto, puedes verlo aquí .

Satheeshwaran
fuente
1
Si el usuario niega el permiso, ¿cómo se determina esto más tarde mediante programación?
jjxtra
@satheeshwaran Cuando uso este código, funciona bien con el simulador con iOS8. Quería el objetivo de implementación de mi aplicación a partir de iOS7. Por lo tanto, cuando ejecuta este código en un dispositivo iOS7, me sale este error: dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings. ¿Hay alguna otra forma en Swift de solicitar permisos al usuario para trabajar en iOS7? por favor ayuda.
Raghavendra
@Raghav UIUserNotificationSettings solo está disponible desde iOS 8 y lo que enfrenta es el comportamiento correcto. No deberías usar esto en iOS 7.
Satheeshwaran
1
-1 para comprobar la versión de iOS UIDevice. stackoverflow.com/a/25735175/1226304 answer tiene un mejor enfoque para hacer esto.
Derpoliuk
3
@derpoliuk Actualizado como en la respuesta para el beneficio de todos, ¿ok ??
Satheeshwaran
38

Coloque este código en el controlador de vista donde primero programará las notificaciones (si las programa en el lanzamiento, entonces será application:didFinishLaunchingWithOptions:):

if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
    [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound categories:nil]];
}

En Swift:

if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:"))) {
    UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert | .Sound, categories: nil))
}

Las soluciones que se prueban con el número de versión del sistema son subóptimas y propensas a errores.

KPM
fuente
Me gustaría utilizar application.respondsToSelector(Selector("registerUserNotificationSettings"))yif ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
derpoliuk
7
Bueno, eso es solo porque lo está usando en el interior, lo application:didFinishLaunchingWithOptions:que proporciona un applicationobjeto útil :)
KPM
18

Pruebe esto para Objective-C:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:    (NSDictionary *)launchOptions
{
// are you running on iOS8?
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) 
  {
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
    [application registerUserNotificationSettings:settings];
  } 
else // iOS 7 or earlier
  {
    UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
    [application registerForRemoteNotificationTypes:myTypes];
  }
}

Para Swift:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
// Override point for customization after application launch.
 if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:")))
 {
    application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: UIUserNotificationType.Sound | UIUserNotificationType.Alert | UIUserNotificationType.Badge, categories: nil))
 }
 else
 {
    //
 }
return true
}
Nagarjun
fuente
5

Simplemente enfrenté el mismo problema. Parece que en iOS 8 necesitamos hacer un paso adicional, generalmente se hace en el interior:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { /*...*/ }

Puede usar este código si desea mantenerlo compatible con versiones anteriores:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)])
    {
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]];
    }
#endif

El sistema recordará la decisión y solo preguntará una vez.

ppalancica
fuente
Es mejor verificar la versión de iOS con este código si ([[UIDevice currentDevice] .systemVersion floatValue] <10)
Mehul Chuahan
1

** Notificación local con acción de tres botones para iOS8 +

// Botón: LO TOMÉ, RECUERDA MÁS TARDE, SALTÉLO **

        let completeAction = UIMutableUserNotificationAction()
        completeAction.identifier = "COMPLETE_TODO"
        completeAction.title = "I TOOK IT"
        completeAction.activationMode = .Background
        completeAction.destructive = true
        completeAction.authenticationRequired = false

        let remindAction = UIMutableUserNotificationAction()
        remindAction.identifier = "REMIND_TODO"
        remindAction.title = "REMIND LATER"
        remindAction.activationMode = .Background
        remindAction.destructive = false
        //  remindAction.authenticationRequired = false

        let skipAction = UIMutableUserNotificationAction()
        skipAction.identifier = "SKIP_TODO"
        skipAction.title = "SKIP IT"
        skipAction.activationMode = .Background
        skipAction.destructive = false
        skipAction.authenticationRequired = false


        let todoCategory = UIMutableUserNotificationCategory()
        todoCategory.identifier = "TODO_CATEGORY"
        todoCategory.setActions([completeAction, remindAction, skipAction], forContext: .Default)
        todoCategory.setActions([completeAction,remindAction,skipAction], forContext: .Minimal)


        if application.respondsToSelector("isRegisteredForRemoteNotifications")
        {

            let categories = NSSet(array: [todoCategory,todoVideoCategory])
            let types:UIUserNotificationType = ([.Alert, .Sound, .Badge])

            let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: categories as? Set<UIUserNotificationCategory>)

            application.registerUserNotificationSettings(settings)
            application.registerForRemoteNotifications()

        }

    }
PSS
fuente