registerForRemoteNotificationTypes: is not supported in iOS 8.0 and later

前端 未结 15 1725
时光说笑
时光说笑 2020-11-29 15:09

When trying to register for push notifications under iOS 8.x:

application.registerForRemoteNotificationTypes(UIRemoteNotificationType.Alert | UIRemoteNotific         


        
相关标签:
15条回答
  • 2020-11-29 15:27

    So it turns out that because AnyObject is the spiritual successor to id, you can call any message you want on AnyObject. That's the equivalent of sending a message to id. Ok, fair enough. But now we add in the concept that all methods are optional on AnyObject, and we have something we can work with.

    Given the above, I was hopeful I could just cast UIApplication.sharedApplication() to AnyObject, then create a variable equal to the method signature, set that variable to the optional method, then test the variable. This didn't seem to work. My guess is that when compiled against the iOS 8.0 SDK, the compiler knows where it thinks that method should be, so it optimizes this all down to a memory lookup. Everything works fine until I try to test the variable, at which point I get a EXC_BAD_ACCESS.

    However, in the same WWDC talk where I found the gem about all methods being optional, they use Optional Chaining to call an optional method - and this seems to work. The lame part is that you have to actually attempt to call the method in order to know if it exists, which in the case of registering for notifications is a problem because you're trying to figure out if this method exists before you go creating a UIUserNotificationSettings object. It seems like calling that method with nil though is okay, so the solution that seems to be working for me is:

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

    After much searching related to this, the key info came from this WWDC talk https://developer.apple.com/videos/wwdc/2014/#407 right in the middle at the section about "Optional Methods in Protocols"

    In Xcode 6.1 beta the above code does not work anymore, the code below works:

       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)
        }
    
    0 讨论(0)
  • 2020-11-29 15:28

    If you like to add support to IOS7 IOS8 you can apply this code into your project .

    -(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
        }
    }
    
    0 讨论(0)
  • 2020-11-29 15:28

    This is cleaner way I am doing and it just works great

    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];
         }
    
    0 讨论(0)
  • 2020-11-29 15:32

    As you described, you will need to use a different method based on different versions of iOS. If your team is using both Xcode 5 (which doesn't know about any iOS 8 selectors) and Xcode 6, then you will need to use conditional compiling as follows:

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

    If you are only using Xcode 6, you can stick with just this:

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

    The reason is here is that the way you get notification permissions has changed in iOS 8. A UserNotification is a message shown to the user, whether from remote or from local. You need to get permission to show one. This is described in the WWDC 2014 video "What's New in iOS Notifications"

    0 讨论(0)
  • 2020-11-29 15:33

    iOS 8 has changed notification registration in a non-backwards compatible way. While you need to support iOS 7 and 8 (and while apps built with the 8 SDK aren't accepted), you can check for the selectors you need and conditionally call them correctly for the running version.

    Here's a category on UIApplication that will hide this logic behind a clean interface for you that will work in both Xcode 5 and Xcode 6.

    Header:

    //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
    

    Implementation:

    //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
    
    0 讨论(0)
  • 2020-11-29 15:34

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

    For iOS10

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

    0 讨论(0)
提交回复
热议问题