Skip to content

Commit

Permalink
feat: Add Firebase Cloud Messaging (FCM) HTTP/2 support and option `f…
Browse files Browse the repository at this point in the history
…cmEnableLegacyHttpTransport` to use legacy HTTP/1.1 (#274)
  • Loading branch information
jimnor0xF authored Aug 2, 2024
1 parent a15decd commit 70e6b6f
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 25 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ The official Push Notification adapter for Parse Server. See [Parse Server Push
- [Configure Parse Server](#configure-parse-server)
- [Apple Push Options](#apple-push-options)
- [Android Push Options](#android-push-options)
- [Firebase Cloud Messaging (FCM)](#firebase-cloud-messaging-fcm)
- [Google Cloud Service Account Key](#google-cloud-service-account-key)
- [Migration to FCM HTTP v1 API (June 2024)](#migration-to-fcm-http-v1-api-june-2024)
- [HTTP/1.1 Legacy Option](#http11-legacy-option)
- [Expo Push Options](#expo-push-options)
- [Bundled with Parse Server](#bundled-with-parse-server)
- [Logging](#logging)
Expand Down Expand Up @@ -110,6 +112,10 @@ android: {
}
```

### Firebase Cloud Messaging (FCM)

This section contains some considerations when using FCM, regardless of the destination ecosystems the push notification is sent to.

#### Google Cloud Service Account Key

The Firebase console allows to easily create and download a Google Cloud service account key JSON file with the required permissions. Instead of setting `firebaseServiceAccount` to the path of the JSON file, you can provide an object representing a Google Cloud service account key:
Expand Down Expand Up @@ -139,6 +145,19 @@ android: {
}
```

#### HTTP/1.1 Legacy Option

With the introduction of the FCM HTTP v1 API, support for HTTP/2 was added which provides faster throughput for push notifications. To use the older version HTTP/1.1 set `fcmEnableLegacyHttpTransport: true` in your push options.

Example options:

```js
android: {
firebaseServiceAccount: __dirname + '/firebase.json',
fcmEnableLegacyHttpTransport: true
}
```

### Expo Push Options

Example options:
Expand Down
42 changes: 19 additions & 23 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@parse/node-apn": "6.0.1",
"@parse/node-gcm": "1.0.2",
"expo-server-sdk": "3.10.0",
"firebase-admin": "12.2.0",
"firebase-admin": "12.3.0",
"npmlog": "7.0.1",
"parse": "5.2.0",
"web-push": "3.6.7"
Expand Down
36 changes: 36 additions & 0 deletions spec/FCM.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path';
import log from 'npmlog';
import FCM from '../src/FCM.js';
import { getApps, deleteApp } from 'firebase-admin/app';

const testArgs = {
firebaseServiceAccount: path.join(
Expand All @@ -13,6 +14,10 @@ const testArgs = {
};

describe('FCM', () => {
beforeEach(async () => {
getApps().forEach(app => deleteApp(app));
});

it('can initialize', () => {
const fcm = new FCM(testArgs);
expect(fcm).toBeDefined();
Expand All @@ -31,6 +36,37 @@ describe('FCM', () => {
expect(spy).toHaveBeenCalledWith('parse-server-push-adapter FCM', 'invalid push payload');
});

it('initializes with fcmEnableLegacyHttpTransport set to false by default', () => {
const fcm = new FCM(testArgs);
expect(fcm).toBeDefined();
expect(fcm.sender).toBeDefined();
expect(fcm.sender.useLegacyTransport).toEqual(false);
});

it('can initialize with fcmEnableLegacyHttpTransport set to false', () => {
const legacyHttpTransportArgs = {
...testArgs,
fcmEnableLegacyHttpTransport: false
};

const fcm = new FCM(legacyHttpTransportArgs);
expect(fcm).toBeDefined();
expect(fcm.sender).toBeDefined();
expect(fcm.sender.useLegacyTransport).toEqual(false);
});

it('can initialize with fcmEnableLegacyHttpTransport set to true', () => {
const legacyHttpTransportArgs = {
...testArgs,
fcmEnableLegacyHttpTransport: true
};

const fcm = new FCM(legacyHttpTransportArgs);
expect(fcm).toBeDefined();
expect(fcm.sender).toBeDefined();
expect(fcm.sender.useLegacyTransport).toEqual(true);
});

it('can send successful FCM android request', async () => {
const spyVerbose = spyOn(log, 'verbose').and.callFake(() => {});
const spyInfo = spyOn(log, 'info').and.callFake(() => {});
Expand Down
14 changes: 13 additions & 1 deletion src/FCM.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,26 @@ export default function FCM(args, pushType) {
);
}

const fcmEnableLegacyHttpTransport = typeof args.fcmEnableLegacyHttpTransport === 'boolean'
? args.fcmEnableLegacyHttpTransport
: false;

let app;
if (getApps().length === 0) {
app = initializeApp({ credential: cert(args.firebaseServiceAccount) });
} else {
app = getApp();
}

this.sender = getMessaging(app);
this.pushType = pushType; // Push type is only used to remain backwards compatible with APNS and GCM

if (fcmEnableLegacyHttpTransport) {
this.sender.enableLegacyHttpTransport();
log.warn(LOG_PREFIX, 'Legacy HTTP/1.1 transport is enabled. This is a deprecated feature and support for this flag will be removed in the future.');
}

// Push type is only used to remain backwards compatible with APNS and GCM
this.pushType = pushType;
}

FCM.FCMRegistrationTokensMax = FCMRegistrationTokensMax;
Expand Down

0 comments on commit 70e6b6f

Please sign in to comment.