registerForRemoteNotificationTypes: n'est pas pris en charge dans iOS 8.0 et versions ultérieures

Lorsque vous essayez de vous inscrire aux notifications push sous iOS 8.x:

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

Je reçois l'erreur suivante:

registerForRemoteNotificationTypes: is not supported in iOS 8.0 and later.

Des idées Quelle est la nouvelle façon de le faire? Cela fonctionne quand je lance cette application Swift sur iOS 7.X.

Modifier

Sur iOS 7.x lorsque j'inclus le code conditionnel que je reçois (soit SystemVersion conditionnel ou #if _ _ IPHONE_OS _ VERSION_MAX_ALLOWED > = 80000)

dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings
209
demandé sur Iulian Onofrei 2014-06-27 18:15:52

15 réponses

Comme vous l'avez décrit, vous devrez utiliser une méthode différente basée sur différentes versions d'iOS. Si votre équipe utilise à la fois Xcode 5 (qui ne connaît aucun sélecteur iOS 8) et Xcode 6, vous devrez utiliser la compilation conditionnelle comme suit:

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

Si vous utilisez uniquement Xcode 6, Vous pouvez vous en tenir à ceci:

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

La raison en est que la façon dont vous obtenez les autorisations de notification a changé dans iOS 8. Un UserNotification est un message affiché à l'utilisateur, que ce soit de distant ou local. Vous devez obtenir la permission d'en montrer un. Ceci est décrit dans la vidéo WWDC 2014 "Quoi de neuf dans les Notifications iOS"

145
répondu matt--- 2018-03-26 08:25:51

Pour iOS

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

Pour iOS10

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

334
répondu Prasath 2017-05-23 12:17:23

Construire sur la réponse de @Prasath. Voici comment vous le faites dans 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)
}
23
répondu Austen Chongpison 2014-10-17 23:47:22

IOS 8 a modifié l'enregistrement des notifications d'une manière non rétrocompatible. Bien que vous ayez besoin de prendre en charge iOS 7 et 8 (et bien que les applications construites avec le SDK 8 ne soient pas acceptées), Vous pouvez vérifier les sélecteurs dont vous avez besoin et les appeler correctement pour la version en cours d'exécution.

Voici une catégorie sur UIApplication qui va cacher cette logique derrière une interface propre pour vous qui fonctionnera à la fois dans Xcode 5 et Xcode 6.

En-tête:

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

Mise en œuvre:

//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
14
répondu Jeff Holliday 2014-07-24 15:42:14

