diff --git a/notificationsender/firebase.js b/notificationsender/firebase.js index ba4fa7e..a7663ef 100644 --- a/notificationsender/firebase.js +++ b/notificationsender/firebase.js @@ -1,8 +1,7 @@ const system = require('../system'); const firebase = require('firebase-admin'); const logger = require('../logger.js'); -const redis = require('../redis-helper'); -const crypto = require("crypto") +const crypto = require("crypto"); if (system.isGcmConfigured()) { const serviceAccount = require(system.getFirebaseServiceFile()); @@ -22,62 +21,73 @@ function sendMessage(message) { }; exports.sendFCMNotification = function (registrationIds, notification) { - // We can safely remove androidNotificationId, our android client has removed the need for this, but i need to double check - redis.incr("androidNotificationId", function (error, androidNotificationId) { - if (error) { - return; - } - const data = notification.payload; + let data = notification.payload; - //for IOS we need to set an actual notification payload so they show up when the app is not running - //we can remove badge/sound/alert after our IOS app dynamically adds these - const apns = { - payload: { - aps: { - 'mutable-content': 1, // Enables mutable content for iOS - badge: 0, - sound: { name: 'default' }, - alert: { body: data.message }, - } - } - } + const apns = { + payload: { + aps: {} + }, + headers: {} + } - const android = { - priority: 'high', + const android = { + priority: 'high', + } + + // make sure all our values are strings per FCM requirements + Object.keys(data).forEach(key => { + const value = data[key]; + if(value === undefined){ + delete data[key] + } else if (typeof value !== 'string') { + data[key] = JSON.stringify(value) } + }) - const updatedData = { - type: 'notification', - severity: notification.severity || '', - icon: notification.icon || '', - persistedId: notification._id.toString(), - timestamp: notification.created.getTime().toString(), - notificationId: androidNotificationId.toString() - }; + data.type = data.type || 'notification' // default to sending notifications - Object.assign(data, updatedData) + // this a silent/background notification + if (data.type === "hideNotification") { + // required for silent notifications on IOS + apns.payload.aps["content-available"] = 1 + apns.headers["apns-priority"] = "5" + } else { + // Normal notification + data.persistedId = notification._id.toString() + data.timestamp = notification.created.getTime().toString() - if (data.actions) { - if (data.actions instanceof Array) { - data.actions = JSON.stringify(data.actions) - } - // for apple, create a unique hash for the category, secret sauce for dynamic actions - apns.payload.aps.category = crypto.createHash('sha256').update(data.actions).digest('hex'); + // Setting title and body is really only necessary for the legacy IOS app (V1) + // The non-legacy app will set these from the payload data before surfacing the notification + apns.payload.aps = { + 'mutable-content': 1, // allows for background processing - required + title: data.title, + badge: 0, + alert: { body: data.message }, + sound: { name: 'default' } } - if(data.title){ - apns.payload.aps.alert.title = data.title + //set the user supplied id for the collapse header so notifications can be replaced with new ones + const refId = data["reference-id"] + if (refId) { + apns.headers["apns-collapse-id"] = refId; + android.collapseKey = refId; } - const message = { - android: android, - apns: apns, - data: data, - tokens: Array.isArray(registrationIds) ? registrationIds : [registrationIds], - }; + if (data.actions) { + // for apple, create a unique hash for the category, secret sauce for dynamic actions + apns.payload.aps.category = crypto.createHash('sha256').update(data.actions).digest('hex'); + } + } - sendMessage(message); - }); + const message = { + android: android, + apns: apns, + data: data, + tokens: Array.isArray(registrationIds) ? registrationIds : [registrationIds] + }; + console.info("sending message", message) + //console.info("sending message", JSON.stringify(message, null, 2)) + sendMessage(message); }; exports.hideNotification = function (registrationIds, notificationId) { @@ -93,6 +103,5 @@ exports.hideNotification = function (registrationIds, notificationId) { priority: 'high', } }; - sendMessage(message, data); }; diff --git a/notificationsender/index.js b/notificationsender/index.js index c6fc079..e2dedd9 100644 --- a/notificationsender/index.js +++ b/notificationsender/index.js @@ -18,11 +18,12 @@ function sendNotification(userId, data) { var fcmRegistrations = []; var iosDeviceTokens = []; + data.tag = data.tag || data.severity // tag is replacing severity in OH 4.2 var newNotification = new Notification({ user: userId, message: data.message, icon: data.icon, - severity: data.severity, + severity: data.tag, //legacy field payload: data }); newNotification.save(function (error) { diff --git a/routes/devices.js b/routes/devices.js index 246f282..dec870b 100644 --- a/routes/devices.js +++ b/routes/devices.js @@ -53,7 +53,8 @@ exports.devicessendmessage = function (req, res) { const message = req.form.messagetext; const newNotification = new Notification({ user: req.user.id, - message: message + message: message, + payload: {message : message} }); newNotification.save(function (error) { if (error) {