Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supports sending hide notification background pushes, small cleanups #470

Merged
merged 4 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 57 additions & 48 deletions notificationsender/firebase.js
Original file line number Diff line number Diff line change
@@ -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());
Expand All @@ -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) {
Expand All @@ -93,6 +103,5 @@ exports.hideNotification = function (registrationIds, notificationId) {
priority: 'high',
}
};

sendMessage(message, data);
};
3 changes: 2 additions & 1 deletion notificationsender/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion routes/devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down