diff --git a/keyserver/src/push/send.js b/keyserver/src/push/send.js --- a/keyserver/src/push/send.js +++ b/keyserver/src/push/send.js @@ -45,6 +45,7 @@ fcmPush, getUnreadCounts, apnMaxNotificationPayloadByteSize, + fcmMaxNotificationPayloadByteSize, } from './utils'; type Device = { @@ -530,33 +531,41 @@ allMessageInfos, threadInfo, ); - const messageInfos = JSON.stringify(newRawMessageInfos); - - if (badgeOnly && codeVersion < 69) { - // Older Android clients don't look at badgeOnly, so if we sent them the - // full payload they would treat it as a normal notif. Instead we will - // send them this payload that is missing an ID, which will prevent the - // system notif from being generated, but still allow for in-app notifs - // and badge updating. - return { - data: { - badge: unreadCount.toString(), - ...rest, - threadID: threadInfo.id, - messageInfos, - }, - }; - } - return { + const notification = { data: { badge: unreadCount.toString(), ...rest, - id: notifID, threadID: threadInfo.id, - messageInfos, - badgeOnly: badgeOnly ? '1' : '0', }, }; + + // The reason we only include `badgeOnly` for newer clients is because older + // clients don't know how to parse it. The reason we only include `id` for + // newer clients is that if the older clients see that field, they assume + // the notif has a full payload, and then crash when trying to parse it. + // By skipping `id` we allow old clients to still handle in-app notifs and + // badge updating. + if (!badgeOnly || codeVersion >= 69) { + notification.data = { + ...notification.data, + id: notifID, + badgeOnly: badgeOnly ? '1' : '0', + }; + } + + const messageInfos = JSON.stringify(newRawMessageInfos); + const copyWithMessageInfos = { + ...notification, + data: { ...notification.data, messageInfos }, + }; + + if ( + Buffer.byteLength(JSON.stringify(copyWithMessageInfos)) <= + fcmMaxNotificationPayloadByteSize + ) { + return copyWithMessageInfos; + } + return notification; } type NotificationInfo =