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

时间:2014-06-27 14:15:53

标签: objective-c ios8 apple-push-notifications dyld

尝试在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

14 个答案:

答案 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

  

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

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