在 iOS 8 中请求本地通知的许可,但仍有 App 支持 iOS 7

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24946650/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:32:53  来源:igfitidea点击:

Ask for Permission for Local Notifications in iOS 8, but still have the App Support iOS 7

iosobjective-cxcode

提问by dannysandler

I have an app which uses local notifications. In iOS 7 everything works fine, but in iOS 8 the app needs to ask for user permission to display notifications. To ask for permission in iOS 8 I'm using:

我有一个使用本地通知的应用程序。在 iOS 7 中一切正常,但在 iOS 8 中,应用程序需要请求用户许可才能显示通知。要在 iOS 8 中请求许可,我正在使用:

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

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

It works fine in Xcode 6 and in iOS 8. When I open the same project in Xcode 5, the error is a Semantic Issue. "Use of undeclared identifier 'UIUserNotificationSettings'."

它在 Xcode 6 和 iOS 8 中运行良好。当我在 Xcode 5 中打开同一个项目时,错误是语义问题。“使用未声明的标识符‘UIUserNotificationSettings’。”

How can I get the app to work with iOS 7 & 8, and have the notifications work properly on both versions.

如何让应用程序与 iOS 7 和 8 一起使用,并让通知在两个版本上都能正常工作。

回答by rmaddy

The following answer makes a few assumptions:

以下答案做出了一些假设:

  1. The app must build properly with a Base SDK of iOS 8 when using Xcode 6 and it must build properly with a Base SDK of iOS 7 when using Xcode 5.
  2. The app must support a Deployment Target of iOS 7 (or earlier) regardless of the Base SDK and Xcode version.
  1. 使用 Xcode 6 时,应用程序必须使用 iOS 8 的基础 SDK 正确构建,使用 Xcode 5 时,它必须使用 iOS 7 的基础 SDK 正确构建。
  2. 无论基础 SDK 和 Xcode 版本如何,应用程序都必须支持 iOS 7(或更早版本)的部署目标。

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
}

All of this is covered in the Apple SDK Compatibility Guide.

所有这些都包含在 Apple SDK 兼容性指南中

回答by Prakash Raj

I have implemented simply -

我已经简单地实施了 -

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

回答by Michi

In case you still want to compile against older SDKs or have a special reason to do so, you may try calling the whole stuff dynamically:

如果您仍然想针对较旧的 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
}

This should perfectly compile on iOS 7 SDK and work (effectively) on iOS 8 devices, ignored on older ones.

这应该在 iOS 7 SDK 上完美编译并在 iOS 8 设备上(有效)工作,在旧设备上忽略。

Migrating your project to iOS 8 SDK is another solution, thought, but there are still options.

将您的项目迁移到 iOS 8 SDK 是另一种解决方案,但仍有选择。

回答by TooManyEduardos

So far, this code snippet works for me, and its simple to reuse:

到目前为止,这段代码片段对我有用,而且很容易重用:

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

回答by KkMIW

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

回答by Simon Germain

You can try something like this:

你可以尝试这样的事情:

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

It's a bit more convoluted but it works fine.

它有点复杂,但效果很好。

** EDIT ** Fixed code better

** 编辑 ** 更好地固定代码