You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by sh...@apache.org on 2015/03/18 00:51:43 UTC

cordova-plugins git commit: CB-8475 - Create plugin to handle local/remote push notification delegates in the app delegate

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 <sh...@apache.org>
Authored: Tue Mar 17 16:51:42 2015 -0700
Committer: Shazron Abdullah <sh...@apache.org>
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 <objc/runtime.h>
 
-@implementation CDVAppDelegate (SwizzledMethods)
+#pragma mark Global Methods
 
-+ (void)load
+// Return a NSArray<Class> 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