Skip to content

Instantly share code, notes, and snippets.

@lolsborn
Created August 30, 2010 20:38
Show Gist options
  • Save lolsborn/558014 to your computer and use it in GitHub Desktop.
Save lolsborn/558014 to your computer and use it in GitHub Desktop.
== How to use demo: !PhoneGap with UA push ==
- Create a !PhoneGap project
- Download !PhoneGap [http://github.com/phonegap/phonegap-iphone here], and install it by following README.md
- Create a !PhoneGap project from Xcode !PhoneGap template.
- A good tutorial [http://idebuggedababoon.com/the-quick-start-guide-to-developing-iphone-applications-with-html-css-and-javascript-using-phonegap/ here]
- Add push notification implementation for iPhone.
- Create a folder named "Plugins" in your project folder if it does not exist. Add two files "!PushNotification.h", "!PushNotification.m", which should contain following code snippets. These are iPhone side push notification implementation. Then add these two files to Xcode project inside folder plugins, and set base SDK version for both project and !PhoneGapLib.xcodeproj
- !PushNotification.h
{{{
#import "PhoneGapCommand.h"
@interface PushNotification : PhoneGapCommand {
NSString *registerSuccessCallback;
NSString *registerErrorCallback;
NSDictionary *notificationMessage;
BOOL ready;
}
@property (nonatomic, retain) NSDictionary *notificationMessage;
@property (nonatomic, retain) NSString *registerSuccessCallback;
@property (nonatomic, retain) NSString *registerErrorCallback;
- (void)registerAPN:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)options;
- (void)startNotify:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)options;
- (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
- (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
- (void)setNotificationMessage:(NSDictionary *)notification;
- (void)notificationReceived;
@end
}}}
- !PushNotification.m
{{{
#import "PushNotification.h"
@implementation PushNotification
@synthesize notificationMessage;
@synthesize registerSuccessCallback;
@synthesize registerErrorCallback;
- (void)dealloc {
[notificationMessage release];
[registerSuccessCallback release];
[registerErrorCallback release];
[super dealloc];
}
- (void)registerAPN:(NSMutableArray *)arguments
withDict:(NSMutableDictionary *)options {
NSLog(@"registerAPN:%@\nwithDict:%@", arguments, options);
NSUInteger argc = [arguments count];
if (argc > 0 && [[arguments objectAtIndex:0] length] > 0)
self.registerSuccessCallback = [arguments objectAtIndex:0];
if (argc > 1 && [[arguments objectAtIndex:1] length] > 0)
self.registerErrorCallback = [arguments objectAtIndex:1];
UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeNone;
if ([options objectForKey:@"badge"]) {
notificationTypes |= UIRemoteNotificationTypeBadge;
}
if ([options objectForKey:@"sound"]) {
notificationTypes |= UIRemoteNotificationTypeSound;
}
if ([options objectForKey:@"alert"]) {
notificationTypes |= UIRemoteNotificationTypeAlert;
}
if (notificationTypes == UIRemoteNotificationTypeNone)
NSLog(@"PushNotification.registerAPN: Push notification type is set to none");
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes];
}
- (void)startNotify:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)options {
NSLog(@"startNotify:%@\nwithDict:%@", arguments, options);
ready = YES;
// Check if there is cached notification before JS PushNotification messageCallback is set
if (notificationMessage) {
[self notificationReceived];
}
}
- (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [[[[deviceToken description] stringByReplacingOccurrencesOfString:@"<"withString:@""]
stringByReplacingOccurrencesOfString:@">" withString:@""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
NSLog(@"didRegisterForRemoteNotificationsWithDeviceToken:%@", token);
if (registerSuccessCallback) {
NSString *jsStatement = [NSString stringWithFormat:@"%@({deviceToken:'%@'});",
registerSuccessCallback, token];
[super writeJavascript:jsStatement];
}
}
- (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"didFailToRegisterForRemoteNotificationsWithError:%@", error);
if (registerErrorCallback) {
NSString *jsStatement = [NSString stringWithFormat:@"%@({error:'%@'});",
registerErrorCallback, error];
[super writeJavascript:jsStatement];
}
}
- (void)setNotificationMessage:(NSDictionary *)notification {
NSLog(@"setNotificationMessage:%@", notification);
[notification retain];
[notificationMessage release];
notificationMessage = notification;
if (notificationMessage) {
[self notificationReceived];
}
}
- (void)notificationReceived {
if (ready) {
NSMutableString *jsonStr = [NSMutableString stringWithString:@"{"];
if ([notificationMessage objectForKey:@"alert"]) {
[jsonStr appendFormat:@"alert:'%@',", [notificationMessage objectForKey:@"alert"]];
}
if ([notificationMessage objectForKey:@"badge"]) {
[jsonStr appendFormat:@"badge:%d,", [[notificationMessage objectForKey:@"badge"] intValue]];
}
if ([notificationMessage objectForKey:@"sound"]) {
[jsonStr appendFormat:@"sound:'%@',", [notificationMessage objectForKey:@"sound"]];
}
[jsonStr appendString:@"}"];
NSString *jsStatement = [NSString stringWithFormat:@"navigator.pushNotification.notificationCallback(%@);", jsonStr];
[super writeJavascript:jsStatement];
NSLog(@"run JS: %@", jsStatement);
self.notificationMessage = nil;
}
}
@end
}}}
- you can add your own method, e.g.
{{{
- (void)isEnabled:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)options {
UIRemoteNotificationType type = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
NSString *jsStatement = [NSString stringWithFormat:@"navigator.pushNotification.isEnabled = %d;", type != UIRemoteNotificationTypeNone];
[super writeJavascript:jsStatement];
}
}}}
- ''' <Updated> '''Add following changes to the auto generated app delegate.
- <!ProjectName>!AppDelegate.h. Add one more instance field 'launchNotification'
{{{
@interface <ProjectName>AppDelegate : PhoneGapDelegate {
...
NSDictionary *launchNotification;
...
}
}}}
- <!ProjectName>!AppDelegate.m. Replace auto generated - (void)applicationDidFinishLaunching:(UIApplication *)application with following code
{{{
#import "PushNotification.h"
...
#pragma mark -
#pragma mark Push Notification Related Modification
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// cache notification, if any, until webview finished loading, then process it if needed
// assume will not receive another message before webview loaded
launchNotification = [[launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey] retain];
application.applicationIconBadgeNumber = 0;
[super applicationDidFinishLaunching:application];
return NO;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
PushNotification *pushHandler = [self getCommandInstance:@"PushNotification"];
[pushHandler didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
PushNotification *pushHandler = [self getCommandInstance:@"PushNotification"];
[pushHandler didFailToRegisterForRemoteNotificationsWithError:error];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
PushNotification *pushHandler = [self getCommandInstance:@"PushNotification"];
pushHandler.notificationMessage = [userInfo objectForKey:@"aps"];
}
...
}}}
- Create a file "!PushNotification.js" in /PROJECT_PATH/www/, containing following snippet. Feel free to add more functions.
- !PushNotification.js
{{{
// Gets the function name of a Function object, else uses "alert" if anonymous
function GetFunctionName(fn) {
if (fn) {
var m = fn.toString().match(/^\s*function\s+([^\s\(]+)/);
return m ? m[1] : "alert";
} else {
return null;
}
}
/**
* This class handles iPhone push notification service
* @constructor
*/
function PushNotification() {
if (!this.notificationCallback) {
// default notification callback implementation
this.notificationCallback = function(notification) {
var msg = 'Push Notification:\n';
for (var property in notification) {
msg += property + ' : ' + notification[property] + '\n';
}
alert(msg);
};
}
}
/**
* Start receiving push notification. Should be invoked right after system is loaded
*/
PushNotification.prototype.startNotify = function() {
PhoneGap.exec("PushNotification.startNotify");
}
/**
* Enables push notification as specified in options, or disable if no options provided
* @param {Function} successCallback Invoded after registration successful
* @param {Function} errorCallback Invoded after registration failed
* @param {alert, sound, badge} options Set property [alert | sound | badge] to enable corresponding push notification type.
* Or null to disable push notification
*/
PushNotification.prototype.register = function(successCallback, errorCallback, options) {
PhoneGap.exec("PushNotification.registerAPN", GetFunctionName(successCallback),
GetFunctionName(errorCallback), options);
}
PhoneGap.addConstructor(function() {
if (typeof navigator.pushNotification == "undefined") navigator.pushNotification = new PushNotification();
});
}}}
- In your /PROJECT_PATH/www/index.html or main html file, add following snippet in <head>
{{{
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
/* Import PushNotification.js, should be right after importing phonegap.js and before your custom script */
<script type="text/javascript" charset="utf-8" src="PushNotification.js"></script>
<script type="text/javascript" charset="utf-8">
/* When this function is called, PhoneGap has been initialized and is ready to roll */
function onDeviceReady() {
// IMPORTANT: must start notify after device is ready,
// otherwise you will not be able to receive notification in JS callback
navigator.pushNotification.startNotify();
// Typically, you want to register APN every time when app starts
registerAPN();
}
/**
* Customize following callbacks in your application
*/
// Callback when receiving notification
PushNotification.prototype.notificationCallback = function (notification) {
var msg = '';
for (var property in notification) {
msg += property + ' : ' + notification[property] + '\n';
}
alert(msg);
};
// when register APN succeeded
function successCallback(e) {
alert("Device registered. Device token: " + e.deviceToken);
}
// when register APN failed
function errorCallback(e) {
alert('Error during registration: '+e.error);
}
// register button action
function registerAPN() {
navigator.pushNotification.register(successCallback, errorCallback, { alert:true, badge:true, sound:true });
//specify no parameter or (null, null, {}) to unregister APN
//navigator.pushNotification.register();
}
}}}
- You should be able to receive push notification through !PhoneGap now
- Integrate with Urban Airship Push Service
- Send device token to Urban Airship after push notification registered successfully.
{{{
<script type="text/javascript" charset="utf-8">
...
// when APN register succeeded
function successCallback(e) {
...
registerUAPush(e.deviceToken);
...
}
...
// app key and secret for your Urban Airship application
var HOST = 'https://go.urbanairship.com/';
var KEY = '<YOUR_APP_KEY>';
var SECRET = '<YOUR__APP_SECRET>';
// register with Urban Airship push service
function registerUAPush(deviceToken) {
var request = new XMLHttpRequest();
// open the client and encode our URL
request.open('PUT', HOST+'api/device_tokens/'+deviceToken, true, KEY, SECRET);
// callback when request finished
request.onload = function() {
if(this.status == 200 || this.status == 201) {
// succeeded
alert('UA push service successfully registered.');
} else {
// error
alert('Error when registering UA push service.\nError: '+this.statusText);
}
};
request.send();
}
</script>
}}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment