5 minute recipe for Apple Push Notifications
May 18, 2013
Apple Push Notifications is service launched with iOS 3.0. It uses open IP socket allowing servers send instantly payload to mobile devices like iPhone or iPad. This solution has great advantage over pull approach because there is possibility to send message from application server to client with few bits of network traffic instead of overloading network with periodic queries. There are all snippets of code needed to quickstart with this technology. There are places in documentation where one can wonder how to do something, esspecialy how to handle tokens. Here the code comes:
First application should subscribe to notification on Apple Push Notification (APN) servers:
-(void)APNRegister {
// we should register only once
if (self.registered){
return;
// if notifications are enabled by user
if (config.notificationsEnabled){
// we request registration for specified types of notifcations
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeAlert)];
}
}
We should check at application startup if we should register or registration occurs when user enables notification in app settings. One can use KVO for this like:
[config addObserver:self forKeyPath:@"notificationsEnabled" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial) context:NULL];
NSKeyValueObservingOptionInitial is important to force registration at startup. So we are notified if registration is necessary:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"notificationsEnabled"])
{
if ([change[NSKeyValueChangeNewKey] boolValue]==YES)
[self APNRegister];
}
}
iOS API uses everywhere delegates and callbacks therefore app is to be notfied about successful registration in AppDelegate.m method:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
self.token = [[NSString alloc]initWithFormat:@"%@",[[[deviceToken description]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]
stringByReplacingOccurrencesOfString:@" "
withString:@""]];
self.registered = YES; // one should rememeber that we registered
/*
notify Application Server sending self.token to it
*/
}
If registration is successful we should notfiy our application server to send notificatins via Apple notification service. For example if app is mail client, mail server notifies user about
new e-mail message to be read. Failure should be handled too :
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
// some action here
}
Wow ! Registration is successfull and now client is waiting for notifications. There are TWO ways for notification entry to application.
First when mobile program is running in foreground:
// application delegate method in AppDelegate.m
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[self handleRemoteNotification:userInfo];
}
… and second when app is turned off or in background state :
// application delegate method in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (launchOptions != nil)
{
NSDictionary* dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
[self handleRemoteNotification:dictionary];
}
}
Payload of notification is kind of dictionary in both cases. In second it needs to be extracted from launchOptions dictionary.
No matter what was entry method of notification we can have one handler:
-(void)handleRemoteNotification:(NSDictionary*)payload
{
NSString *someInfo = payload[@"info"]; //extract some information from payload
/*
do some action here, for example get new emails from application server or anything you want
*/
// and finally clear icon badge number if needed
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
}
We are done !!!
Comments
comments powered by Disqus