Creating a Custom Push Handler for Urban Airship for iOS
Github Repo
A custom push handler is used to open your app to specific content depending on the contents provided by a push notification's payload.
Here are some necessary steps I took. For the rest refer to the code below.
1. Implement didReceiveRemoteNotification in your app delegate.
Set your custom push notification delegate.
Call handleNotification.
2. In didFinishLaunchingWithOptions in your app delegate:
Make sure to include all of the necessary library calls in the template project.
Note: There are some additional functions that can be implemented to deal with UA badges, etc. To see what is available, go to the header declaration for UA's push notification handler. Unfortunately the implementation is black boxed in UA's library files.
//
// CustomUAPushHandler.h
// MyCustomPushHandler
//
// Created by Raj Wilhoit on 9/9/13.
// Copyright (c) 2013 UF.rajwilhoit. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "UAirship.h"
#import "UAPush.h"
#import "UAAnalytics.h"
@interface CustomUAPushHandler : NSObject <UIAlertViewDelegate, UAPushNotificationDelegate>
// singleton
+ (SSDPCustomUAPushNotificationHandler *)sharedInstance;
@property (nonatomic, strong) NSString *id; // The id of the asset or item that the push notification wants to open
@property (nonatomic) BOOL launchedFromColdStart; // A flag for if we are opening the app from a cold start
@property (nonatomic) BOOL receivedPushNotification; // A flag for if we have received a push notification. Set to nil after you have finished
// handling the noitifcation
@property (nonatomic) BOOL delegateLock; // A lock for the delegate to handle a UA bug where UA's UAAutoDelegate would fire my methods for
// the custom handler at the same time my custom handler would
/**
* Called when an alert notification is received in the foreground.
* @param alertMessage a simple string to be displayed as an alert
*/
- (void)displayNotificationAlert:(NSString *)alertMessage;
/**
* Called when a push notification is received while the app is running in the foreground.
*
* @param notification The notification dictionary.
*/
- (void)receivedForegroundNotification:(NSDictionary *)notification;
/**
* Called when the app is started or resumed because a user opened a notification.
*
* @param notification The notification dictionary.
*/
- (void)launchedFromNotification:(NSDictionary *)notification;
@end
//
// CustomUAPushHandler.m
// MyCustomPushHandler
//
// Created by Raj Wilhoit on 9/9/13.
// Copyright (c) 2013 UF.rajwilhoit. All rights reserved.
//
#import "CustomUAPushHandler.h"
@implementation CustomUAPushHandler
@synthesize id = _id;
#pragma mark - sharedInstance
/*
I used a singleton to tell the delegate that THIS is the custom push handler to use
*/
+ (CustomUAPushHandler *)sharedInstance
{
static CustomUAPushHandler *sharedInstance;
@synchronized(self)
{
if (sharedInstance == nil) {
sharedInstance = [[CustomUAPushHandler alloc] init];
}
return sharedInstance;
}
}
/*
This will make it so after calling id once, the id value will be set to nil.
The point is to make sure there won't be a value for id that is remaining from a previous usage
(Since we're using a handler with a singleton instance)
*/
- (NSString *)id
{
NSString *identifier = _id;
_id = nil;
return identifier;
}
/*
This will display a UIAlert notificication, where the alertMessage
variable contains the body of the push notification message
*/
- (void)displayNotificationAlert:(NSString *)alertMessage {
UA_LDEBUG(@"Received an alert in the foreground.");
/*
Unfortunately due to a bug I encountered with UA I had to create a lock (think semaphores)
that would only let my own custom handler show a UIAlert. This may not be the case for you.
*/
if(self.delegateLock) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"My App Name"
message: alertMessage
delegate: self
cancelButtonTitle: @"Cancel"
otherButtonTitles: @"Open",nil];
self.delegateLock = NO;
[alert show];
}
}
/*
This checks if the user clicked cancel for the foreground push notification.
You must 'nil' out the value for the id if the user cancels the notification.
*/
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != 0) {
[[NSNotificationCenter defaultCenter] postNotificationName:DATA_READY_TO_DISPLAY_NOTIFICATION object:nil];
}
else {
self.id = nil;
}
}
/*
This is called when receiving a notification in the foreground
*/
- (void)receivedForegroundNotification:(NSDictionary *)notification {
UA_LDEBUG(@"Received a notification while the app was already in the foreground");
if([notification count] != 0) {
// I had to use this flag to handle how to display the assets down the line
[SSDPCustomUAPushNotificationHandler sharedInstance].launchedFromColdStart = NO;
// Set the id given from the push notifcation
[self handleAssetFromPushNotification:notification];
}
}
/*
This is called when the user opens the app from a notification
*/
- (void)launchedFromNotification:(NSDictionary *)notification {
if([notification count] != 0) {
// Set the id given from the push notifcation
[self handleAssetFromPushNotification:notification];
[[NSNotificationCenter defaultCenter] postNotificationName:DATA_READY_TO_DISPLAY_NOTIFICATION object:nil];
}
}
/*
This reads JSON from the notification to take out the information we need
to follow the notification's directions. In this case I want to open an asset
with an id from the JSON value ID.
*/
- (void)handleAssetFromPushNotification:(NSDictionary *)notification {
if([notification count] != 0)
{
// Set flag for receiving a push notification
[self setReceivedPushNotification:YES];
// Check that the value for id actually exists
if ([notification valueForKey:@"id"])
{
// Find asset id and start dashboard
[self setId:[[NSString alloc] initWithFormat:@"%@",[notification valueForKey:@"id"]]];
}
}
}
}
@end












