Skip to content

Commit f90277b

Browse files
committed
Fix FCM custom data handling
1 parent 12f2b14 commit f90277b

File tree

3 files changed

+76
-6
lines changed

3 files changed

+76
-6
lines changed

src/utils/fcmMessage.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ class FcmMessage {
3434
}
3535

3636
static buildAndroidMessage(params, options) {
37-
const message = buildGcmMessage(params, options);
37+
// Mark as FCM so buildGcmMessage doesn't pollute custom data
38+
const fcmOptions = { ...options, fcm: true };
39+
const message = buildGcmMessage(params, fcmOptions);
3840

3941
const androidMessage = message.toJson();
4042

src/utils/tools.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,15 @@ const buildGcmMessage = (data, options) => {
113113
};
114114
}
115115

116-
custom.title = custom.title || data.title;
117-
custom.message = custom.message || data.body;
118-
custom.sound = custom.sound || data.sound;
119-
custom.icon = custom.icon || data.icon;
120-
custom.msgcnt = custom.msgcnt || data.badge;
116+
// Only add notification fields to custom data for GCM (not FCM)
117+
// FCM uses separate notification and data fields
118+
if (!options.fcm) {
119+
custom.title = custom.title || data.title;
120+
custom.message = custom.message || data.body;
121+
custom.sound = custom.sound || data.sound;
122+
custom.icon = custom.icon || data.icon;
123+
custom.msgcnt = custom.msgcnt || data.badge;
124+
}
121125
if (options.phonegap === true && data.contentAvailable) {
122126
custom['content-available'] = 1;
123127
}

test/send/sendFCM.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,68 @@ describe('push-notifications-fcm', () => {
7979
.catch(done);
8080
});
8181
});
82+
83+
describe('send push notifications with custom data', () => {
84+
const customDataMessage = {
85+
title: 'Notification Title',
86+
body: 'Notification Body',
87+
custom: {
88+
userId: '12345',
89+
actionId: 'action-001',
90+
deepLink: 'app://section/item',
91+
},
92+
};
93+
94+
let customDataSendMethod;
95+
96+
function sendCustomDataMethod() {
97+
return sinon.stub(
98+
fbMessaging.prototype,
99+
'sendEachForMulticast',
100+
function sendFCMWithCustomData(firebaseMessage) {
101+
const { custom } = customDataMessage;
102+
103+
// Verify custom data is preserved in top-level data field
104+
expect(firebaseMessage.data).to.deep.equal(custom);
105+
106+
// Verify custom data does NOT pollute the notification
107+
// Note: normalizeDataParams converts all values to strings (FCM requirement)
108+
expect(firebaseMessage.android.data).to.deep.equal(custom);
109+
expect(firebaseMessage.android.data).to.not.have.property('title');
110+
expect(firebaseMessage.android.data).to.not.have.property('body');
111+
112+
// Verify notification has proper fields (separate from data)
113+
expect(firebaseMessage.android.notification).to.include({
114+
title: customDataMessage.title,
115+
body: customDataMessage.body,
116+
});
117+
118+
return Promise.resolve({
119+
successCount: 1,
120+
failureCount: 0,
121+
responses: [{ error: null }],
122+
});
123+
}
124+
);
125+
}
126+
127+
before(() => {
128+
customDataSendMethod = sendCustomDataMethod();
129+
});
130+
131+
after(() => {
132+
customDataSendMethod.restore();
133+
});
134+
135+
it('custom data should be preserved and not mixed with notification fields', (done) => {
136+
pn.send(regIds, customDataMessage)
137+
.then((results) => {
138+
expect(results).to.be.an('array');
139+
expect(results[0].method).to.equal('fcm');
140+
expect(results[0].success).to.equal(1);
141+
done();
142+
})
143+
.catch(done);
144+
});
145+
});
82146
});

0 commit comments

Comments
 (0)