summaryrefslogtreecommitdiff
path: root/StoneIsland/plugins/phonegap-plugin-push/src/ios/AppDelegate+notification.m
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/plugins/phonegap-plugin-push/src/ios/AppDelegate+notification.m')
-rw-r--r--StoneIsland/plugins/phonegap-plugin-push/src/ios/AppDelegate+notification.m278
1 files changed, 278 insertions, 0 deletions
diff --git a/StoneIsland/plugins/phonegap-plugin-push/src/ios/AppDelegate+notification.m b/StoneIsland/plugins/phonegap-plugin-push/src/ios/AppDelegate+notification.m
new file mode 100644
index 00000000..fc18dd79
--- /dev/null
+++ b/StoneIsland/plugins/phonegap-plugin-push/src/ios/AppDelegate+notification.m
@@ -0,0 +1,278 @@
+//
+// AppDelegate+notification.m
+// pushtest
+//
+// Created by Robert Easterday on 10/26/12.
+//
+//
+
+#import "AppDelegate+notification.h"
+#import "PushPlugin.h"
+#import <objc/runtime.h>
+
+static char launchNotificationKey;
+static char coldstartKey;
+
+@implementation AppDelegate (notification)
+
+- (id) getCommandInstance:(NSString*)className
+{
+ return [self.viewController getCommandInstance:className];
+}
+
+// its dangerous to override a method from within a category.
+// Instead we will use method swizzling. we set this up in the load call.
++ (void)load
+{
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ Class class = [self class];
+
+ SEL originalSelector = @selector(init);
+ SEL swizzledSelector = @selector(pushPluginSwizzledInit);
+
+ Method original = class_getInstanceMethod(class, originalSelector);
+ Method swizzled = class_getInstanceMethod(class, swizzledSelector);
+
+ BOOL didAddMethod =
+ class_addMethod(class,
+ originalSelector,
+ method_getImplementation(swizzled),
+ method_getTypeEncoding(swizzled));
+
+ if (didAddMethod) {
+ class_replaceMethod(class,
+ swizzledSelector,
+ method_getImplementation(original),
+ method_getTypeEncoding(original));
+ } else {
+ method_exchangeImplementations(original, swizzled);
+ }
+ });
+}
+
+- (AppDelegate *)pushPluginSwizzledInit
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(createNotificationChecker:)
+ name:UIApplicationDidFinishLaunchingNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]addObserver:self
+ selector:@selector(pushPluginOnApplicationDidBecomeActive:)
+ name:UIApplicationDidBecomeActiveNotification
+ object:nil];
+
+ // This actually calls the original init method over in AppDelegate. Equivilent to calling super
+ // on an overrided method, this is not recursive, although it appears that way. neat huh?
+ return [self pushPluginSwizzledInit];
+}
+
+// This code will be called immediately after application:didFinishLaunchingWithOptions:. We need
+// to process notifications in cold-start situations
+- (void)createNotificationChecker:(NSNotification *)notification
+{
+ NSLog(@"createNotificationChecker");
+ if (notification)
+ {
+ NSDictionary *launchOptions = [notification userInfo];
+ if (launchOptions) {
+ NSLog(@"coldstart");
+ self.launchNotification = [launchOptions objectForKey: @"UIApplicationLaunchOptionsRemoteNotificationKey"];
+ self.coldstart = [NSNumber numberWithBool:YES];
+ } else {
+ NSLog(@"not coldstart");
+ self.coldstart = [NSNumber numberWithBool:NO];
+ }
+ }
+}
+
+- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
+ PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
+ [pushHandler didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
+}
+
+- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
+ PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
+ [pushHandler didFailToRegisterForRemoteNotificationsWithError:error];
+}
+
+- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
+ NSLog(@"clicked on the shade");
+ PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
+ pushHandler.notificationMessage = userInfo;
+ pushHandler.isInline = NO;
+ [pushHandler notificationReceived];
+}
+
+- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
+ NSLog(@"didReceiveNotification with fetchCompletionHandler");
+
+ // app is in the foreground so call notification callback
+ if (application.applicationState == UIApplicationStateActive) {
+ NSLog(@"app active");
+ PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
+ pushHandler.notificationMessage = userInfo;
+ pushHandler.isInline = YES;
+ [pushHandler notificationReceived];
+
+ completionHandler(UIBackgroundFetchResultNewData);
+ }
+ // app is in background or in stand by
+ else {
+ NSLog(@"app in-active");
+
+ // do some convoluted logic to find out if this should be a silent push.
+ long silent = 0;
+ id aps = [userInfo objectForKey:@"aps"];
+ id contentAvailable = [aps objectForKey:@"content-available"];
+ if ([contentAvailable isKindOfClass:[NSString class]] && [contentAvailable isEqualToString:@"1"]) {
+ silent = 1;
+ } else if ([contentAvailable isKindOfClass:[NSNumber class]]) {
+ silent = [contentAvailable integerValue];
+ }
+
+ if (silent == 1) {
+ NSLog(@"this should be a silent push");
+ void (^safeHandler)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult result){
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completionHandler(result);
+ });
+ };
+
+ PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
+
+ if (pushHandler.handlerObj == nil) {
+ pushHandler.handlerObj = [NSMutableDictionary dictionaryWithCapacity:2];
+ }
+
+ id notId = [userInfo objectForKey:@"notId"];
+ if (notId != nil) {
+ NSLog(@"Push Plugin notId %@", notId);
+ [pushHandler.handlerObj setObject:safeHandler forKey:notId];
+ } else {
+ NSLog(@"Push Plugin notId handler");
+ [pushHandler.handlerObj setObject:safeHandler forKey:@"handler"];
+ }
+
+ pushHandler.notificationMessage = userInfo;
+ pushHandler.isInline = NO;
+ [pushHandler notificationReceived];
+ } else {
+ NSLog(@"just put it in the shade");
+ //save it for later
+ self.launchNotification = userInfo;
+
+ completionHandler(UIBackgroundFetchResultNewData);
+ }
+ }
+}
+
+- (BOOL)userHasRemoteNotificationsEnabled {
+ UIApplication *application = [UIApplication sharedApplication];
+ if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
+ return application.currentUserNotificationSettings.types != UIUserNotificationTypeNone;
+ } else {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+ return application.enabledRemoteNotificationTypes != UIRemoteNotificationTypeNone;
+#pragma GCC diagnostic pop
+ }
+}
+
+- (void)pushPluginOnApplicationDidBecomeActive:(NSNotification *)notification {
+
+ NSLog(@"active");
+
+ UIApplication *application = notification.object;
+
+ PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
+ if (pushHandler.clearBadge) {
+ NSLog(@"PushPlugin clearing badge");
+ //zero badge
+ application.applicationIconBadgeNumber = 0;
+ } else {
+ NSLog(@"PushPlugin skip clear badge");
+ }
+
+ if (self.launchNotification) {
+ pushHandler.isInline = NO;
+ pushHandler.coldstart = [self.coldstart boolValue];
+ pushHandler.notificationMessage = self.launchNotification;
+ self.launchNotification = nil;
+ self.coldstart = [NSNumber numberWithBool:NO];
+ [pushHandler performSelectorOnMainThread:@selector(notificationReceived) withObject:pushHandler waitUntilDone:NO];
+ }
+}
+
+
+- (void)application:(UIApplication *) application handleActionWithIdentifier: (NSString *) identifier
+forRemoteNotification: (NSDictionary *) notification completionHandler: (void (^)()) completionHandler {
+
+ NSLog(@"Push Plugin handleActionWithIdentifier %@", identifier);
+ NSMutableDictionary *userInfo = [notification mutableCopy];
+ [userInfo setObject:identifier forKey:@"actionCallback"];
+ NSLog(@"Push Plugin userInfo %@", userInfo);
+
+ if (application.applicationState == UIApplicationStateActive) {
+ PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
+ pushHandler.notificationMessage = userInfo;
+ pushHandler.isInline = NO;
+ [pushHandler notificationReceived];
+ } else {
+ void (^safeHandler)() = ^(void){
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completionHandler();
+ });
+ };
+
+ PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
+
+ if (pushHandler.handlerObj == nil) {
+ pushHandler.handlerObj = [NSMutableDictionary dictionaryWithCapacity:2];
+ }
+
+ id notId = [userInfo objectForKey:@"notId"];
+ if (notId != nil) {
+ NSLog(@"Push Plugin notId %@", notId);
+ [pushHandler.handlerObj setObject:safeHandler forKey:notId];
+ } else {
+ NSLog(@"Push Plugin notId handler");
+ [pushHandler.handlerObj setObject:safeHandler forKey:@"handler"];
+ }
+
+ pushHandler.notificationMessage = userInfo;
+ pushHandler.isInline = NO;
+
+ [pushHandler performSelectorOnMainThread:@selector(notificationReceived) withObject:pushHandler waitUntilDone:NO];
+ }
+}
+
+// The accessors use an Associative Reference since you can't define a iVar in a category
+// http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocAssociativeReferences.html
+- (NSMutableArray *)launchNotification
+{
+ return objc_getAssociatedObject(self, &launchNotificationKey);
+}
+
+- (void)setLaunchNotification:(NSDictionary *)aDictionary
+{
+ objc_setAssociatedObject(self, &launchNotificationKey, aDictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (NSNumber *)coldstart
+{
+ return objc_getAssociatedObject(self, &coldstartKey);
+}
+
+- (void)setColdstart:(NSNumber *)aNumber
+{
+ objc_setAssociatedObject(self, &coldstartKey, aNumber, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)dealloc
+{
+ self.launchNotification = nil; // clear the association and release the object
+ self.coldstart = nil;
+}
+
+@end