// // AppDelegate+notification.m // pushtest // // Created by Robert Easterday on 10/26/12. // // #import "AppDelegate+notification.h" #import "PushPlugin.h" #import static char launchNotificationKey; @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 { Method original, swizzled; original = class_getInstanceMethod(self, @selector(init)); swizzled = class_getInstanceMethod(self, @selector(swizzled_init)); method_exchangeImplementations(original, swizzled); } - (AppDelegate *)swizzled_init { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(createNotificationChecker:) name:@"UIApplicationDidFinishLaunchingNotification" 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 swizzled_init]; } // This code will be called immediately after application:didFinishLaunchingWithOptions:. We need // to process notifications in cold-start situations - (void)createNotificationChecker:(NSNotification *)notification { if (notification) { NSDictionary *launchOptions = [notification userInfo]; if (launchOptions) self.launchNotification = [launchOptions objectForKey: @"UIApplicationLaunchOptionsRemoteNotificationKey"]; } } - (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 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); }); }; NSMutableDictionary* params = [NSMutableDictionary dictionaryWithCapacity:2]; [params setObject:safeHandler forKey:@"handler"]; PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"]; pushHandler.notificationMessage = userInfo; pushHandler.isInline = NO; pushHandler.handlerObj = params; [pushHandler notificationReceived]; } else { NSLog(@"just put it in the shade"); //save it for later self.launchNotification = userInfo; completionHandler(UIBackgroundFetchResultNewData); } } } - (void)applicationDidBecomeActive:(UIApplication *)application { NSLog(@"active"); 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.notificationMessage = self.launchNotification; self.launchNotification = nil; [pushHandler performSelectorOnMainThread:@selector(notificationReceived) withObject:pushHandler waitUntilDone:NO]; } } //For interactive notification only - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler { //handle the actions if ([identifier isEqualToString:@"declineAction"]){ } else if ([identifier isEqualToString:@"answerAction"]){ } } // 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); } - (void)dealloc { self.launchNotification = nil; // clear the association and release the object } @end