web-dev-qa-db-fra.com

Demandez l'autorisation pour les notifications locales dans iOS 8, mais avez toujours le support de l'application iOS 7

J'ai une application qui utilise des notifications locales. Dans iOS 7, tout fonctionne bien, mais dans iOS 8, l'application doit demander la permission de l'utilisateur pour afficher les notifications. Pour demander la permission dans iOS 8, j'utilise:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{
  [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}

Cela fonctionne très bien dans Xcode 6 et dans iOS 8. Lorsque j'ouvre le même projet dans Xcode 5, l'erreur est un problème sémantique. "Utilisation de l'identifiant non déclaré 'UIUserNotificationSettings'."

Comment puis-je faire fonctionner l'application avec iOS 7 et 8 et que les notifications fonctionnent correctement sur les deux versions.

32
dannysandler

La réponse suivante fait quelques hypothèses:

  1. L'application doit se construire correctement avec un SDK de base d'iOS 8 lors de l'utilisation de Xcode 6 et elle doit se construire correctement avec un SDK de base d'iOS 7 lors de l'utilisation de Xcode 5.
  2. L'application doit prendre en charge une cible de déploiement d'iOS 7 (ou version antérieure), quelle que soit la version du SDK de base et de la version Xcode.

Code:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // None of the code should even be compiled unless the Base SDK is iOS 8.0 or later
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    // The following line must only run under iOS 8. This runtime check prevents
    // it from running if it doesn't exist (such as running under iOS 7 or earlier).
    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
    }
#endif
}

Tout cela est couvert dans le Apple Guide de compatibilité du SDK .

63
rmaddy

J'ai implémenté simplement -

if([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {

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

} else {
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge];
}
11
Prakash Raj

Jusqu'à présent, cet extrait de code fonctionne pour moi, et il est simple à réutiliser:

//-- Set Notification
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)];
}
3
TooManyEduardos

Si vous souhaitez toujours compiler avec des SDK plus anciens ou si vous avez une raison particulière de le faire, vous pouvez essayer d'appeler l'ensemble de manière dynamique:

#ifdef __IPHONE_8_0
#define USING_IOS8_SDK
#else // iOS <8 SDK compatibility definitions
#define UIUserNotificationTypeNone    (0)
#define UIUserNotificationTypeBadge   (1 << 0)
#define UIUserNotificationTypeSound   (1 << 1)
#define UIUserNotificationTypeAlert   (1 << 2)
#endif


...

if ([_sharedApplication respondsToSelector:NSSelectorFromString(@"registerUserNotificationSettings:")])
{
    NSUInteger settingsParam = (UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound);
    id categoriesParam = nil;

#ifdef USING_IOS8_SDK

    // Perform direct call when using iOS 8 SDK
    [_sharedApplication registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:settingsParam categories:categoriesParam]];

#else
#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

    // Do the dynamic stuff

    // Get UIUserNotificationSettings class reference
    Class settings = NSClassFromString(@"UIUserNotificationSettings");
    if (settings) {

        // Prepare class selector
        SEL sel = NSSelectorFromString(@"settingsForTypes:categories:");

        // Obtain a method signature of selector on UIUserNotificationSettings class
        NSMethodSignature *signature = [settings methodSignatureForSelector:sel];

        // Create an invocation on a signature -- must be used because of primitive (enum) arguments on selector
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        invocation.selector = sel;
        invocation.target = settings;

        // Set arguments
        [invocation setArgument:&settingsParam atIndex:2];
        [invocation setArgument:&categoriesParam atIndex:3];

        // Obtain an instance by firing an invocation
        NSObject *settingsInstance;
        [invocation invoke];
        [invocation getReturnValue:&settingsInstance];

        // Retain an instance so it can live after quitting method and prevent crash :-)
        CFRetain((__bridge CFTypeRef)(settingsInstance));

        // Finally call the desired method with proper settings
        if (settingsInstance)
            [_sharedApplication performSelector:NSSelectorFromString(@"registerUserNotificationSettings:") withObject:settingsInstance];
    }

#pragma clang diagnostic pop
#endif
}

Cela devrait parfaitement compiler sur le SDK iOS 7 et fonctionner (efficacement) sur les appareils iOS 8, ignoré sur les anciens.

La migration de votre projet vers le SDK iOS 8 est une autre solution, pensé, mais il y a encore des options.

3
Michi
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
    [application registerUserNotificationSettings:settings];
}
0
KkMIW