Introduction
This project NotificationExample helps developers to have a quick idea on how to use new features introduced in iOS 10 to present flexible and powerful notifications to the users. This article explains how to attach media content, actions and customize the notification UI.
Background
iOS 10 came up with more powerful and flexible local and remote notification features for developers. It introduced two new frameworks.
They are
- UserNotifications.framework
- UserNotificationsUI.framework
New features for developers
- Notification supports video, audio, and images.
- Notification gets displayed even if App is in foreground
- Add actions to notification
- Enable quick reply text
- GIF image support
- Customized User Interface for notification
Using the code
Let us create a local notification using new features in iOS 10.
In Xcode, go to build phases and add UserNotifications.framework and UserNotificationsUI.frameworks
#import <UserNotifications/UserNotifications.h>
Get notification when App is in foreground
extend UNUserNotificationCenterDelegate protocol in your .h/App delegate file and implement willPresentNotification delegate method by executing UNNotificationPresentationOptionAlert in the completion handler.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0){
completionHandler(UNNotificationPresentationOptionAlert);
}
Registration for Notification Service
It is mandatory for both local and remote notification
@property(strong,nonatomic) UNUserNotificationCenter* notiCenter;
Add above property in your class extension
_notiCenter = [UNUserNotificationCenter currentNotificationCenter];
_notiCenter.delegate=self;
[_notiCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if(granted)
{
[_notiCenter setDelegate:self];
[self generateTimerBasedNotification];
[self generateLocationBasedNotification];
}
}];
We can also read notification settings value programmatically in iOS 10 using the API class UNUserNotificationCenter
[_notiCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if(settings.soundSetting==UNNotificationSettingEnabled)
{
NSLog(@"Sound Notification is Enabled");
}
else
{
NSLog(@"Sound Notification is Disabled");
}
if(settings.alertSetting==UNNotificationSettingEnabled)
{
NSLog(@"Alert Notification is Enabled");
}
else
{
NSLog(@"Alert Notification is Disabled");
}
if(settings.badgeSetting==UNNotificationSettingEnabled)
{
NSLog(@"Badge is Enabled");
}
else
{
NSLog(@"Badge is Disabled");
}
}];
Let us have a look at 2 App extensions newly added in iOS 10 for notification.
-
Notification Service
-
Notification Content
Notification Service Extension
It runs in the background to download any URL, which is specified in the remote notification or replace any content of remote notification before it is displayed to the user.
Go to file->New->Target select Notification Service Extension
After adding the target, NotificationService.h ,NotificationService.m and info.plist files will be created.
NotificationService class derived from UNNotificationServiceExtension, this base class has only 2 messages and Notification Service works only with remote notification.
(void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent *contentToDeliver))contentHandler;
Use above delegate method to download URL content mentioned in your remote notification to display it to user
(void)serviceExtensionTimeWillExpire;
If your App can’t complete the content download within the given time (time between when the device received remote notification and before it is delivered to the user) then use the above delegate method to define an alternative solution.
Once the device received the remote notification and before displaying it to the user, the system will run this service extension. First, the system will call didReceiveNotificationRequest , here you can get the notification data from UNNotificationRequest , and get the media URL and start downloading it. The system will call serviceExtensionTimeWillExpire method to tell you that allotted time to download the content is going to get over. Here is the place where you can have some alternative solutions, maybe you can replace it with a static image, video or audio.
Notification Content
Go to file->New->Target , select Notification Content
This content extension helps developers to add their own view or custom views and also for handling the user actions on the notification. But these views are non-interactive.
Once you add the target, NotificationViewController.h, NotificationViewController.m, MainInterface.storyboard and info.plist files will be created.
Please use MainInterface.storyboard to customize the notification view. Select Notification View Controller Scene, and tap on Main View and go to Size inspector and set the height same as its width.
NotificationViewController Class extends UNNotificationContentExtension with main two delegate methods didReceiveNotification and didReceiveNotificationResponse
The system calls didReceiveNotificationResponse delegate method in this extension when the user taps on any action buttons.
Let us see how to create a notification with action buttons and media file
Attaching image to notification
Using UNMutableNotificationContent class, developers can add rich content to the notification.
In the case of a local notification, we can add the path of images, audio or video to the UNMutableNotificationContent.attachments.
UNMutableNotificationContent *notificationcontent = [[UNMutableNotificationContent alloc] init];
notificationcontent.title = [NSString localizedUserNotificationStringForKey:@"New Arrivals" arguments:nil];
notificationcontent.body = [NSString localizedUserNotificationStringForKey:@"New arrival of Your favourite products!"
arguments:nil];
notificationcontent.sound = [UNNotificationSound defaultSound];
notificationcontent.categoryIdentifier=@"com.mcoe.notificationcategory.timerbased";
NSError *error=nil;
NSURL *fileFromBundle =[[NSBundle mainBundle] URLForResource:@"psc" withExtension:@"png"];
NSURL *url = [[self applicationDocumentsDirectory]URLByAppendingPathComponent:@"psc.png"];
NSError *error1;
[[NSFileManager defaultManager]copyItemAtURL:fileFromBundle toURL:url error:&error1];
UNNotificationAttachment *image_attachment=[UNNotificationAttachment attachmentWithIdentifier:@"com.mcoe.notificationcategory.timerbased" URL:url options:nil error:&error];
notificationcontent.attachments=[NSArray arrayWithObject:image_attachment];
notificationcontent.badge = @([[UIApplication sharedApplication] applicationIconBadgeNumber] + 1);
Adding Actions to Notification
There are mainly 3 kinds of actions
- Default Actions – The default action is when the user opens the App from notification.
- Custom Actions – Quick action can be executed directly from the notification itself without launching the App. These Custom actions can be background or foreground. Background custom actions can dismiss the notification and the System will be providing a limited amount of time in the background to execute the custom action. The foreground actions can dismiss the notification and can launch the app to execute the custom action.
- Dismiss Actions
UNNotificationAction *checkoutAction = [UNNotificationAction actionWithIdentifier:@"com.mcoe.notificationcategory.timerbased.yes" title:@"Check out" options:UNNotificationActionOptionForeground];
UNNotificationAction *declineAction = [UNNotificationAction actionWithIdentifier:@"com.mcoe.notificationcategory.timerbased.no" title:@"Decline" options:UNNotificationActionOptionDestructive];
UNNotificationAction *laterAction = [UNNotificationAction actionWithIdentifier:@"com.mcoe.notificationcategory.timerbased.dismiss" title:@"Later" options:UNNotificationActionOptionDestructive];
NSArray *notificationActions = @[ checkoutAction, declineAction, laterAction ];
UNNotificationCategory *notificationCategory=[UNNotificationCategory categoryWithIdentifier:@"com.mcoe.notificationcategory.timerbased" actions:notificationActions intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];
NSSet *categories = [NSSet setWithObject:notificationCategory];
[_notiCenter setNotificationCategories:categories];
Scheduling the notification
Local notification can be triggered in 3 ways
-
Time interval
-
Calendar time
- Location
Time Interval
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger
triggerWithTimeInterval:3.f repeats:NO];
Location
CLLocationCoordinate2D officeArea = CLLocationCoordinate2DMake(12.970540,80.251060);
CLCircularRegion* officeRegion = [[CLCircularRegion alloc] initWithCenter:officeArea
radius:10 identifier:@"My Office Bay"];
officeRegion.notifyOnEntry = YES;
officeRegion.notifyOnExit = YES;
UNLocationNotificationTrigger* locationTrigger = [UNLocationNotificationTrigger
triggerWithRegion:officeRegion repeats:YES];
Creating the request object and add it to the Notification Center
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"com.mcoe.notificationcategory.timerbased"
content:notificationcontent trigger:timerbasedtrigger];
[_notiCenter addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"added timer based NotificationRequest suceessfully!");
}
}];
Please note that the category identifier you assign to UNNotificationCategory object and the identifier name of UNNotificationExtensionCategory in info.plist of notification content extension should be same.
As we can add multiple content extensions to the project, the system uses the category identifier name from the received notification and contact its corresponding extension codebase to call its delegate methods.
UNNotificationExtensionInitialContentSizeRatio in info.plist of notification content extension Indicates the aspect ratio of custom interface. Its value is between 0 and 1.
1 indicates that the custom interface height is equal to its width.
0 indicates that its height will be half of its total width.