From a1ce16d16792933b17016c36ef833278a835615e Mon Sep 17 00:00:00 2001 From: Shivang Date: Thu, 6 Sep 2018 17:36:00 +0530 Subject: [PATCH 1/3] feat: Actionable Notifications --- docs/ADVANCED.md | 104 ++++++++++++++++++++++++++++++++++++ lib/common/notifications.js | 5 +- lib/server/push.api.js | 5 ++ 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/docs/ADVANCED.md b/docs/ADVANCED.md index cfee484..2cf587a 100644 --- a/docs/ADVANCED.md +++ b/docs/ADVANCED.md @@ -323,3 +323,107 @@ When a client calls send on Push, the Push's allow and deny callbacks are called } }); ``` + +## Action Buttons + +Your notification can include a maximum of three action buttons. You register the event callback name for each of your actions, then when a user clicks on one of notification's buttons, the event corresponding to that button is fired and the listener you have registered is invoked. For instance, here is a setup with two actions `emailGuests` and `snooze`. + +```javascript +const push = PushNotification.init({ + android: {} +}); + +// data contains the push payload just like a notification event +push.on('emailGuests', data => { + console.log('I should email my guests'); +}); + +push.on('snooze', data => { + console.log('Remind me later'); +}); +``` + +If you wish to include an icon along with the button name, they must be placed in the `res/drawable` directory of your Android project. Then you can send the following JSON from FCM: + +```json +{ + "registration_ids": ["my device id"], + "data": { + "title": "AUX Scrum", + "message": "Scrum: Daily touchbase @ 10am Please be on time so we can cover everything on the agenda.", + "actions": [ + { + "icon": "emailGuests", + "title": "EMAIL GUESTS", + "callback": "emailGuests", + "foreground": true + }, + { + "icon": "snooze", + "title": "SNOOZE", + "callback": "snooze", + "foreground": false + } + ] + } +} + +This will produce the following notification in your tray: + +![action_combo](https://cloud.githubusercontent.com/assets/353180/9313435/02554d2a-44f1-11e5-8cd9-0aadd1e02b18.png) + +If your user clicks on the main body of the notification, then your app will be opened. However, if they click on either of the action buttons the app will open (or start) and the specified event will be triggered with the callback name. In this case it is `emailGuests` and `snooze`, respectively. If you set the `foreground` property to `true`, the app will be brought to the front, if `foreground` is `false` then the callback is run without the app being brought to the foreground. + +#### Actionable Notification for IOS + +You must setup the possible actions when you initialize the plugin: +```javascript +var categories = { + "snoozeRule": { + "yes": { + "callback": "Notification.snoozeAction6Hour", + "title": "6 Hours", + "foreground": false, + "destructive": false + }, + "no": { + "callback": "Notification.snoozeAction1Day", + "title": "1 Day", + "foreground": false, + "destructive": false + }, + "maybe": { + "callback": "Notification.closeAlert", + "title": "Cancel", + "foreground": false, + "destructive": false + } + }, + "delete": { + "yes": { + "callback": "Notification.delete", + "title": "Delete", + "foreground": true, + "destructive": false + }, + "no": { + "callback": "Notification.closeAlert", + "title": "Cancel", + "foreground": true, + "destructive": false + } + } +}; + +Push.Configure({ + ios: { + alert: true, + badge: true, + sound: true, + clearBadge: true, + categories: categories + } + }); +``` + +Each category is a named object, snoozeRule and delete in this case. These names will need to match the ones you send via your payload to APNS if you want the action buttons to be displayed. Each category can have up to three buttons which must be labeled yes, no and maybe (This is strict, it will not work if you label them anything other than this). In turn each of these buttons has four properties, callback the javascript function you want to call, title the label for the button, foreground whether or not to bring your app to the foreground and destructive which doesn’t actually do anything destructive, it just colors the button red as a warning to the user that the action may be destructive. diff --git a/lib/common/notifications.js b/lib/common/notifications.js index 3851022..233f505 100644 --- a/lib/common/notifications.js +++ b/lib/common/notifications.js @@ -38,7 +38,8 @@ var _validateDocument = function(notification) { picture: Match.Optional(String), badge: Match.Optional(Match.Integer), sound: Match.Optional(String), - notId: Match.Optional(Match.Integer) + notId: Match.Optional(Match.Integer), + actions: Match.Optional([Match.Any]) }), query: Match.Optional(String), token: Match.Optional(_matchToken), @@ -82,7 +83,7 @@ Push.send = function(options) { } if (Match.test(options.gcm, Object)) { - notification.gcm = _.pick(options.gcm, 'image', 'style', 'summaryText', 'picture', 'from', 'title', 'text', 'badge', 'sound', 'notId'); + notification.gcm = _.pick(options.gcm, 'image', 'style', 'summaryText', 'picture', 'from', 'title', 'text', 'badge', 'sound', 'notId', 'actions'); } // Set one token selector, this can be token, array of tokens or query diff --git a/lib/server/push.api.js b/lib/server/push.api.js index 5f901d4..27476a4 100644 --- a/lib/server/push.api.js +++ b/lib/server/push.api.js @@ -334,6 +334,11 @@ Push.Configure = function(options) { data.picture = notification.picture; } + //Action Buttons + if(typeof notification.actions !== 'undefined') { + data.actions = notification.actions; + } + //var message = new gcm.Message(); var message = new gcm.Message({ collapseKey: notification.from, From 6dc8907ffe2ba635d0ae37667c0e204d424b48f8 Mon Sep 17 00:00:00 2001 From: Shivang Kar Date: Thu, 6 Sep 2018 18:04:02 +0530 Subject: [PATCH 2/3] Update ADVANCED.md --- docs/ADVANCED.md | 79 +++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/docs/ADVANCED.md b/docs/ADVANCED.md index 2cf587a..150e21a 100644 --- a/docs/ADVANCED.md +++ b/docs/ADVANCED.md @@ -326,48 +326,57 @@ When a client calls send on Push, the Push's allow and deny callbacks are called ## Action Buttons -Your notification can include a maximum of three action buttons. You register the event callback name for each of your actions, then when a user clicks on one of notification's buttons, the event corresponding to that button is fired and the listener you have registered is invoked. For instance, here is a setup with two actions `emailGuests` and `snooze`. +Your notification can include a maximum of three action buttons. You register the event callback name for each of your actions, then when a user clicks on one of notification's buttons, the event corresponding to that button is fired and the listener you have registered is invoked. For instance, here is a setup with three actions `snoozeAction6Hour` `snoozeAction1Day` and `closeAlert`. ```javascript -const push = PushNotification.init({ - android: {} -}); +window.Notification = {}; // data contains the push payload just like a notification event -push.on('emailGuests', data => { - console.log('I should email my guests'); -}); +Notification.snoozeAction6Hour = function(data) { + data.additionalData.snoozeHours = 6; + Meteor.call('snoozeRuleAlerts', data, function() {}); +}; -push.on('snooze', data => { - console.log('Remind me later'); -}); +Notification.snoozeAction1Day = function(data) { + data.additionalData.snoozeHours = 24; + Meteor.call('snoozeRuleAlerts', data, function() {}); +}; + +//closing function for alert +Notification.closeAlert = function() {}; ``` If you wish to include an icon along with the button name, they must be placed in the `res/drawable` directory of your Android project. Then you can send the following JSON from FCM: ```json { - "registration_ids": ["my device id"], - "data": { - "title": "AUX Scrum", - "message": "Scrum: Daily touchbase @ 10am Please be on time so we can cover everything on the agenda.", - "actions": [ - { - "icon": "emailGuests", - "title": "EMAIL GUESTS", - "callback": "emailGuests", - "foreground": true - }, - { - "icon": "snooze", - "title": "SNOOZE", - "callback": "snooze", - "foreground": false - } - ] - } + "title": "Snooze Notification", + "message": "Snooze your daily requirement alerts for a specific amount of time.", + "query": { + userId: { $in: recipients } + }, + "actions": [ + { + "icon": "halfDay", + "title": "6 hours", + "callback": "Notification.snoozeAction6Hour", + "foreground": true + }, + { + "icon": "oneDay", + "title": "1 Day", + "callback": "Notification.snoozeAction1Day", + "foreground": true + }, + { + "icon": "discard", + "title": "Cancel", + "callback": "Notification.closeAlert", + "foreground": false + } + ] } - +``` This will produce the following notification in your tray: ![action_combo](https://cloud.githubusercontent.com/assets/353180/9313435/02554d2a-44f1-11e5-8cd9-0aadd1e02b18.png) @@ -417,11 +426,11 @@ var categories = { Push.Configure({ ios: { - alert: true, - badge: true, - sound: true, - clearBadge: true, - categories: categories + "alert": true, + "badge": true, + "sound": true, + "clearBadge": true, + "categories": categories } }); ``` From 3bd5614c0aa63a67dd7b53deb752077bccee14ab Mon Sep 17 00:00:00 2001 From: Shivang Kar Date: Thu, 6 Sep 2018 18:08:26 +0530 Subject: [PATCH 3/3] Update ADVANCED.md --- docs/ADVANCED.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ADVANCED.md b/docs/ADVANCED.md index 150e21a..4a07650 100644 --- a/docs/ADVANCED.md +++ b/docs/ADVANCED.md @@ -346,14 +346,14 @@ Notification.snoozeAction1Day = function(data) { Notification.closeAlert = function() {}; ``` -If you wish to include an icon along with the button name, they must be placed in the `res/drawable` directory of your Android project. Then you can send the following JSON from FCM: +If you wish to include an icon along with the button name, they must be placed in the `res/drawable` directory of your Android project. Then you can send the following JSON from GCM/FCM: ```json { "title": "Snooze Notification", "message": "Snooze your daily requirement alerts for a specific amount of time.", "query": { - userId: { $in: recipients } + "userId": 123456789 }, "actions": [ {