Ask for permissions for local notifications in iOS 8, but there is still support for iOS 7 applications

I have an application that uses local notifications. In iOS 7, everything works fine, but in iOS 8, the application should ask the user for permission to display notifications. To request permission in iOS 8, I use:

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

It works fine in Xcode 6 and iOS 8. When I open the same project in Xcode 5, the error is a semantic problem. "Use of undeclared identifier" UIUserNotificationSettings "."

How can I make the application work with iOS 7 and 8 and work correctly with notifications in both versions.

+32
ios objective-c xcode
Jul 25 '14 at 1:31
source share
6 answers

The following answer gives several assumptions:

  • When using Xcode 6, the application must correctly create the base iOS 8 SDK, and it must correctly build the base iOS 7 SDK when using Xcode 5.
  • The application must support the iOS 7 deployment target (or earlier), regardless of the base version of the SDK and Xcode.

the code:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // None of the code should even be compiled unless the Base SDK is iOS 8.0 or later #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 // The following line must only run under iOS 8. This runtime check prevents // it from running if it doesn't exist (such as running under iOS 7 or earlier). if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) { [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]]; } #endif } 

All of this is described in the Apple SDK Compatibility Guide.

+62
Jul 25 '14 at 4:26
source share

I implemented simply -

 if([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) { [[UIApplication sharedApplication] registerForRemoteNotifications]; UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; } else { [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge]; } 
+11
Sep 24 '14 at 6:18
source share

If you still want to compile files with older SDKs or have a special reason, you can try to call all the stuff dynamically:

 #ifdef __IPHONE_8_0 #define USING_IOS8_SDK #else // iOS <8 SDK compatibility definitions #define UIUserNotificationTypeNone (0) #define UIUserNotificationTypeBadge (1 << 0) #define UIUserNotificationTypeSound (1 << 1) #define UIUserNotificationTypeAlert (1 << 2) #endif ... if ([_sharedApplication respondsToSelector:NSSelectorFromString(@"registerUserNotificationSettings:")]) { NSUInteger settingsParam = (UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound); id categoriesParam = nil; #ifdef USING_IOS8_SDK // Perform direct call when using iOS 8 SDK [_sharedApplication registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:settingsParam categories:categoriesParam]]; #else #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" // Do the dynamic stuff // Get UIUserNotificationSettings class reference Class settings = NSClassFromString(@"UIUserNotificationSettings"); if (settings) { // Prepare class selector SEL sel = NSSelectorFromString(@"settingsForTypes:categories:"); // Obtain a method signature of selector on UIUserNotificationSettings class NSMethodSignature *signature = [settings methodSignatureForSelector:sel]; // Create an invocation on a signature -- must be used because of primitive (enum) arguments on selector NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.selector = sel; invocation.target = settings; // Set arguments [invocation setArgument:&settingsParam atIndex:2]; [invocation setArgument:&categoriesParam atIndex:3]; // Obtain an instance by firing an invocation NSObject *settingsInstance; [invocation invoke]; [invocation getReturnValue:&settingsInstance]; // Retain an instance so it can live after quitting method and prevent crash :-) CFRetain((__bridge CFTypeRef)(settingsInstance)); // Finally call the desired method with proper settings if (settingsInstance) [_sharedApplication performSelector:NSSelectorFromString(@"registerUserNotificationSettings:") withObject:settingsInstance]; } #pragma clang diagnostic pop #endif } 

This should compile fine in the iOS 7 SDK and work effectively on iOS 8 devices, ignored on older ones.

Porting a project to the iOS 8 SDK is another solution, but there are still options.

+3
Sep 16 '14 at 14:34
source share

So far, this piece of code works for me, and its simple reuse:

 //-- Set Notification 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)]; } 
+3
Sep 16 '14 at 2:54
source share
 if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil]; [application registerUserNotificationSettings:settings]; } 
0
Aug 17 '16 at 10:32
source share

You can try something like this:

 if (NSClassFromString(@"UIUserNotificationSettings") != nil) { // your iOS 8 code here #define isiOS8 } else { #undef isiOS8 } #ifdef isiOS8 [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]]; #endif 

This is a bit confusing, but it works great.

** EDIT ** Improved fixed code

-2
Jul 25 '14 at 1:38
source share



All Articles