在 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
Ask for Permission for Local Notifications in iOS 8, but still have the App Support iOS 7
提问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:
以下答案做出了一些假设:
- 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.
- The app must support a Deployment Target of iOS 7 (or earlier) regardless of the Base SDK and Xcode version.
- 使用 Xcode 6 时,应用程序必须使用 iOS 8 的基础 SDK 正确构建,使用 Xcode 5 时,它必须使用 iOS 7 的基础 SDK 正确构建。
- 无论基础 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
** 编辑 ** 更好地固定代码