尝试在iOS 8.x下注册推送通知时
application.registerForRemoteNotificationTypes(UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound)
我收到以下错误:
registerForRemoteNotificationTypes: is not supported in iOS 8.0 and later.
任何想法是什么新的做法?当我在iOS 7.x上运行这个Swift应用程序时,它确实有效。
修改
在iOS 7.x上,当我包含我得到的条件代码时(SystemVersion条件或#if __IPHONE_OS_VERSION_MAX_ALLOWED> = 80000)
dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings
答案 0 :(得分:334)
适用于iOS< 10
- (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;
}
对于iOS10
答案 1 :(得分:145)
如您所述,您需要使用基于不同iOS版本的不同方法。如果您的团队正在使用Xcode 5(它不知道任何iOS 8选择器)和Xcode 6,那么您将需要使用条件编译,如下所示:
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
// use registerUserNotificationSettings
} else {
// use registerForRemoteNotificationTypes:
}
#else
// use registerForRemoteNotificationTypes:
#endif
如果你只使用Xcode 6,你可以坚持下去:
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
// use registerUserNotificationSettings
} else {
// use registerForRemoteNotificationTypes:
}
原因在于,您在iOS 8中获得通知权限的方式已更改。UserNotification
是向用户显示的消息,无论是来自远程还是来自本地。您需要获得显示权限。这在WWDC 2014视频"What's New in iOS Notifications"
答案 2 :(得分:23)
以@Prasath的回答为基础。这是你在 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)
}
答案 3 :(得分:14)
iOS 8以非向后兼容的方式更改了通知注册。虽然您需要支持iOS 7和8(虽然不接受使用8 SDK构建的应用程序),但您可以检查所需的选择器,并有条件地为正在运行的版本正确调用它们。
这里是UIApplication的一个类别,它会将这个逻辑隐藏在一个干净的界面背后,适用于Xcode 5和Xcode 6。
部首:
//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
实现:
//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
答案 4 :(得分:6)
我认为这是保持向后兼容性的更好方法,如果我们采用这种方法,它适用于我的情况,希望对你有用。也很容易理解。
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 :(得分:5)
对于斯威夫特倾向:
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)
}
答案 6 :(得分:3)
我无法弄清楚&#34;类别&#34; NSSet变量应该设置为,所以如果有人可以填写我,我会很乐意编辑这篇文章。但是,以下操作会打开推送通知对话框。
[[UIApplication sharedApplication] registerForRemoteNotifications];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
编辑:我收到推送通知,要使用此代码发送到我的手机,因此我不确定类别参数是否必要。
答案 7 :(得分:3)
事实证明,因为AnyObject是id的精神继承者,你可以在AnyObject上调用你想要的任何消息。这相当于向id发送消息。好,可以。但是现在我们添加了所有方法在AnyObject 上都是可选的概念,我们可以使用它们。
鉴于上述情况,我希望我可以将UIApplication.sharedApplication()转换为AnyObject,然后创建一个等于方法签名的变量,将该变量设置为可选方法,然后测试变量。这似乎不起作用。我的猜测是,当针对iOS 8.0 SDK编译时,编译器知道它认为应该的方法在哪里,所以它将这一切优化到内存查找。一切正常,直到我尝试测试变量,此时我得到一个EXC_BAD_ACCESS。
然而,在同一个WWDC讨论中,我发现所有方法都是可选的gem,他们使用Optional Chaining来调用一个可选方法 - 这似乎有效。蹩脚的部分是你必须实际尝试调用该方法以便知道它是否存在,在注册通知的情况下这是一个问题,因为你在创建一个方法之前试图弄清楚这个方法是否存在UIUserNotificationSettings对象。似乎用nil调用该方法是可以的,所以似乎对我有用的解决方案是:
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)
}
经过大量搜索后,关键信息来自WWDC讲座https://developer.apple.com/videos/wwdc/2014/#407,正好位于“协议中的可选方法”部分中间
在Xcode 6.1 beta中,上述代码不再起作用,下面的代码可以工作:
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)
}
答案 8 :(得分:3)
如果您想添加对IOS7 IOS8的支持,您可以将此代码应用到您的项目中。
-(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
}
}
答案 9 :(得分:2)
在Xcode 6.1 Beta之后,下面的代码可以使用,对Tom S代码停止使用6.1 beta进行了轻微编辑(使用之前的测试版):
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)
}
答案 10 :(得分:2)
您可以使用此
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;
答案 11 :(得分:2)
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])
}
答案 12 :(得分:1)
如果您只需要ios 8代码,那么应该这样做。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
[application registerUserNotificationSettings: [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
return YES;
}
答案 13 :(得分:0)
这是我正在做的更清洁的方式,而且效果很好
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];
}