iOS 10 – User’s Privacy revised.

A significant change in iOS 10 is that you must declare ahead of time any access to private data or your App will crash. The fix is quick but easy to overlook if the usage is not a major feature of an App so here is your reminder if you are planning an iOS 10 migration.

 

Because being forgetful can cause you a lot

Once you link with iOS 10 you must declare access to any user private data types. You do this by adding a usage key to your app’s Info.plist together with a purpose string. The list of frameworks that count as private data is a long one:

Contacts, Calendar, Reminders, Photos, Bluetooth Sharing, Microphone, Camera, Location, Health, HomeKit, Media Library, Motion, CallKit, Speech Recognition, SiriKit, TV Provider.

If you are using one of these frameworks and fail to declare the usage your app will crash when it first makes the access. The crash log helpfully tells you which key you are missing. For example, this is the result of accessing the camera without adding the key to Info.plist:

This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.

To avoid the crash we need to add the suggested key to ‘Info.plist’ (Xcode 8 already contains the full list of possible keys):

2016-07-03-001.png

 

The system shows the purpose string when asking the user to allow access (so you may want to localize it):

2016-07-03-002.png

 

You may need to refer below links to know more about this.
https://developer.apple.com/videos/play/wwdc2016/709/
https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html

 

 

 

iOS 10 compatibility with notifications.

Step 1 : 

In your Appdelegate.h file

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000

#import <UserNotifications/UserNotifications.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>

#else

@interface AppDelegate : UIResponder <UIApplicationDelegate>

#endif

Step 2 : 

In your Appdelegate.m file

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// other code

  NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];

    if([standardDefaults objectForKey:@”NotificationDeviceToken”]) {

        // Register the supported interaction types.

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000

        {

            UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

            center.delegate = self;

            [center requestAuthorizationWithOptions: (UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){

                if( !error ){

                    [[UIApplication sharedApplication] registerForRemoteNotifications];

                }

            }];

        }

#else

        {

            UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;

            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];

            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];

            // Register for remote notifications.

            [[UIApplication sharedApplication] registerForRemoteNotifications];

        }

#endif

    }

return YES;

}

– (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo {

        NSLog( @”===%s===Notification: %@”,__FUNCTION__, userInfo );

    if (application.applicationState != UIApplicationStateActive)

    {

        // Action to be performed when you recieve push notifications.

    }

}

-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void(^)(UIBackgroundFetchResult))completionHandler {

    

    DLog( @”===%s===Notification: %@”,__FUNCTION__, userInfo );

    [Crittercism leaveBreadcrumb:[NSString stringWithFormat:@”%s”, __FUNCTION__]];

    // iOS 10 will handle notifications through other methods

    if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@”10.0″))

    {

        NSLog( @”iOS version >= 10. Let NotificationCenter handle this one.” );

        // set a member variable to tell the new delegate that this is background

        return;

    }

    

    if (application.applicationState != UIApplicationStateActive)

    {

        // Action to be performed when you recieve push notifications.

        completionHandler( UIBackgroundFetchResultNewData );

    }

}

#pragma mark iOS 10 UserNotification delegates

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000

– (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {

    

    NSLog( @”Handle push from foreground – %s=======Notification:%@”,__FUNCTION__,notification.request.content.userInfo);

    // custom code to handle push while app is in the foreground

    // Action to be performed when you recieve push notifications.

}

– (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {

   

    NSLog( @”Handle push from background or closed – %s=======Notification:%@”,__FUNCTION__,response.notification.request.content.userInfo);    

    // if you set a member variable in didReceiveRemoteNotification, you  will know if this is from closed or background

           // Action to be performed when you recieve push notifications.

}

#endif