Return-Path: X-Original-To: apmail-cordova-commits-archive@www.apache.org Delivered-To: apmail-cordova-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 6E08D10B4F for ; Tue, 17 Mar 2015 23:51:46 +0000 (UTC) Received: (qmail 88027 invoked by uid 500); 17 Mar 2015 23:51:43 -0000 Delivered-To: apmail-cordova-commits-archive@cordova.apache.org Received: (qmail 87994 invoked by uid 500); 17 Mar 2015 23:51:43 -0000 Mailing-List: contact commits-help@cordova.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Delivered-To: mailing list commits@cordova.apache.org Received: (qmail 87984 invoked by uid 99); 17 Mar 2015 23:51:43 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 17 Mar 2015 23:51:43 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 1C5E3E17EA; Tue, 17 Mar 2015 23:51:43 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: shazron@apache.org To: commits@cordova.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: cordova-plugins git commit: CB-8475 - Create plugin to handle local/remote push notification delegates in the app delegate Date: Tue, 17 Mar 2015 23:51:43 +0000 (UTC) Repository: cordova-plugins Updated Branches: refs/heads/master 60de2dbd5 -> 976fe8185 CB-8475 - Create plugin to handle local/remote push notification delegates in the app delegate Project: http://git-wip-us.apache.org/repos/asf/cordova-plugins/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugins/commit/976fe818 Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugins/tree/976fe818 Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugins/diff/976fe818 Branch: refs/heads/master Commit: 976fe818556eca390dc433b098ac3bdb38cb1a40 Parents: 60de2db Author: Shazron Abdullah Authored: Tue Mar 17 16:51:42 2015 -0700 Committer: Shazron Abdullah Committed: Tue Mar 17 16:51:42 2015 -0700 ---------------------------------------------------------------------- notification-rebroadcast/README.md | 39 +++- .../src/ios/CDVNotificationRebroadcast.h | 6 +- .../src/ios/CDVNotificationRebroadcast.m | 184 ++++++++++++++++--- 3 files changed, 202 insertions(+), 27 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/976fe818/notification-rebroadcast/README.md ---------------------------------------------------------------------- diff --git a/notification-rebroadcast/README.md b/notification-rebroadcast/README.md index 7d94246..51f6a19 100644 --- a/notification-rebroadcast/README.md +++ b/notification-rebroadcast/README.md @@ -3,9 +3,44 @@ Cordova Notification Rebroadcast Plugin See [CB-8475](https://issues.apache.org/jira/browse/CB-8475). This plugin rebroadcasts remote push notifications as well as local notifications to other plugins. -Install: +This plugin currently needs to use the `4.0.x` branch of `cordova-ios`. - cordova plugin add https://github.com/apache/cordova-plugins.git#master:notification-rebroadcast +To `alpha test` this: + +You may have to remove the cached 4.0.x platform: + + rm -rf ~/.cordova/lib/ios/cordova/4.0.x + +Then: + + cordova create nrtest my.project.id nrtest + cd nrtest + cordova platform add ios@4.0.x --usegit + cordova plugin add https://github.com/apache/cordova-plugins.git#master:notification-rebroadcast + +Document Events +----------- + +Listen for these 3 types of document events in JavaScript: + +1. CDVLocalNotification + + data is a JSON object of the UILocalNotification details + +2. CDVRemoteNotification + + data is a JSON object containing one key, "token" which is the push device token + +3. CDVRemoteNotificationError + + data is a JSON object containing one key, "error", which is the localized error message + +Usage +===== + + document.addEventListener('CDVLocalNotification', function(event) { console.log(event.data); }); + document.addEventListener('CDVRemoteNotification', function(event) { console.log(event.data.token); }); + document.addEventListener('CDVRemoteNotificationError', function(event) { console.log(event.data.error); }); Permissions ----------- http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/976fe818/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.h ---------------------------------------------------------------------- diff --git a/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.h b/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.h index 2cc27be..9fe278d 100644 --- a/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.h +++ b/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.h @@ -21,11 +21,11 @@ @interface CDVAppDelegate (SwizzledMethods) -- (void) customApplication:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification; +- (void) cdv_notification_rebroadcastApplication:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification; -- (void) customApplication:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; +- (void) cdv_notification_rebroadcastApplication:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; -- (void) customApplication:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error; +- (void) cdv_notification_rebroadcastApplication:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error; @end http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/976fe818/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.m ---------------------------------------------------------------------- diff --git a/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.m b/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.m index f064151..b8aae30 100644 --- a/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.m +++ b/notification-rebroadcast/src/ios/CDVNotificationRebroadcast.m @@ -20,35 +20,105 @@ #import "CDVNotificationRebroadcast.h" #import -@implementation CDVAppDelegate (SwizzledMethods) +#pragma mark Global Methods -+ (void)load +// Return a NSArray containing all subclasses of a Class +NSArray* ClassGetSubclasses(Class parentClass) +{ + int numClasses = objc_getClassList(nil, 0); + Class* classes = nil; + + classes = (Class*)malloc(sizeof(Class) * numClasses); + numClasses = objc_getClassList(classes, numClasses); + + NSMutableArray* result = [NSMutableArray array]; + for (NSInteger i = 0; i < numClasses; i++) { + + Class superClass = classes[i]; + do { + superClass = class_getSuperclass(superClass); + } + while(superClass && superClass != parentClass); + + if (superClass == nil) { + continue; + } + + [result addObject:classes[i]]; + } + + free(classes); + + return result; +} + +// Replace or Exchange method implementations +// Return YES if method was exchanged, NO if replaced +BOOL MethodSwizzle(Class clazz, SEL originalSelector, SEL overrideSelector) { - Method original, custom; + Method originalMethod = class_getInstanceMethod(clazz, originalSelector); + Method overrideMethod = class_getInstanceMethod(clazz, overrideSelector); - original = class_getInstanceMethod(self, @selector(application:didReceiveLocalNotification:)); - custom = class_getInstanceMethod(self, @selector(customApplication:didReceiveLocalNotification:)); - method_exchangeImplementations(original, custom); + // try to add, if it does not exist, replace + if (class_addMethod(clazz, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) { + class_replaceMethod(clazz, overrideSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); + } + // add failed, so we exchange + else { + method_exchangeImplementations(originalMethod, overrideMethod); + return YES; + } - original = class_getInstanceMethod(self, @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)); - custom = class_getInstanceMethod(self, @selector(customApplication:didRegisterForRemoteNotificationsWithDeviceToken:)); - method_exchangeImplementations(original, custom); + return NO; +} - original = class_getInstanceMethod(self, @selector(application:didFailToRegisterForRemoteNotificationsWithError:)); - custom = class_getInstanceMethod(self, @selector(customApplication:didFailToRegisterForRemoteNotificationsWithError:)); - method_exchangeImplementations(original, custom); +// Helper to return the Class to swizzle +// We need to swizzle the subclass (if available) of CDVAppDelegate +Class ClassToSwizzle() { + Class clazz = [CDVAppDelegate class]; + + NSArray* subClazz = ClassGetSubclasses(clazz); + if ([subClazz count] > 0) { + clazz = [subClazz objectAtIndex:0]; + } + + return clazz; } -- (void) customApplication:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification +#pragma mark Global Variables + +static BOOL cdvLocalNotifSelExchanged = NO; +static BOOL cdvRemoteNotifSelExchanged = NO; +static BOOL cdvRemoteNotifErrorSelExchanged = NO; + +#pragma mark CDVAppDelegate (SwizzledMethods) + +@implementation CDVAppDelegate (SwizzledMethods) + ++ (void)load +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class clazz = ClassToSwizzle(); + + cdvLocalNotifSelExchanged = MethodSwizzle(clazz, @selector(application:didReceiveLocalNotification:), @selector(cdv_notification_rebroadcastApplication:didReceiveLocalNotification:)); + cdvRemoteNotifSelExchanged = MethodSwizzle(clazz, @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:), @selector(cdv_notification_rebroadcastApplication:didRegisterForRemoteNotificationsWithDeviceToken:)); + cdvRemoteNotifErrorSelExchanged = MethodSwizzle(clazz, @selector(application:didFailToRegisterForRemoteNotificationsWithError:), @selector(cdv_notification_rebroadcastApplication:didFailToRegisterForRemoteNotificationsWithError:)); + }); +} + +- (void) cdv_notification_rebroadcastApplication:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification { // re-post ( broadcast ) [[NSNotificationCenter defaultCenter] postNotificationName:CDVLocalNotification object:notification]; - // no, not recursion. we swapped implementations, remember. calling original implementation - [self customApplication:application didReceiveLocalNotification:notification]; + // if method was exchanged through method_exchangeImplementations, we call ourselves (no, it's not a recursion) + if (cdvLocalNotifSelExchanged) { + [self cdv_notification_rebroadcastApplication:application didReceiveLocalNotification:notification]; + } } -- (void) customApplication:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; +- (void) cdv_notification_rebroadcastApplication:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; { // re-post ( broadcast ) NSString* token = [[[[deviceToken description] @@ -58,28 +128,98 @@ [[NSNotificationCenter defaultCenter] postNotificationName:CDVRemoteNotification object:token]; - // no, not recursion. we swapped implementations, remember. calling original implementation - [self customApplication:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; + // if method was exchanged through method_exchangeImplementations, we call ourselves (no, it's not a recursion) + if (cdvRemoteNotifSelExchanged) { + [self cdv_notification_rebroadcastApplication:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; + } } -- (void) customApplication:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error; +- (void) cdv_notification_rebroadcastApplication:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error; { // re-post ( broadcast ) [[NSNotificationCenter defaultCenter] postNotificationName:CDVRemoteNotificationError object:error]; - // no, not recursion. we swapped implementations, remember. calling original implementation - [self customApplication:application didFailToRegisterForRemoteNotificationsWithError:error]; + // if method was exchanged through method_exchangeImplementations, we call ourselves (no, it's not a recursion) + if (cdvRemoteNotifErrorSelExchanged) { + [self cdv_notification_rebroadcastApplication:application didFailToRegisterForRemoteNotificationsWithError:error]; + } } +@end + +#pragma mark UILocalNotification (JSONString) + +@implementation UILocalNotification (JSONString) + +- (NSString*) cdv_notification_rebroadcastJSONString +{ + NSMutableDictionary* dict = [NSMutableDictionary dictionary]; + + if ([self alertAction]) { + [dict setValue:[self alertAction] forKey:@"alertAction"]; + } + if ([self alertBody]) { + [dict setValue:[self alertBody] forKey:@"alertBody"]; + } + if ([self alertLaunchImage]) { + [dict setValue:[self alertLaunchImage] forKey:@"alertLaunchImage"]; + } + if ([self alertTitle]) { + [dict setValue:[self alertTitle] forKey:@"alertTitle"]; + } + if ([self userInfo]) { + [dict setValue:[self userInfo] forKey:@"userInfo"]; + } + + NSError* error = nil; + NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error]; + NSString* val = nil; + + if (error == nil) { + val = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } + + return val; +} @end +#pragma mark CDVNotificationRebroadcast Plugin + @implementation CDVNotificationRebroadcast : CDVPlugin - (void)pluginInitialize { - // TODO: listen to the notifications, and send to JavaScript as events? + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onLocalNotification:) name:CDVLocalNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRemoteNotification:) name:CDVRemoteNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRemoteNotificationError:) name:CDVRemoteNotificationError object:nil]; +} + + - (void)onLocalNotification:(NSNotification*)notification +{ + UILocalNotification* localNotification = notification.object; + NSString* jsString = [NSString stringWithFormat:@"cordova.fireDocumentEvent('CDVLocalNotification', %@);", [localNotification cdv_notification_rebroadcastJSONString]]; + + [self.commandDelegate evalJs:jsString]; +} + +- (void)onRemoteNotification:(NSNotification*)notification +{ + NSString* token = notification.object; + NSString* jsString = [NSString stringWithFormat:@"cordova.fireDocumentEvent('CDVRemoteNotification', { 'token': '%@'});", token]; + + [self.commandDelegate evalJs:jsString]; } +- (void)onRemoteNotificationError:(NSNotification*)notification +{ + NSError* error = notification.object; + NSString* desc = [error localizedDescription]; + NSString* jsString = [NSString stringWithFormat:@"cordova.fireDocumentEvent('CDVRemoteNotificationError', { 'error': '%@'});", desc]; + + [self.commandDelegate evalJs:jsString]; +} + + @end --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org For additional commands, e-mail: commits-help@cordova.apache.org