registerForRemoteNotificationTypes:在iOS 8.0及更高版本中不受支持

在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 conditional或#if __IPHONE_OS_VERSION_MAX_ALLOWED> = 80000)

 dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings 

正如你所描述的,你将需要使用基于不同版本的iOS的不同方法。 如果您的团队同时使用Xcode 5(不知道任何iOS 8select器)和Xcode 6(目前处于testing版),那么您将需要使用条件编译,如下所示:

 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) { // use registerUserNotificationSettings } else { // use registerForRemoteNotificationTypes: } #else // use registerForRemoteNotificationTypes: #endif 

如果你只使用Xcode 6(beta),你可以坚持这样做:

 if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) { // use registerUserNotificationSettings } else { // use registerForRemoteNotificationTypes: } 

原因是在iOS 8中,获取通知权限的方式发生了变化UserNotification是向用户显示的消息,无论是从远程还是从本地。 您需要获得许可才能显示一个。 这在WWDC 2014video“iOS新增function”

对于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

https://stackoverflow.com/a/39383027/3560390

build立在@ 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) } 

iOS 8已经以非向后兼容的方式改变了通知注册。 虽然您需要支持iOS 7和8(以及使用8 SDK构build的应用程序不被接受),但您可以检查所需的select器,并有条件地为正在运行的版本调用它们。

这里有一个关于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 

对于Swift倾斜的:

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

我认为这是保持向后兼容性的更好方法,如果我们采用这种方法,它正在为我的案件工作,希望将为你工作。 也很容易理解。

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

我无法弄清楚“NSSetvariables”应该设置为“什么类别”,所以如果有人能够填补我的话,我会很乐意编辑这篇文章。 但是,下面会显示推送通知对话框。

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

编辑:我有一个推送通知发送到我的手机与此代码,所以我不知道类别参数是必要的。

所以事实certificate,因为AnyObject是id的精神inheritance者,所以你可以在AnyObject上调用你想要的任何消息。 这相当于向ID发送消息。 好,可以。 但是现在我们添加一个概念,即AnyObject上的所有方法都是可选的 ,我们可以使用一些东西。

鉴于上述情况,我希望我可以将UIApplication.sharedApplication()投射到AnyObject,然后创build一个等于方法签名的variables,将该variables设置为可选方法,然后testing该variables。 这似乎没有工作。 我的猜测是,当针对iOS 8.0 SDK进行编译时,编译器知道它认为该方法应该在哪里,所以它优化了所有的内存查找。 一切工作正常,直到我尝试testingvariables,在这一点上,我得到一个EXC_BAD_ACCESS。

然而,在同一个WWDC对话中,我发现关于所有方法的gem是可选的,他们使用可选链来调用一个可选的方法 – 这似乎工作。 跛脚的部分是,你必须真正尝试调用该方法,以便知道它是否存在,在注册通知的情况下,这是一个问题,因为你正在试图找出这个方法是否存在之前,你去创buildUIUserNotificationSettings对象。 似乎用nil调用这个方法虽然没关系,所以似乎对我有用的解决scheme是:

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

在与此有关的许多search之后,关键信息来自于这个WWDC讨论https://developer.apple.com/videos/wwdc/2014/#407正确的中间部分关于“可选方法在协议中”;

在Xcode 6.1testing版中,上面的代码不再工作,下面的代码工作:

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

如果你想添加对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 } } 

在Xcode 6.1 Beta之后,下面的代码工作,稍微编辑了一下Tom S代码,它停止了6.1 beta(与以前的testing版一起工作):

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

你可以使用这个

 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; 

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

如果你需要的只是ios 8的代码,这应该做到这一点。

  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { [application registerUserNotificationSettings: [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]]; [application registerForRemoteNotifications]; } return YES; } 

这是更干净的方式,我做的很好

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

对于iOS 8及以上版本

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