diff --git a/keyserver/flow-typed/npm/@parse/node-apn_vx.x.x.js b/keyserver/flow-typed/npm/@parse/node-apn_vx.x.x.js --- a/keyserver/flow-typed/npm/@parse/node-apn_vx.x.x.js +++ b/keyserver/flow-typed/npm/@parse/node-apn_vx.x.x.js @@ -38,7 +38,7 @@ // be accessed from apn.Notification instance aps: { +badge: string | number, - +alert: string, + +alert: string | { +body?: string, ... }, +'thread-id': string, +'mutable-content': boolean, +sound: string, diff --git a/keyserver/src/push/crypto.js b/keyserver/src/push/crypto.js --- a/keyserver/src/push/crypto.js +++ b/keyserver/src/push/crypto.js @@ -4,6 +4,8 @@ import invariant from 'invariant'; import _cloneDeep from 'lodash/fp/cloneDeep.js'; +import { NEXT_CODE_VERSION } from 'lib/shared/version-utils.js'; + import type { AndroidNotification, AndroidNotificationPayload, @@ -15,6 +17,7 @@ async function encryptIOSNotification( cookieID: string, notification: apn.Notification, + codeVersion?: ?number, notificationSizeValidator?: apn.Notification => boolean, ): Promise<{ +notification: apn.Notification, +payloadSizeExceeded: boolean }> { invariant( @@ -62,6 +65,18 @@ ); encryptedNotification.payload.encryptedPayload = serializedPayload.body; + + if ( + codeVersion && + codeVersion >= NEXT_CODE_VERSION && + codeVersion % 2 === 0 + ) { + encryptedNotification.aps = { + alert: { body: 'ENCRYPTED' }, + ...encryptedNotification.aps, + }; + } + return { notification: encryptedNotification, payloadSizeExceeded: !!dbPersistConditionViolated, @@ -200,6 +215,7 @@ function prepareEncryptedIOSNotifications( devices: $ReadOnlyArray, notification: apn.Notification, + codeVersion?: ?number, notificationSizeValidator?: apn.Notification => boolean, ): Promise< $ReadOnlyArray<{ @@ -214,6 +230,7 @@ const notif = await encryptIOSNotification( cookieID, notification, + codeVersion, notificationSizeValidator, ); return { cookieID, deviceToken, ...notif }; @@ -225,6 +242,7 @@ function prepareEncryptedIOSNotificationRescind( devices: $ReadOnlyArray, notification: apn.Notification, + codeVersion?: ?number, ): Promise< $ReadOnlyArray<{ +cookieID: string, @@ -237,6 +255,7 @@ const { notification: notif } = await encryptIOSNotification( cookieID, notification, + codeVersion, ); return { deviceToken, cookieID, notification: notif }; }, diff --git a/keyserver/src/push/rescind.js b/keyserver/src/push/rescind.js --- a/keyserver/src/push/rescind.js +++ b/keyserver/src/push/rescind.js @@ -247,6 +247,7 @@ encryptCallback: ( devices: $ReadOnlyArray, notification: T, + codeVersion?: ?number, ) => Promise< $ReadOnlyArray<{ +notification: T, @@ -262,7 +263,11 @@ deviceToken, })); } - const notifications = await encryptCallback(devices, notification); + const notifications = await encryptCallback( + devices, + notification, + codeVersion, + ); return notifications.map(({ deviceToken, notification: notif }) => ({ deviceToken, notification: notif, 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 @@ -784,6 +784,7 @@ const notifsWithMessageInfos = await prepareEncryptedIOSNotifications( devices, copyWithMessageInfos, + platformDetails.codeVersion, notificationSizeValidator, ); @@ -803,6 +804,7 @@ const notifsWithoutMessageInfos = await prepareEncryptedIOSNotifications( devicesWithExcessiveSize, notification, + platformDetails.codeVersion, ); const targetedNotifsWithMessageInfos = notifsWithMessageInfos @@ -1354,6 +1356,7 @@ const notificationsArray = await prepareEncryptedIOSNotifications( deviceInfos, notification, + codeVersion, ); targetedNotifications = notificationsArray.map( ({ notification: notif, deviceToken }) => ({ diff --git a/native/ios/NotificationService/NotificationService.mm b/native/ios/NotificationService/NotificationService.mm --- a/native/ios/NotificationService/NotificationService.mm +++ b/native/ios/NotificationService/NotificationService.mm @@ -58,6 +58,15 @@ self.contentHandler([[UNNotificationContent alloc] init]); return; } + + if ([self isBadgeOnly:self.bestAttemptContent.userInfo]) { + UNMutableNotificationContent *badgeOnlyContent = + [[UNMutableNotificationContent alloc] init]; + badgeOnlyContent.badge = self.bestAttemptContent.badge; + self.contentHandler(badgeOnlyContent); + return; + } + [self sendNewMessageInfosNotification]; // TODO modify self.bestAttemptContent here @@ -155,6 +164,12 @@ [payload[backgroundNotificationTypeKey] isEqualToString:@"CLEAR"]; } +- (BOOL)isBadgeOnly:(NSDictionary *)payload { + // TODO: refactor this check by introducing + // badgeOnly property in iOS notification payload + return !payload[@"threadID"]; +} + - (void)sendNewMessageInfosNotification { CFNotificationCenterPostNotification( CFNotificationCenterGetDarwinNotifyCenter(),