Socialize

Feel free to follow me on twitter

iOS8 – Interactive Notifications

Posted on Jun 26, 2014

As of iOS8 you can add buttons to push and local notifications in order to trigger actions.

The banner and notification centre style notification allows a maximum of 2 buttons whilst the alert view style allows up to 4 (in addition to the mandatory Open and Close actions).

Notification Center:


Banner Style:


Alert Style (yes two button taps required :o(  )



Given an application that already supports push the below details extending this to include action buttons.

1. Create your actions(usually in the appDelegate didFinishLaunchingWithOptions) as instances of UIMutableUserNotificationAction, below is a an example of an Accept and Decline action.

// Setup each action thar will appear in the notification
    UIMutableUserNotificationAction *acceptAction = [[UIMutableUserNotificationAction alloc] init];
    acceptAction.identifier = ACCEPT_ACTION; // Identifier is returned in handleActionWithIdentifier: after the user taps on an action
    acceptAction.title = ACCEPT_TITLE;
    acceptAction.activationMode = UIUserNotificationActivationModeForeground; //Brings the app into the foreground when action tapped
    
    /* Optional properties
    acceptAction.destructive = NO;
    acceptAction.authenticationRequired = NO; */
    
    UIMutableUserNotificationAction *declineAction = [[UIMutableUserNotificationAction alloc] init];
    declineAction.identifier = DECLINE_ACTION;
    declineAction.title = DECLINE_TITLE;
    declineAction.activationMode = UIUserNotificationActivationModeBackground; //Allows app to remain the background when action tapped

 

2. Create a category to group your actions and give it an identifier, then add your category to a set.

UIMutableUserNotificationCategory *callCat = [[UIMutableUserNotificationCategory alloc] init];
    callCat.identifier = CALL_CATEGORY;
  
    [callCat setActions:@[acceptAction, declineAction] forContext:UIUserNotificationActionContextDefault];
 
    NSSet *categories = [NSSet setWithObjects:callCat, nil];

 

3. Register your app for User Notifications with an instance of UIUserNotificationSettings that includes your categories set. You still need to call registerForRemoteNotifications to handle push.

[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:categories]];
    
    [[UIApplication sharedApplication] registerForRemoteNotifications];

 

4. Still in the app delegate, aside from the usual didReceiveLocalNotification and didReceiveRemoteNotification you should implement handleActionWithIdentifier:forLocalNotification and handleActionWithIdentifier:forRemoteNotification:. These are called when an action button is tapped within a notification and the identifier you gave to the action is provided.

//Called for local notification action events
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler
{
    NSLog(@"AppDelegate - handleActionWithIdentifier: %@", identifier);
    
    if ([identifier isEqualToString:ACCEPT_ACTION]) {
        
        //handle accept action
        NSLog(@"User accepted phone call");
        
    } else if ([identifier isEqualToString:DECLINE_ACTION]) {
        
        //handle cancel action
        NSLog(@"User dismissed phone call");
    }
    
    //must call completion handler when finished
    completionHandler();
}
//Called for remote notification action events
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler
{
    NSLog(@"AppDelegate - handleActionWithIdentifier: %@", identifier);
    
    if ([identifier isEqualToString:ACCEPT_ACTION]) {
        
        //handle accept action
        NSLog(@"User accepted phone call");
        
    } else if ([identifier isEqualToString:DECLINE_ACTION]) {
        
        //handle cancel action
        NSLog(@"User dismissed phone call");
    }
    
    //must call completion handler when finished
    completionHandler();
}

 

5. When sending a push notification, along with the usual key/values, the JSON payload should additionally include a “category” key and a value that’s the identifier you gave to your category in step 2.

{
    "aps" : {
        "category" : "CALL_CATEGORY",
    }
}

 

6. When sending local notifications set the ‘category’ property to the identifier you assigned to your category in step 2.

- (void)sendLocalNotificationInForeground:(BOOL)foreground
{
    UILocalNotification *localNotif = [[UILocalNotification alloc] init];
    
    // Set the category to the category that contains our action
    localNotif.category = CALL_CATEGORY;
    localNotif.alertBody = @"Incoming call from 0777856544...";
    localNotif.soundName = UILocalNotificationDefaultSoundName;
    localNotif.applicationIconBadgeNumber = 1;
    localNotif.userInfo = [NSDictionary dictionaryWithObject:@"07779325657" forKey:@"PhoneNumber"];
    
    if (foreground) {
        [[UIApplication sharedApplication] presentLocalNotificationNow:localNotif];
        
    } else {
        localNotif.fireDate = [NSDate dateWithTimeIntervalSinceNow:5]; //5 seconds
        [[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
    }
    
    NSLog(@"Sending Local notification");
}

 

As you can see, Apple made it really easy to extend push notifications to include interactive actions and I look forward to seeing what developers come up with following the launch of iOS8. Hopefully Apple will at some point release the ‘quick reply’ api seen within the standard iOS8 messages app to third parties to allow quick replying to for example Facebook comments or tweets.