RegisterForRemoteNotificationTypes: no es compatible con iOS 8.0 y posteriores

Resuelto Wojtek Turowicz asked hace 10 años • 15 respuestas

Al intentar registrarse para recibir notificaciones automáticas en iOS 8.x:

application.registerForRemoteNotificationTypes(UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound)

Obtuve el siguiente error:

registerForRemoteNotificationTypes: is not supported in iOS 8.0 and later.

¿Alguna idea de cuál es la nueva forma de hacerlo? Funciona cuando ejecuto esta aplicación Swift en iOS 7.x.

EDITAR

En iOS 7.x, cuando incluyo el código condicional, obtengo (ya sea SystemVersion condicional o #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)

dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings
Wojtek Turowicz avatar Jun 27 '14 21:06 Wojtek Turowicz
Aceptado

Para iOS<10

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    //-- Set Notification
    if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) 
    {
           // iOS 8 Notifications
           [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];

           [application registerForRemoteNotifications];
    }
    else
    {
          // iOS < 8 Notifications
          [application registerForRemoteNotificationTypes:
                     (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
    }

     //--- your custom code
     return YES;
}

Para iOS10

https://stackoverflow.com/a/39383027/3560390

PrasathBabu avatar Jul 16 '2014 06:07 PrasathBabu

Como describió, deberá utilizar un método diferente según las diferentes versiones de iOS. Si su equipo usa Xcode 5 (que no conoce ningún selector de iOS 8) y Xcode 6, necesitará usar la compilación condicional de la siguiente manera:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
    // use registerUserNotificationSettings
} else {
    // use registerForRemoteNotificationTypes:
}
#else
// use registerForRemoteNotificationTypes:
#endif

Si solo estás usando Xcode 6, puedes quedarte con esto:

if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
    // use registerUserNotificationSettings
} else {
    // use registerForRemoteNotificationTypes:
}

La razón aquí es que la forma de obtener permisos de notificación ha cambiado en iOS 8. A UserNotificationes un mensaje que se muestra al usuario, ya sea de forma remota o local. Necesita obtener permiso para mostrar uno. Esto se describe en el vídeo de la WWDC 2014 "Novedades de las notificaciones de iOS".

matt--- avatar Jul 11 '2014 00:07 matt---

Aprovechando la respuesta de @Prasath. Así es como se hace en Swift :

if application.respondsToSelector("isRegisteredForRemoteNotifications")
{
    // iOS 8 Notifications
    application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: (.Badge | .Sound | .Alert), categories: nil));
    application.registerForRemoteNotifications()
}
else
{
    // iOS < 8 Notifications
    application.registerForRemoteNotificationTypes(.Badge | .Sound | .Alert)
}
Austen Chongpison avatar Oct 14 '2014 00:10 Austen Chongpison

iOS 8 ha cambiado el registro de notificaciones de una manera no compatible con versiones anteriores. Si bien necesita ser compatible con iOS 7 y 8 (y aunque no se aceptan aplicaciones creadas con el SDK 8), puede verificar los selectores que necesita y llamarlos condicionalmente correctamente para la versión en ejecución.

Aquí hay una categoría en UIApplication que ocultará esta lógica detrás de una interfaz limpia que funcionará tanto en Xcode 5 como en Xcode 6.

Encabezamiento:

//Call these from your application code for both iOS 7 and 8
//put this in the public header
@interface UIApplication (RemoteNotifications)

- (BOOL)pushNotificationsEnabled;
- (void)registerForPushNotifications;

@end

Implementación:

//these declarations are to quiet the compiler when using 7.x SDK
//put this interface in the implementation file of this category, so they are
//not visible to any other code.
@interface NSObject (IOS8)

- (BOOL)isRegisteredForRemoteNotifications;
- (void)registerForRemoteNotifications;

+ (id)settingsForTypes:(NSUInteger)types categories:(NSSet*)categories;
- (void)registerUserNotificationSettings:(id)settings;

@end

@implementation UIApplication (RemoteNotifications)

- (BOOL)pushNotificationsEnabled
{
    if ([self respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
    {
        return [self isRegisteredForRemoteNotifications];
    }
    else
    {
        return ([self enabledRemoteNotificationTypes] & UIRemoteNotificationTypeAlert);
    }
}

- (void)registerForPushNotifications
{
    if ([self respondsToSelector:@selector(registerForRemoteNotifications)])
    {
        [self registerForRemoteNotifications];

        Class uiUserNotificationSettings = NSClassFromString(@"UIUserNotificationSettings");

        //If you want to add other capabilities than just banner alerts, you'll need to grab their declarations from the iOS 8 SDK and define them in the same way.
        NSUInteger UIUserNotificationTypeAlert   = 1 << 2;

        id settings = [uiUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:[NSSet set]];            
        [self registerUserNotificationSettings:settings];

    }
    else
    {
        [self registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert];
    }
}

@end
Jeff Holliday avatar Jul 23 '2014 20:07 Jeff Holliday