Попросите разрешения для локальных уведомлений в iOS 8, но все еще есть поддержка приложений iOS 7

У меня есть приложение, которое использует локальные уведомления. В iOS 7 все работает нормально, но в iOS 8 приложение должно запрашивать у пользователя разрешение на отображение уведомлений. Чтобы запросить разрешение в iOS 8, я использую:

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

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

Он отлично работает в Xcode 6 и iOS 8. Когда я открываю тот же проект в Xcode 5, ошибка является семантической проблемой. "Использование необъявленного идентификатора" UIUserNotificationSettings "."

Как я могу заставить приложение работать с iOS 7 и 8 и корректно работать с уведомлениями в обеих версиях.

Ответ 1

Следующий ответ дает несколько предположений:

  • При использовании Xcode 6 приложение должно правильно создать базовый SDK iOS 8, и он должен правильно строить базовый SDK iOS 7 при использовании Xcode 5.
  • Приложение должно поддерживать целевой объект развертывания iOS 7 (или ранее) независимо от базовой версии SDK и Xcode.

код:

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

Все это описано в Руководстве по совместимости SDK Apple .

Ответ 2

Я реализовал просто -

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

Ответ 3

Если вы все еще хотите скомпилировать файлы с более старыми SDK или имеете специальную причину, вы можете попытаться вызвать весь материал динамически:

#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
}

Это должно отлично скомпилироваться в iOS 7 SDK и эффективно работать на устройствах iOS 8, игнорируется на старых.

Перенос проекта на iOS 8 SDK - это еще одно решение, но есть еще варианты.

Ответ 4

Пока этот фрагмент кода работает для меня, и его простое повторное использование:

//-- 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)];
}

Ответ 5

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

Ответ 6

Вы можете попробовать что-то вроде этого:

if (NSClassFromString(@"UIUserNotificationSettings") != nil) {
    // your iOS 8 code here
    #define isiOS8
}
else {
    #undef isiOS8
}

#ifdef isiOS8
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
#endif

Это немного запутаннее, но он отлично работает.

** EDIT ** Улучшенный исправленный код