diff --git a/plugin.xml b/plugin.xml index 68a46ff3..935c6463 100755 --- a/plugin.xml +++ b/plugin.xml @@ -55,16 +55,17 @@ + + - - + diff --git a/src/android/com/plugin/android-support-v13.jar b/src/android/com/plugin/android-support-v13.jar deleted file mode 100644 index cd47212b..00000000 Binary files a/src/android/com/plugin/android-support-v13.jar and /dev/null differ diff --git a/src/android/com/plugin/gcm/BackgroundNotificationReceiver.java b/src/android/com/plugin/gcm/BackgroundNotificationReceiver.java new file mode 100644 index 00000000..f6854e4a --- /dev/null +++ b/src/android/com/plugin/gcm/BackgroundNotificationReceiver.java @@ -0,0 +1,37 @@ +package com.plugin.gcm; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; +import android.app.NotificationManager; +import android.os.Bundle; + +public class BackgroundNotificationReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + Log.v("NOTIFS", "BROADCAST RECEIVER"); + + Bundle extras = intent.getExtras(); + boolean isPushPluginActive = PushPlugin.isActive(); + + + if (extras != null) { + Bundle originalExtras = extras.getBundle("pushBundle"); + + originalExtras.putBoolean("foreground", false); + originalExtras.putBoolean("coldstart", !isPushPluginActive); + + String actionSelected = extras.getString(GCMIntentService.ACTION_KEY); + originalExtras.putString("actionSelected", actionSelected); + + PushPlugin.sendExtras(originalExtras); + + // cancel the notification when an action button is clicked + final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancel(GCMIntentService.getAppName(context), extras.getInt("notId")); + } + } + +} diff --git a/src/android/com/plugin/gcm/CordovaGCMBroadcastReceiver.java b/src/android/com/plugin/gcm/CordovaGCMBroadcastReceiver.java index e383f846..85714c21 100644 --- a/src/android/com/plugin/gcm/CordovaGCMBroadcastReceiver.java +++ b/src/android/com/plugin/gcm/CordovaGCMBroadcastReceiver.java @@ -16,4 +16,4 @@ protected String getGCMIntentServiceClassName(Context context) { return "com.plugin.gcm" + DEFAULT_INTENT_SERVICE_CLASS_NAME; } -} \ No newline at end of file +} diff --git a/src/android/com/plugin/gcm/GCMIntentService.java b/src/android/com/plugin/gcm/GCMIntentService.java index caee145e..3392a9c3 100644 --- a/src/android/com/plugin/gcm/GCMIntentService.java +++ b/src/android/com/plugin/gcm/GCMIntentService.java @@ -2,6 +2,8 @@ import org.json.JSONException; import org.json.JSONObject; +import org.json.JSONArray; +import java.util.Random; import android.annotation.SuppressLint; import android.app.Notification; @@ -13,12 +15,14 @@ import android.support.v4.app.NotificationCompat; import android.util.Log; + import com.google.android.gcm.GCMBaseIntentService; @SuppressLint("NewApi") public class GCMIntentService extends GCMBaseIntentService { private static final String TAG = "GCMIntentService"; + public static final String ACTION_KEY = "PUSH_NOTIFICATION_ACTION_IDENTIFIER"; public GCMIntentService() { super("GCMIntentService"); @@ -61,7 +65,9 @@ protected void onMessage(Context context, Intent intent) { // Extract the payload from the message Bundle extras = intent.getExtras(); - if (extras != null) + + Log.v(TAG, "extras: " + extras.toString()); + if (extras != null && !PushPlugin.isIntercomPush(extras)) { // if we are in the foreground, just surface the payload, else post it to the statusbar if (PushPlugin.isInForeground()) { @@ -97,7 +103,7 @@ public void createNotification(Context context, Bundle extras) defaults = Integer.parseInt(extras.getString("defaults")); } catch (NumberFormatException e) {} } - + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context) .setDefaults(defaults) @@ -131,11 +137,40 @@ public void createNotification(Context context, Bundle extras) catch(Exception e) { Log.e(TAG, "Number format exception - Error parsing Notification ID" + e.getMessage()); } - + + String cat_id = extras.getString("categoryName"); + if(cat_id != null) { + JSONObject category = PushPlugin.categories.optJSONObject(cat_id); + JSONArray actions = category.optJSONArray("actions"); + int requestCode; + + // add each action + for(int i = 0; i < actions.length(); i++) { + JSONObject action = actions.optJSONObject(i); + requestCode = new Random().nextInt(); + + // set up correct receiver for foreground or background handler + //if(extras.getString("activationMode") == "background") { + // notificationIntent = new Intent(this, BackgroundNotificationReceiver.class); + //} + //else { + notificationIntent = new Intent(this, PushHandlerActivity.class); + //} + notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + notificationIntent.putExtra("pushBundle", extras); + notificationIntent.putExtra("notId", notId); + notificationIntent.putExtra(ACTION_KEY, action.optString("identifier")); + + contentIntent = PendingIntent.getBroadcast(this, requestCode, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT); + + mBuilder = mBuilder.addAction(action.optInt("icon"), action.optString("title"), contentIntent); + } + } + mNotificationManager.notify((String) appName, notId, mBuilder.build()); } - private static String getAppName(Context context) + public static String getAppName(Context context) { CharSequence appName = context diff --git a/src/android/com/plugin/gcm/PushHandlerActivity.java b/src/android/com/plugin/gcm/PushHandlerActivity.java index 3675cfec..c55f6fef 100644 --- a/src/android/com/plugin/gcm/PushHandlerActivity.java +++ b/src/android/com/plugin/gcm/PushHandlerActivity.java @@ -27,6 +27,7 @@ public void onCreate(Bundle savedInstanceState) boolean isPushPluginActive = PushPlugin.isActive(); processPushBundle(isPushPluginActive); + finish(); if (!isPushPluginActive) { @@ -38,17 +39,24 @@ public void onCreate(Bundle savedInstanceState) * Takes the pushBundle extras from the intent, * and sends it through to the PushPlugin for processing. */ - private void processPushBundle(boolean isPushPluginActive) + public void processPushBundle(boolean isPushPluginActive) { Bundle extras = getIntent().getExtras(); - if (extras != null) { + if (extras != null && !PushPlugin.isIntercomPush(extras)) { Bundle originalExtras = extras.getBundle("pushBundle"); originalExtras.putBoolean("foreground", false); originalExtras.putBoolean("coldstart", !isPushPluginActive); + String actionSelected = extras.getString(GCMIntentService.ACTION_KEY); + originalExtras.putString("actionSelected", actionSelected); + PushPlugin.sendExtras(originalExtras); + + // cancel the notification when an action button is clicked + final NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancel(GCMIntentService.getAppName(this), extras.getInt("notId")); } } @@ -69,4 +77,4 @@ protected void onResume() { notificationManager.cancelAll(); } -} \ No newline at end of file +} diff --git a/src/android/com/plugin/gcm/PushPlugin.java b/src/android/com/plugin/gcm/PushPlugin.java index 3e390856..e71d5537 100644 --- a/src/android/com/plugin/gcm/PushPlugin.java +++ b/src/android/com/plugin/gcm/PushPlugin.java @@ -23,6 +23,7 @@ public class PushPlugin extends CordovaPlugin { public static final String TAG = "PushPlugin"; public static final String REGISTER = "register"; + public static final String REGISTER_CATEGORIES = "registerUserNotificationSettings"; public static final String UNREGISTER = "unregister"; public static final String EXIT = "exit"; @@ -31,6 +32,7 @@ public class PushPlugin extends CordovaPlugin { private static String gSenderID; private static Bundle gCachedExtras = null; private static boolean gForeground = false; + public static JSONObject categories; /** * Gets the application context from cordova's main activity. @@ -40,6 +42,10 @@ private Context getApplicationContext() { return this.cordova.getActivity().getApplicationContext(); } + public static boolean isIntercomPush(Bundle extras) { + return extras.containsKey("receiver") && "intercom_sdk".equals(extras.getString("receiver")); + } + @Override public boolean execute(String action, JSONArray data, CallbackContext callbackContext) { @@ -78,13 +84,17 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo } } else if (UNREGISTER.equals(action)) { - GCMRegistrar.unregister(getApplicationContext()); Log.v(TAG, "UNREGISTER"); result = true; callbackContext.success(); - } else { + } else if(REGISTER_CATEGORIES.equals(action)) { + JSONObject fullSettings = data.optJSONObject(0); + this.categories = fullSettings.optJSONObject("categories"); + + result = true; + } else { result = false; Log.e(TAG, "Invalid action : " + action); callbackContext.error("Invalid action : " + action); diff --git a/src/ios/AppDelegate+notification.h b/src/ios/AppDelegate+notification.h index 6ca1797c..868ad631 100644 --- a/src/ios/AppDelegate+notification.h +++ b/src/ios/AppDelegate+notification.h @@ -15,6 +15,9 @@ - (void)applicationDidBecomeActive:(UIApplication *)application; - (id) getCommandInstance:(NSString*)className; +- (void)applicationPushPlugin:(UIApplication *) application handleActionWithIdentifier: (NSString *) identifier + forLocalNotification: (NSDictionary *) notification; + @property (nonatomic, retain) NSDictionary *launchNotification; @end diff --git a/src/ios/AppDelegate+notification.m b/src/ios/AppDelegate+notification.m index aa563a34..4c330058 100644 --- a/src/ios/AppDelegate+notification.m +++ b/src/ios/AppDelegate+notification.m @@ -10,6 +10,8 @@ #import "PushPlugin.h" #import +#import "Hurdlr-Swift.h" + static char launchNotificationKey; @implementation AppDelegate (notification) @@ -40,6 +42,16 @@ - (AppDelegate *)swizzled_init return [self swizzled_init]; } ++ (BOOL)isIntercomPushMessage:(NSDictionary *)userInfo { + //check if we contain the key icm_cid + return userInfo && [userInfo isKindOfClass:[NSDictionary class]] && userInfo[@"icm_cid"] != nil; +} + ++ (BOOL)isTrackerPushMessage:(NSDictionary *)userInfo { + //check if we contain the key icm_cid + return userInfo && [userInfo isKindOfClass:[NSDictionary class]] && userInfo[@"checkTracker"] != nil; +} + // This code will be called immediately after application:didFinishLaunchingWithOptions:. We need // to process notifications in cold-start situations - (void)createNotificationChecker:(NSNotification *)notification @@ -47,7 +59,7 @@ - (void)createNotificationChecker:(NSNotification *)notification if (notification) { NSDictionary *launchOptions = [notification userInfo]; - if (launchOptions) + if (launchOptions && ![[self class] isIntercomPushMessage:launchOptions]) self.launchNotification = [launchOptions objectForKey: @"UIApplicationLaunchOptionsRemoteNotificationKey"]; } } @@ -64,6 +76,10 @@ - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotif - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { NSLog(@"didReceiveNotification"); + + if ([[self class] isIntercomPushMessage:userInfo]) { + return; + } // Get application state for iOS4.x+ devices, otherwise assume active UIApplicationState appState = UIApplicationStateActive; @@ -98,6 +114,40 @@ - (void)applicationDidBecomeActive:(UIApplication *)application { } } +- (void)application:(UIApplication *) application handleActionWithIdentifier: (NSString *) identifier +forRemoteNotification: (NSDictionary *) notification + completionHandler: (void (^)()) completionHandler { + + PushPlugin *pushHandler = [self getCommandInstance:@"PushPlugin"]; + + NSMutableDictionary * userInfo = [notification mutableCopy]; + [userInfo setValue:identifier forKey:@"actionSelected"]; + pushHandler.notificationMessage = userInfo; + + [pushHandler performSelectorOnMainThread:@selector(notificationReceived) withObject:pushHandler waitUntilDone:NO]; + + // Must be called when finished + completionHandler(); +} + +- (void)applicationPushPlugin:(UIApplication *) application handleActionWithIdentifier: (NSString *) identifier + forLocalNotification: (NSDictionary *) notification + completionHandler: (void (^)()) completionHandler { + + PushPlugin *pushHandler = [self getCommandInstance:@"PushPlugin"]; + + NSMutableDictionary * userInfo = [[notification valueForKey:@"userInfo"] mutableCopy]; + [userInfo setValue:identifier forKey:@"actionSelected"]; + pushHandler.notificationMessage = userInfo; + + [pushHandler performSelectorOnMainThread:@selector(notificationReceived) withObject:pushHandler waitUntilDone:NO]; + + // Must be called when finished + completionHandler(); +} + + + // 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 diff --git a/src/ios/PushPlugin.h b/src/ios/PushPlugin.h index 7e7ba4bc..364bb631 100644 --- a/src/ios/PushPlugin.h +++ b/src/ios/PushPlugin.h @@ -33,7 +33,6 @@ BOOL isInline; NSString *notificationCallbackId; NSString *callback; - BOOL ready; } @@ -45,6 +44,9 @@ @property BOOL isInline; - (void)register:(CDVInvokedUrlCommand*)command; +- (void)registerUserNotificationSettings:(CDVInvokedUrlCommand*)command; + +- (void)areNotificationsEnabled:(CDVInvokedUrlCommand*)command; - (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken; - (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error; @@ -52,4 +54,5 @@ - (void)setNotificationMessage:(NSDictionary *)notification; - (void)notificationReceived; -@end ++ (NSDictionary*) getCategories; +@end \ No newline at end of file diff --git a/src/ios/PushPlugin.m b/src/ios/PushPlugin.m index 7686ae9d..d185720c 100644 --- a/src/ios/PushPlugin.m +++ b/src/ios/PushPlugin.m @@ -1,16 +1,16 @@ -/* + /* Copyright 2009-2011 Urban Airship Inc. All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + 2. Redistributions in binaryform must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided withthe distribution. - + THIS SOFTWARE IS PROVIDED BY THE URBAN AIRSHIP INC``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -24,6 +24,7 @@ */ #import "PushPlugin.h" +#import "Hurdlr-Swift.h" @implementation PushPlugin @@ -37,27 +38,164 @@ @implementation PushPlugin - (void)unregister:(CDVInvokedUrlCommand*)command; { - self.callbackId = command.callbackId; - + self.callbackId = command.callbackId; + [[UIApplication sharedApplication] unregisterForRemoteNotifications]; [self successWithMessage:@"unregistered"]; } -- (void)register:(CDVInvokedUrlCommand*)command; +- (void)areNotificationsEnabled:(CDVInvokedUrlCommand*)command; { - self.callbackId = command.callbackId; + self.callbackId = command.callbackId; + BOOL registered; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 + registered = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications]; +#else + UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes]; + registered = types != UIRemoteNotificationTypeNone; +#endif + CDVPluginResult *commandResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:registered]; + [self.commandDelegate sendPluginResult:commandResult callbackId:self.callbackId]; +} + +- (void)registerUserNotificationSettings:(CDVInvokedUrlCommand*)command; +{ + self.callbackId = command.callbackId; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 + NSDictionary *options = [command.arguments objectAtIndex:0]; + NSDictionary *categoryData = [PushPlugin getCategories]; - NSMutableDictionary* options = [command.arguments objectAtIndex:0]; + + for(id key in categoryData) { + NSMutableDictionary *c = [categoryData objectForKey:key]; + [c setObject:key forKey:@"identifier"]; + } + + NSArray *categories = [categoryData allValues]; + + if (categories == nil) { + [self failWithMessage:@"No categories specified" withError:nil]; + return; + } + NSMutableArray *nsCategories = [[NSMutableArray alloc] initWithCapacity:[categories count]]; + + for (NSDictionary *category in categories) { + // ** 1. create the actions for this category + NSMutableArray *nsActionsForDefaultContext = [[NSMutableArray alloc] initWithCapacity:4]; + NSArray *actionsForDefaultContext = [category objectForKey:@"actions"]; + if (actionsForDefaultContext == nil) { + [self failWithMessage:@"Category doesn't contain actionsForDefaultContext" withError:nil]; + return; + } + if (![self createNotificationAction:category actions:actionsForDefaultContext nsActions:nsActionsForDefaultContext]) { + return; + } + + NSMutableArray *nsActionsForMinimalContext = [[NSMutableArray alloc] initWithCapacity:2]; + NSArray *actionsForMinimalContext = [category objectForKey:@"actions"]; + if (actionsForMinimalContext == nil) { + [self failWithMessage:@"Category doesn't contain actionsForMinimalContext" withError:nil]; + return; + } + if (![self createNotificationAction:category actions:actionsForMinimalContext nsActions:nsActionsForMinimalContext]) { + return; + } + + // ** 2. create the category + UIMutableUserNotificationCategory *nsCategory = [[UIMutableUserNotificationCategory alloc] init]; + // Identifier to include in your push payload and local notification + NSString *identifier = [category objectForKey:@"identifier"]; + if (identifier == nil) { + [self failWithMessage:@"Category doesn't contain identifier" withError:nil]; + return; + } + nsCategory.identifier = identifier; + // Add the actions to the category and set the action context + [nsCategory setActions:nsActionsForDefaultContext forContext:UIUserNotificationActionContextDefault]; + // Set the actions to present in a minimal context + [nsCategory setActions:nsActionsForMinimalContext forContext:UIUserNotificationActionContextMinimal]; + [nsCategories addObject:nsCategory]; + } + + // ** 3. Determine the notification types + NSArray *types = [options objectForKey:@"types"]; + if (types == nil) { + [self failWithMessage:@"No types specified" withError:nil]; + return; + } + UIUserNotificationType nsTypes = UIUserNotificationTypeNone; + for (NSString *type in types) { + if ([type isEqualToString:@"badge"]) { + nsTypes |= UIUserNotificationTypeBadge; + } else if ([type isEqualToString:@"alert"]) { + nsTypes |= UIUserNotificationTypeAlert; + } else if ([type isEqualToString:@"sound"]) { + nsTypes |= UIUserNotificationTypeSound; + } else { + [self failWithMessage:[NSString stringWithFormat:@"Unsupported type: %@, use one of badge, alert, sound", type] withError:nil]; + } + } + + // ** 4. Register the notification categories + NSSet *nsCategorySet = [NSSet setWithArray:nsCategories]; + UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:nsTypes categories:nsCategorySet]; + [TraxNotificationManager registerUserNotificationSettings:settings]; +#endif + [self successWithMessage:[NSString stringWithFormat:@"%@", @"user notifications registered"]]; +} + +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 +- (BOOL)createNotificationAction:(NSDictionary *)category + actions:(NSArray *) actions + nsActions:(NSMutableArray *)nsActions +{ + for (NSDictionary *action in actions) { + UIMutableUserNotificationAction *nsAction = [[UIMutableUserNotificationAction alloc] init]; + // Define an ID string to be passed back to your app when you handle the action + NSString *identifier = [action objectForKey:@"identifier"]; + if (identifier == nil) { + [self failWithMessage:@"Action doesn't contain identifier" withError:nil]; + return NO; + } + nsAction.identifier = identifier; + // Localized text displayed in the action button + NSString *title = [action objectForKey:@"title"]; + if (title == nil) { + [self failWithMessage:@"Action doesn't contain title" withError:nil]; + return NO; + } + nsAction.title = title; + // If you need to show UI, choose foreground (background gives your app a few seconds to run) + BOOL isForeground = [@"foreground" isEqualToString:[action objectForKey:@"activationMode"]]; + nsAction.activationMode = isForeground ? UIUserNotificationActivationModeForeground : UIUserNotificationActivationModeBackground; + // Destructive actions display in red + BOOL isDestructive = [[action objectForKey:@"destructive"] isEqual:[NSNumber numberWithBool:YES]]; + nsAction.destructive = isDestructive; + // Set whether the action requires the user to authenticate + BOOL isAuthRequired = [[action objectForKey:@"authenticationRequired"] isEqual:[NSNumber numberWithBool:YES]]; + nsAction.authenticationRequired = isAuthRequired; + [nsActions addObject:nsAction]; + } + return YES; +} +#endif + +- (void)register:(CDVInvokedUrlCommand*)command; +{ + self.callbackId = command.callbackId; + + NSMutableDictionary* options = [command.arguments objectAtIndex:0]; + #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 - UIUserNotificationType UserNotificationTypes = UIUserNotificationTypeNone; + UIUserNotificationType UserNotificationTypes = UIUserNotificationTypeNone; #endif UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeNone; - + id badgeArg = [options objectForKey:@"badge"]; id soundArg = [options objectForKey:@"sound"]; id alertArg = [options objectForKey:@"alert"]; - + if ([badgeArg isKindOfClass:[NSString class]]) { if ([badgeArg isEqualToString:@"true"]) { @@ -73,7 +211,7 @@ - (void)register:(CDVInvokedUrlCommand*)command; UserNotificationTypes |= UIUserNotificationTypeBadge; #endif } - + if ([soundArg isKindOfClass:[NSString class]]) { if ([soundArg isEqualToString:@"true"]) { @@ -81,7 +219,7 @@ - (void)register:(CDVInvokedUrlCommand*)command; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 UserNotificationTypes |= UIUserNotificationTypeSound; #endif - } + } } else if ([soundArg boolValue]) { notificationTypes |= UIRemoteNotificationTypeSound; @@ -89,7 +227,7 @@ - (void)register:(CDVInvokedUrlCommand*)command; UserNotificationTypes |= UIUserNotificationTypeSound; #endif } - + if ([alertArg isKindOfClass:[NSString class]]) { if ([alertArg isEqualToString:@"true"]) { @@ -97,7 +235,7 @@ - (void)register:(CDVInvokedUrlCommand*)command; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 UserNotificationTypes |= UIUserNotificationTypeAlert; #endif - } + } } else if ([alertArg boolValue]) { notificationTypes |= UIRemoteNotificationTypeAlert; @@ -105,121 +243,126 @@ - (void)register:(CDVInvokedUrlCommand*)command; UserNotificationTypes |= UIUserNotificationTypeAlert; #endif } - + notificationTypes |= UIRemoteNotificationTypeNewsstandContentAvailability; -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 - UserNotificationTypes |= UIUserNotificationActivationModeBackground; -#endif - + //#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 + // UserNotificationTypes |= UIUserNotificationActivationModeBackground; + //#endif + self.callback = [options objectForKey:@"ecb"]; - + if (notificationTypes == UIRemoteNotificationTypeNone) NSLog(@"PushPlugin.register: Push notification type is set to none"); - + isInline = NO; - + #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 if ([[UIApplication sharedApplication]respondsToSelector:@selector(registerUserNotificationSettings:)]) { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UserNotificationTypes categories:nil]; - [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; + [TraxNotificationManager registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } else { - [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes]; + [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes]; } #else - [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes]; + [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes]; #endif - - if (notificationMessage) // if there is a pending startup notification - [self notificationReceived]; // go ahead and process it + + if (notificationMessage) // if there is a pending startup notification + [self notificationReceived]; // go ahead and process it } /* -- (void)isEnabled:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)options { - UIRemoteNotificationType type = [[UIApplication sharedApplication] enabledRemoteNotificationTypes]; - NSString *jsStatement = [NSString stringWithFormat:@"navigator.PushPlugin.isEnabled = %d;", type != UIRemoteNotificationTypeNone]; - NSLog(@"JSStatement %@",jsStatement); -} -*/ + - (void)isEnabled:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)options { + UIRemoteNotificationType type = [[UIApplication sharedApplication] enabledRemoteNotificationTypes]; + NSString *jsStatement = [NSString stringWithFormat:@"navigator.PushPlugin.isEnabled = %d;", type != UIRemoteNotificationTypeNone]; + NSLog(@"JSStatement %@",jsStatement); + } + */ - (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { - + NSMutableDictionary *results = [NSMutableDictionary dictionary]; NSString *token = [[[[deviceToken description] stringByReplacingOccurrencesOfString:@"<"withString:@""] stringByReplacingOccurrencesOfString:@">" withString:@""] stringByReplacingOccurrencesOfString: @" " withString: @""]; [results setValue:token forKey:@"deviceToken"]; - - #if !TARGET_IPHONE_SIMULATOR - // Get Bundle Info for Remote Registration (handy if you have more than one app) - [results setValue:[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"] forKey:@"appName"]; - [results setValue:[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] forKey:@"appVersion"]; - - // Check what Notifications the user has turned on. We registered for all three, but they may have manually disabled some or all of them. - NSUInteger rntypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes]; - - // Set the defaults to disabled unless we find otherwise... - NSString *pushBadge = @"disabled"; - NSString *pushAlert = @"disabled"; - NSString *pushSound = @"disabled"; - - // Check what Registered Types are turned on. This is a bit tricky since if two are enabled, and one is off, it will return a number 2... not telling you which - // one is actually disabled. So we are literally checking to see if rnTypes matches what is turned on, instead of by number. The "tricky" part is that the - // single notification types will only match if they are the ONLY one enabled. Likewise, when we are checking for a pair of notifications, it will only be - // true if those two notifications are on. This is why the code is written this way - if(rntypes & UIRemoteNotificationTypeBadge){ - pushBadge = @"enabled"; - } - if(rntypes & UIRemoteNotificationTypeAlert) { - pushAlert = @"enabled"; - } - if(rntypes & UIRemoteNotificationTypeSound) { - pushSound = @"enabled"; - } - - [results setValue:pushBadge forKey:@"pushBadge"]; - [results setValue:pushAlert forKey:@"pushAlert"]; - [results setValue:pushSound forKey:@"pushSound"]; - - // Get the users Device Model, Display Name, Token & Version Number - UIDevice *dev = [UIDevice currentDevice]; - [results setValue:dev.name forKey:@"deviceName"]; - [results setValue:dev.model forKey:@"deviceModel"]; - [results setValue:dev.systemVersion forKey:@"deviceSystemVersion"]; - - [self successWithMessage:[NSString stringWithFormat:@"%@", token]]; - #endif + +#if !TARGET_IPHONE_SIMULATOR + // Get Bundle Info for Remote Registration (handy if you have more than one app) + [results setValue:[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"] forKey:@"appName"]; + [results setValue:[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] forKey:@"appVersion"]; + + // Check what Notifications the user has turned on. We registered for all three, but they may have manually disabled some or all of them. + NSUInteger rntypes; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 + rntypes = [[[UIApplication sharedApplication] currentUserNotificationSettings] types]; +#else + rntypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes]; +#endif + + // Set the defaults to disabled unless we find otherwise... + NSString *pushBadge = @"disabled"; + NSString *pushAlert = @"disabled"; + NSString *pushSound = @"disabled"; + + // Check what Registered Types are turned on. This is a bit tricky since if two are enabled, and one is off, it will return a number 2... not telling you which + // one is actually disabled. So we are literally checking to see if rnTypes matches what is turned on, instead of by number. The "tricky" part is that the + // single notification types will only match if they are the ONLY one enabled. Likewise, when we are checking for a pair of notifications, it will only be + // true if those two notifications are on. This is why the code is written this way + if(rntypes & UIRemoteNotificationTypeBadge){ + pushBadge = @"enabled"; + } + if(rntypes & UIRemoteNotificationTypeAlert) { + pushAlert = @"enabled"; + } + if(rntypes & UIRemoteNotificationTypeSound) { + pushSound = @"enabled"; + } + + [results setValue:pushBadge forKey:@"pushBadge"]; + [results setValue:pushAlert forKey:@"pushAlert"]; + [results setValue:pushSound forKey:@"pushSound"]; + + // Get the users Device Model, Display Name, Token & Version Number + UIDevice *dev = [UIDevice currentDevice]; + [results setValue:dev.name forKey:@"deviceName"]; + [results setValue:dev.model forKey:@"deviceModel"]; + [results setValue:dev.systemVersion forKey:@"deviceSystemVersion"]; + + [self successWithMessage:[NSString stringWithFormat:@"%@", token]]; +#endif } - (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { - [self failWithMessage:@"" withError:error]; + [self failWithMessage:@"" withError:error]; } - (void)notificationReceived { NSLog(@"Notification received"); - + if (notificationMessage && self.callback) { NSMutableString *jsonStr = [NSMutableString stringWithString:@"{"]; - + [self parseDictionary:notificationMessage intoJSON:jsonStr]; - + if (isInline) { [jsonStr appendFormat:@"foreground:\"%d\"", 1]; isInline = NO; } - else + else [jsonStr appendFormat:@"foreground:\"%d\"", 0]; - + [jsonStr appendString:@"}"]; - + NSLog(@"Msg: %@", jsonStr); - + NSString * jsCallBack = [NSString stringWithFormat:@"%@(%@);", self.callback, jsonStr]; [self.webView stringByEvaluatingJavaScriptFromString:jsCallBack]; - + self.notificationMessage = nil; } } @@ -229,20 +372,20 @@ -(void)parseDictionary:(NSDictionary *)inDictionary intoJSON:(NSMutableString *) { NSArray *keys = [inDictionary allKeys]; NSString *key; - + for (key in keys) { id thisObject = [inDictionary objectForKey:key]; - + if ([thisObject isKindOfClass:[NSDictionary class]]) [self parseDictionary:thisObject intoJSON:jsonString]; else if ([thisObject isKindOfClass:[NSString class]]) - [jsonString appendFormat:@"\"%@\":\"%@\",", - key, - [[[[inDictionary objectForKey:key] + [jsonString appendFormat:@"\"%@\":\"%@\",", + key, + [[[[inDictionary objectForKey:key] stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"] - stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""] - stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]]; + stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""] + stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]]; else { [jsonString appendFormat:@"\"%@\":\"%@\",", key, [inDictionary objectForKey:key]]; } @@ -250,14 +393,14 @@ -(void)parseDictionary:(NSDictionary *)inDictionary intoJSON:(NSMutableString *) } - (void)setApplicationIconBadgeNumber:(CDVInvokedUrlCommand *)command { - + self.callbackId = command.callbackId; - + NSMutableDictionary* options = [command.arguments objectAtIndex:0]; int badge = [[options objectForKey:@"badge"] intValue] ?: 0; - + [[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge]; - + [self successWithMessage:[NSString stringWithFormat:@"app badge count set to %d", badge]]; } -(void)successWithMessage:(NSString *)message @@ -273,8 +416,68 @@ -(void)failWithMessage:(NSString *)message withError:(NSError *)error { NSString *errorMessage = (error) ? [NSString stringWithFormat:@"%@ - %@", message, [error localizedDescription]] : message; CDVPluginResult *commandResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:errorMessage]; - + [self.commandDelegate sendPluginResult:commandResult callbackId:self.callbackId]; } -@end ++(NSMutableDictionary*) getCategories +{ + NSMutableDictionary *read = [NSMutableDictionary dictionaryWithDictionary: @{ + @"identifier": @"READ", + @"title": @"Read", + @"activationMode": @"foreground", + @"destructive": @(false), + @"authenticationRequired": @(true) + }]; + + NSMutableDictionary *ignore = [NSMutableDictionary dictionaryWithDictionary: @{ + @"identifier": @"IGNORE", + @"title": @"Ignore", + @"activationMode": @"foreground", + @"destructive": @(false), + @"authenticationRequired": @(false) + }]; + + NSMutableDictionary *delete = [NSMutableDictionary dictionaryWithDictionary: @{ + @"identifier": @"DELETE", + @"title": @"Delete", + @"activationMode": @"background", + @"destructive": @(true), + @"authenticationRequired": @(true) + }]; + + NSMutableDictionary *postRetry = [NSMutableDictionary dictionaryWithDictionary: @{ + @"identifier": @"POST_RETRY", + @"title": @"RETRY", + @"activationMode": @"background", + @"destructive": @(false), + @"authenticationRequired": @(true) + }]; + + NSMutableDictionary *postCancel = [NSMutableDictionary dictionaryWithDictionary: @{ + @"identifier": @"POST_CANCEL", + @"title": @"CANCEL", + @"activationMode": @"background", + @"destructive": @(false), + @"authenticationRequired": @(true) + }]; + + NSMutableArray *readIgnoreArr = [NSMutableArray arrayWithArray: @[read, ignore]]; + NSMutableDictionary *readIgnore = [NSMutableDictionary dictionaryWithDictionary: @{ @"actions": readIgnoreArr }]; + + NSMutableArray *readDeleteArr = [NSMutableArray arrayWithArray: @[read, delete]]; + NSMutableDictionary *readDelete = [NSMutableDictionary dictionaryWithDictionary: @{ @"actions": readDeleteArr }]; + + NSMutableArray *postRetryCancelArr = [NSMutableArray arrayWithArray: @[postRetry, postCancel]]; + NSDictionary *postRetryCancel = [NSMutableDictionary dictionaryWithDictionary: @{ @"actions": postRetryCancelArr }]; + + NSMutableDictionary *categories = [NSMutableDictionary dictionaryWithDictionary: @{ + @"READ_IGNORE": readIgnore, + @"READ_DELETE": readDelete, + @"POST_RETRY_CANCEL": postRetryCancel + }]; + + return categories; +} + +@end \ No newline at end of file diff --git a/www/PushNotification.js b/www/PushNotification.js index 6127cf56..aaa75260 100644 --- a/www/PushNotification.js +++ b/www/PushNotification.js @@ -19,15 +19,33 @@ PushNotification.prototype.register = function(successCallback, errorCallback, o cordova.exec(successCallback, errorCallback, "PushPlugin", "register", [options]); }; -// Call this to unregister for push notifications -PushNotification.prototype.unregister = function(successCallback, errorCallback, options) { +PushNotification.prototype.UserNotificationTypes = { + Badge : "badge", + Alert : "alert", + Sound : "sound" +}; + +PushNotification.prototype.UserNotificationActivationMode = { + Foreground : "foreground", + Background : "background" +}; + +PushNotification.prototype.registerUserNotificationSettings = function(successCallback, errorCallback, options) { if (errorCallback == null) { errorCallback = function() {}} - if (typeof errorCallback != "function") { - console.log("PushNotification.unregister failure: failure parameter not a function"); + if (typeof successCallback != "function") { + console.log("PushNotification.registerUserNotificationSettings failure: success callback parameter must be a function"); return } + cordova.exec(successCallback, errorCallback, "PushPlugin", "registerUserNotificationSettings", [options]); +}; + + +// Call this to unregister for push notifications +PushNotification.prototype.unregister = function(successCallback, errorCallback, options) { + errorCallback = errorCallback || function () {} + if (typeof successCallback != "function") { console.log("PushNotification.unregister failure: success callback parameter must be a function"); return @@ -36,17 +54,35 @@ PushNotification.prototype.unregister = function(successCallback, errorCallback, cordova.exec(successCallback, errorCallback, "PushPlugin", "unregister", [options]); }; - // Call this if you want to show toast notification on WP8 - PushNotification.prototype.showToastNotification = function (successCallback, errorCallback, options) { - if (errorCallback == null) { errorCallback = function () { } } +// Check to see if we've already registered +PushNotification.prototype.areNotificationsEnabled = function(successCallback, errorCallback, options) { + if (errorCallback == null) { errorCallback = function() {}} - if (typeof errorCallback != "function") { - console.log("PushNotification.register failure: failure parameter not a function"); - return - } + if (typeof errorCallback != "function") { + console.log("PushNotification.areNotificationsEnabled failure: failure parameter not a function"); + return + } - cordova.exec(successCallback, errorCallback, "PushPlugin", "showToastNotification", [options]); + if (typeof successCallback != "function") { + console.log("PushNotification.areNotificationsEnabled failure: success callback parameter must be a function"); + return } + + cordova.exec(successCallback, errorCallback, "PushPlugin", "areNotificationsEnabled", [options]); +}; + +// Call this if you want to show toast notification on WP8 +PushNotification.prototype.showToastNotification = function (successCallback, errorCallback, options) { + if (errorCallback == null) { errorCallback = function () { } } + + if (typeof errorCallback != "function") { + console.log("PushNotification.register failure: failure parameter not a function"); + return + } + + cordova.exec(successCallback, errorCallback, "PushPlugin", "showToastNotification", [options]); +}; + // Call this to set the application icon badge PushNotification.prototype.setApplicationIconBadgeNumber = function(successCallback, errorCallback, badge) { if (errorCallback == null) { errorCallback = function() {}} @@ -75,4 +111,4 @@ if (!window.plugins.pushNotification) { if (typeof module != 'undefined' && module.exports) { module.exports = PushNotification; -} \ No newline at end of file +}