-
Notifications
You must be signed in to change notification settings - Fork 401
fix FCM Push notification payload structure #492
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
Changes from 3 commits
06c89ba
c31a02f
de6e30c
0edce18
e4d3aa8
95f4152
3cf4c99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| import type { Payload } from '../types/api'; | ||
|
|
||
| // -------------------------------------------------------- | ||
| // ------------------------ Types ------------------------- | ||
| // -------------------------------------------------------- | ||
|
|
@@ -177,24 +179,51 @@ type FCMPayload = { | |
| body?: string; | ||
|
|
||
| /** | ||
| * Name of the icon file from resource bundle which should be shown on notification. | ||
| */ | ||
| icon?: string; | ||
|
|
||
| /** | ||
| * Name of the file from resource bundle which should be played when notification received. | ||
| * URL of an image to be displayed in the notification. | ||
| */ | ||
| sound?: string; | ||
|
|
||
| tag?: string; | ||
| image?: string; | ||
| }; | ||
|
|
||
| /** | ||
| * Configuration of data notification. | ||
| * | ||
| * Silent notification configuration. | ||
| */ | ||
| data?: { notification?: FCMPayload['notification'] }; | ||
| data?: { notification?: FCMPayload['notification'] } & Record<string, Payload | null>; | ||
|
|
||
| /** | ||
| * Android-specific options for notification delivery. | ||
| */ | ||
| android?: { | ||
| notification?: { | ||
| /** | ||
| * Name of the icon file from resource bundle which should be shown on notification. | ||
| */ | ||
| icon?: string; | ||
|
|
||
| /** | ||
| * Name of the file from resource bundle which should be played when notification received. | ||
| */ | ||
| sound?: string; | ||
|
|
||
| tag?: string; | ||
| }; | ||
| } & Record<string, Payload | null>; | ||
|
|
||
| /** | ||
| * APNS-specific options for notification delivery. | ||
| */ | ||
| apns?: Record<string, Payload | null>; | ||
|
|
||
| /** | ||
| * Web Push-specific options for notification delivery. | ||
| */ | ||
| webpush?: Record<string, Payload | null>; | ||
|
|
||
| /** | ||
| * FCM service level options. | ||
| */ | ||
| fcm_options?: Record<string, Payload | null>; | ||
| }; | ||
| // endregion | ||
| // endregion | ||
|
|
@@ -700,7 +729,7 @@ export class FCMNotificationPayload extends BaseNotificationPayload { | |
| set sound(value) { | ||
| if (!value || !value.length) return; | ||
|
|
||
| this.payload.notification!.sound = value; | ||
| this.androidNotification.sound = value; | ||
| this._sound = value; | ||
| } | ||
|
|
||
|
|
@@ -716,12 +745,12 @@ export class FCMNotificationPayload extends BaseNotificationPayload { | |
| /** | ||
| * Update notification icon. | ||
| * | ||
| * @param value - Name of the icon file which should be shown on notification. | ||
| * @param value - Name of the icon file set for `android.notification.icon`. | ||
| */ | ||
| set icon(value) { | ||
| if (!value || !value.length) return; | ||
|
|
||
| this.payload.notification!.icon = value; | ||
| this.androidNotification.icon = value; | ||
| this._icon = value; | ||
| } | ||
|
|
||
|
|
@@ -737,12 +766,12 @@ export class FCMNotificationPayload extends BaseNotificationPayload { | |
| /** | ||
| * Update notifications grouping tag. | ||
| * | ||
| * @param value - String which will be used to group similar notifications in notification center. | ||
| * @param value - String set for `android.notification.tag` to group similar notifications. | ||
| */ | ||
| set tag(value) { | ||
| if (!value || !value.length) return; | ||
|
|
||
| this.payload.notification!.tag = value; | ||
| this.androidNotification.tag = value; | ||
| this._tag = value; | ||
| } | ||
|
|
||
|
|
@@ -767,6 +796,48 @@ export class FCMNotificationPayload extends BaseNotificationPayload { | |
| this.payload.data = {}; | ||
mohitpubnub marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /** | ||
| * Retrieve Android notification payload and initialize required structure. | ||
| * | ||
| * @returns Android specific notification payload. | ||
| */ | ||
| private get androidNotification() { | ||
| if (!this.payload.android) this.payload.android = {}; | ||
| if (!this.payload.android.notification) this.payload.android.notification = {}; | ||
|
|
||
| return this.payload.android.notification; | ||
| } | ||
mohitpubnub marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * Move legacy Android-specific notification fields under `android.notification`. | ||
| * | ||
| * @param notification - Common FCM notification payload. | ||
| * @param android - Android-specific payload. | ||
| * | ||
| * @returns Updated Android payload. | ||
| */ | ||
| private moveLegacyAndroidNotificationFields( | ||
|
||
| notification: NonNullable<FCMPayload['notification']>, | ||
| android?: FCMPayload['android'], | ||
| ): FCMPayload['android'] { | ||
| const legacyFields = ['sound', 'icon', 'tag'] as const; | ||
| const notificationPayload = notification as Record<string, unknown>; | ||
| let androidPayload = android; | ||
|
|
||
| legacyFields.forEach((field) => { | ||
| const value = notificationPayload[field]; | ||
| if (typeof value !== 'string' || !value.length) return; | ||
|
|
||
| if (!androidPayload) androidPayload = {}; | ||
| if (!androidPayload.notification) androidPayload.notification = {}; | ||
|
|
||
| androidPayload.notification[field] = value; | ||
| delete notificationPayload[field]; | ||
| }); | ||
|
|
||
| return androidPayload; | ||
| } | ||
|
|
||
| /** | ||
| * Translate data object into PubNub push notification payload object. | ||
| * | ||
|
|
@@ -775,22 +846,33 @@ export class FCMNotificationPayload extends BaseNotificationPayload { | |
| * @returns Preformatted push notification payload. | ||
| */ | ||
| public toObject(): FCMPayload | null { | ||
| let data = { ...this.payload.data }; | ||
| let notification = null; | ||
| const reservedTopLevelKeys = ['notification', 'data', 'android', 'apns', 'webpush', 'fcm_options'] as const; | ||
| let data = { ...(this.payload.data ?? {}) }; | ||
| const notification = { ...(this.payload.notification ?? {}) }; | ||
| let android = this.payload.android ? { ...this.payload.android } : undefined; | ||
| const payload: FCMPayload = {}; | ||
| const { apns, webpush, fcm_options } = this.payload; | ||
| const additionalData = { ...this.payload } as Record<string, Payload | null>; | ||
|
|
||
| // Check whether additional data has been passed outside 'data' object and put it into it if required. | ||
| if (Object.keys(this.payload).length > 2) { | ||
| const { notification: initialNotification, data: initialData, ...additionalData } = this.payload; | ||
| android = this.moveLegacyAndroidNotificationFields(notification, android); | ||
|
|
||
| reservedTopLevelKeys.forEach((key) => { | ||
| delete additionalData[key]; | ||
| }); | ||
|
|
||
| // Check whether additional data has been passed outside 'data' object and put it into it if required. | ||
| if (Object.keys(additionalData).length) { | ||
| data = { ...data, ...additionalData }; | ||
| } | ||
|
|
||
| if (this._isSilent) data.notification = this.payload.notification; | ||
| else notification = this.payload.notification; | ||
| if (this._isSilent && Object.keys(notification).length) data.notification = notification; | ||
| else if (Object.keys(notification).length) payload.notification = notification; | ||
|
|
||
| if (Object.keys(data).length) payload.data = data; | ||
| if (notification && Object.keys(notification).length) payload.notification = notification; | ||
| if (android && Object.keys(android).length) payload.android = android; | ||
| if (apns && Object.keys(apns).length) payload.apns = apns; | ||
| if (webpush && Object.keys(webpush).length) payload.webpush = webpush; | ||
| if (fcm_options && Object.keys(fcm_options).length) payload.fcm_options = fcm_options; | ||
|
|
||
| return Object.keys(payload).length ? payload : null; | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.