Je pense que c'est la meilleure façon de garder la rétrocompatibilité si nous allons avec cette approche, cela fonctionne pour mon cas et l'espoir fonctionnera pour vous. Assez facile à comprendre.

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
    [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
    [[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
         (UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
}
6
répondu Hussain KMR Behestee 2015-01-31 19:07:54

Pour le SWIFT-incliné:

if let registration: AnyObject = NSClassFromString("UIUserNotificationSettings") { // iOS 8+
    let notificationTypes: UIUserNotificationType = (.Alert | .Badge | .Sound)
    let notificationSettings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)

    application.registerUserNotificationSettings(notificationSettings)
} else { // iOS 7
    application.registerForRemoteNotificationTypes(.Alert | .Badge | .Sound)
}
5
répondu AstroCB 2015-01-14 14:58:08

Je ne pouvais pas comprendre à quoi la variable NSSet "catégories" devrait être définie, donc si quelqu'un pouvait me renseigner, je me ferai un plaisir d'éditer ce post. Ce qui suit, cependant, fait apparaître la boîte de dialogue de notification push.

[[UIApplication sharedApplication] registerForRemoteNotifications];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];

Edit: j'ai reçu une notification push à envoyer à mon téléphone avec ce code, donc je ne suis pas sûr que le paramètre categories soit nécessaire.

3
répondu 2014-07-03 23:58:41

Il s'avère donc que puisque AnyObject est le successeur spirituel de id, vous pouvez appeler n'importe quel message que vous voulez sur AnyObject. C'est l'équivalent d'envoyer un message à id. Ok, juste assez. Mais maintenant, nous ajoutons dans le concept que toutes les méthodes sont facultatives sur AnyObject , et nous avons quelque chose avec lequel nous pouvons travailler.

Compte tenu de ce qui précède, j'espérais pouvoir lancer UIApplication.sharedApplication () à AnyObject, puis créez une variable égale à la signature de la méthode, définissez cette variable à la méthode facultative, puis testez la variable. Cela ne semble pas fonctionner. Je suppose que lorsqu'il est compilé avec le SDK iOS 8.0, le compilateur sait où il pense que cette méthode devrait être , donc il optimise tout cela jusqu'à une recherche de mémoire. Tout fonctionne bien jusqu'à ce que j'essaie de tester la variable, à quel point j'obtiens un EXC_BAD_ACCESS.

Cependant, dans la même conférence WWDC où j'ai trouvé la gemme à propos de toutes les méthodes étant facultatives, ils utilisent le chaînage optionnel pour appeler une méthode facultative - et cela semble fonctionner. La partie boiteuse est que vous devez réellement essayer d'appeler la méthode afin de savoir si elle existe, ce qui dans le cas de l'inscription aux notifications est un problème car vous essayez de comprendre si cette méthode existe avant de créer un objet UIUserNotificationSettings. Il semble que l'appel de cette méthode avec nil soit correct, donc la solution qui semble fonctionner pour moi est:

var ao: AnyObject = UIApplication.sharedApplication()
if let x:Void = ao.registerUserNotificationSettings?(nil) {
    // It's iOS 8
    var types = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert
    var settings = UIUserNotificationSettings(forTypes: types, categories: nil)
    UIApplication.sharedApplication().registerUserNotificationSettings(settings)
} else {
    // It's older
    var types = UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound | UIRemoteNotificationType.Alert
    UIApplication.sharedApplication().registerForRemoteNotificationTypes(types)
}

Après beaucoup de recherches liées à cela, les informations clés proviennent de cette conférence de la WWDC https://developer.apple.com/videos/wwdc/2014/#407 juste au milieu de la section sur "méthodes optionnelles dans les protocoles"

Dans Xcode 6.1 bêta le code ci-dessus ne fonctionne plus, le code ci-dessous fonctionne:

   if UIApplication.sharedApplication().respondsToSelector("registerUserNotificationSettings:") {
        // It's iOS 8
        var types = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert
       var settings = UIUserNotificationSettings(forTypes: types, categories: nil)
       UIApplication.sharedApplication().registerUserNotificationSettings(settings)
    } else {
        // It's older
        var types = UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound | UIRemoteNotificationType.Alert
        UIApplication.sharedApplication().registerForRemoteNotificationTypes(types)
    }
3
répondu Tom S. 2014-09-25 06:04:42

Si vous souhaitez ajouter un support à IOS7 IOS8, vous pouvez appliquer ce code dans votre projet .

-(void) Subscribe {
    NSLog(@"Registering for push notifications...");

    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else {
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    }
}

-(void)application:(UIApplication *)application 
    didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {

    if (notificationSettings.types) {
        NSLog(@"user allowed notifications");
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else {
        NSLog(@"user did not allow notifications");
        UIAlertView *alert =[[UIAlertView alloc] 
            initWithTitle:@"Please turn on Notification"
            message:@"Go to Settings > Notifications > App.\n Switch on Sound, Badge & Alert"
            delegate:self
            cancelButtonTitle:@"Ok"
            otherButtonTitles: nil];
        [alert show];
        // show alert here
    }
}
3
répondu Nuno Sarmento 2015-03-31 09:48:32

Après Xcode 6.1 Beta le code ci-dessous fonctionne, légère modification sur le code de Tom qui a cessé de fonctionner avec la bêta 6.1 (travaillé avec la bêta précédente):

   if UIApplication.sharedApplication().respondsToSelector("registerUserNotificationSettings:") {
        // It's iOS 8
        var types = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert
       var settings = UIUserNotificationSettings(forTypes: types, categories: nil)
       UIApplication.sharedApplication().registerUserNotificationSettings(settings)
    } else {
        // It's older
        var types = UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound | UIRemoteNotificationType.Alert
        UIApplication.sharedApplication().registerForRemoteNotificationTypes(types)
    }
2
répondu Alain Marcel 2014-09-25 05:18:46

Vous pouvez utiliser ceci

if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) 
    {
        // for iOS 8
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];

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

    // RESET THE BADGE COUNT 
    application.applicationIconBadgeNumber = 0;
2
répondu Neenu 2015-04-01 09:02:37

Swift 2.0

// Checking if app is running iOS 8
    if application.respondsToSelector("isRegisteredForRemoteNotifications") {

        print("registerApplicationForPushNotifications - iOS 8")

        application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil));
        application.registerForRemoteNotifications()

    } else {
        // Register for Push Notifications before iOS 8
        print("registerApplicationForPushNotifications - <iOS 8")
        application.registerForRemoteNotificationTypes([UIRemoteNotificationType.Alert, UIRemoteNotificationType.Badge, UIRemoteNotificationType.Sound])

    }
2
répondu Anit Kumar 2016-03-03 07:23:06

Si tout ce dont vous avez besoin est le code ios 8, cela devrait le faire.

 - (BOOL)application:(UIApplication *)application       didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
       [application registerUserNotificationSettings: [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound  | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge)  categories:nil]];

       [application registerForRemoteNotifications];
}

 return YES;
}
1
répondu Tim 2015-05-16 23:44:11

C'est une façon plus propre que je fais et cela fonctionne très bien

if (floor(NSFoundationVersionNumber) < NSFoundationVersionNumber_iOS_8_0)
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge|
     UIRemoteNotificationTypeAlert| UIRemoteNotificationTypeSound];
     else {
         [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]]; 
         [application registerForRemoteNotifications];
     }
0
répondu Deepak Dhakal 2016-03-11 07:07:47

Pour iOS 8 et supérieur

UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert) categories:nil];
[application registerUserNotificationSettings:settings];
0
répondu Hardik Thakkar 2016-12-03 12:03:01