Created
August 30, 2010 20:38
-
-
Save lolsborn/558014 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
== 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