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条件或#如果__IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)

dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings
104219 次浏览

我不知道“categories”NSSet变量应该设置为什么,所以如果有人能告诉我,我很乐意编辑这篇文章。但是,下面的操作会弹出推送通知对话框。

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

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

正如你所描述的,你需要根据不同的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视频“iOS通知的新功能”中描述的

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 < a href = " https://stackoverflow.com/a/39383027/3560390 " > < / >

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

因此,由于AnyObject是id的精神继承者,您可以在AnyObject上调用您想要的任何消息。这相当于向id发送消息。好吧,有道理。但现在我们添加了AnyObject上的所有方法都是可选的的概念,我们就有了可以使用的东西。

鉴于上述情况,我希望我可以将UIApplication.sharedApplication()转换为AnyObject,然后创建一个等于方法签名的变量,将该变量设置为可选方法,然后测试该变量。这似乎并不奏效。我的猜测是,当针对iOS 8.0 SDK编译时,编译器知道它认为应该方法在哪里,所以它优化了这一切,直到内存查找。一切正常,直到我尝试测试变量,这时我得到一个EXC_BAD_ACCESS。

然而,在同一个WWDC演讲中,我发现所有方法都是可选的,他们使用可选链接来调用一个可选方法——这似乎是有效的。蹩脚的部分是,你必须尝试调用这个方法来知道它是否存在,这在注册通知的情况下是一个问题,因为你在创建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)
}

在Xcode 6.1 Beta之后,下面的代码可以工作,稍微编辑一下Tom S的代码,它不再与6.1 Beta一起工作(与之前的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)
}

基于@Prasath的回答。这是你在斯威夫特中如何做的:

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

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

我认为如果我们采用这种方法,这是保持向后兼容性的更好方法,它适用于我的案例,希望也适用于你。也很容易理解。

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

对于喜欢斯威夫特的人来说:

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 ([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;

如果你所需要的只是ios 8代码,这应该可以做到。

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


[application registerForRemoteNotifications];
}


return YES;
}

斯威夫特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])


}

我这样做更干净,而且效果很好

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