From 06662dfbc83a2b2621728e3dc0ffc16faa77cd44 Mon Sep 17 00:00:00 2001 From: Corey Baker Date: Fri, 17 Jan 2025 06:25:50 -0800 Subject: [PATCH 1/4] feat: Add support for watchOS notifications --- spec/ParsePushAdapter.spec.js | 26 ++++++++++++++++++-------- src/ParsePushAdapter.js | 3 ++- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/spec/ParsePushAdapter.spec.js b/spec/ParsePushAdapter.spec.js index 4cbbb81b..602aae3b 100644 --- a/spec/ParsePushAdapter.spec.js +++ b/spec/ParsePushAdapter.spec.js @@ -160,13 +160,13 @@ describe('ParsePushAdapter', () => { it('can get valid push types', (done) => { const parsePushAdapter = new ParsePushAdapter(); - expect(parsePushAdapter.getValidPushTypes()).toEqual(['ios', 'osx', 'tvos', 'android', 'fcm', 'web', 'expo']); + expect(parsePushAdapter.getValidPushTypes()).toEqual(['ios', 'osx', 'tvos', 'watchos', 'android', 'fcm', 'web', 'expo']); done(); }); it('can classify installation', (done) => { // Mock installations - const validPushTypes = ['ios', 'osx', 'tvos', 'android', 'fcm', 'web', 'expo']; + const validPushTypes = ['ios', 'osx', 'tvos', 'watchos', 'android', 'fcm', 'web', 'expo']; const installations = [ { deviceType: 'android', @@ -180,6 +180,10 @@ describe('ParsePushAdapter', () => { deviceType: 'tvos', deviceToken: 'tvosToken' }, + { + deviceType: 'watchos', + deviceToken: 'watchosToken' + }, { deviceType: 'osx', deviceToken: 'osxToken' @@ -208,6 +212,7 @@ describe('ParsePushAdapter', () => { expect(deviceMap['ios']).toEqual([makeDevice('iosToken', 'ios')]); expect(deviceMap['osx']).toEqual([makeDevice('osxToken', 'osx')]); expect(deviceMap['tvos']).toEqual([makeDevice('tvosToken', 'tvos')]); + expect(deviceMap['watchos']).toEqual([makeDevice('watchosToken', 'watchos')]); expect(deviceMap['web']).toEqual([makeDevice('webToken', 'web')]); expect(deviceMap['win']).toBe(undefined); expect(deviceMap['expo']).toEqual([makeDevice('expoToken', 'ios')]); @@ -395,7 +400,7 @@ describe('ParsePushAdapter', () => { done(); }); - it('reports properly results', (done) => { + it('reports proper results', (done) => { spyOn(log, 'error').and.callFake(() => {}); const pushConfig = { web: { @@ -450,10 +455,15 @@ describe('ParsePushAdapter', () => { appIdentifier: 'osxbundleId' }, { - deviceType: 'tvos', - deviceToken: '3e72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6', + deviceType: 'watchos', + deviceToken: '8f72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6', appIdentifier: 'iosbundleId' // ios and tvos share the same bundleid }, + { + deviceType: 'watchos', + deviceToken: '3e72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6', + appIdentifier: 'iosbundleId' // ios and watchos share the same bundleid + }, { deviceType: 'web', deviceToken: JSON.stringify({ endpoint: 'https://fcm.googleapis.com/fcm/send/123' }), @@ -477,8 +487,8 @@ describe('ParsePushAdapter', () => { parsePushAdapter.send({ data: { alert: 'some' } }, installations).then((results) => { expect(Array.isArray(results)).toBe(true); - // 2x iOS, 1x android, 1x osx, 1x tvos, 1x web, 1x expo - expect(results.length).toBe(7); + // 2x iOS, 1x android, 1x osx, 1x tvos, 1xwatchos, 1x web, 1x expo + expect(results.length).toBe(8); results.forEach((result) => { expect(typeof result.device).toBe('object'); if (!result.device) { @@ -530,7 +540,7 @@ describe('ParsePushAdapter', () => { parsePushAdapter.send({data: {alert: 'some'}}, installations).then((results) => { expect(Array.isArray(results)).toBe(true); - // 2x iOS, 1x android, 1x osx, 1x tvos + // 2x iOS, 1x android, 1x osx, 1x tvos, 1x watchos expect(results.length).toBe(1); const result = results[0]; expect(typeof result.device).toBe('object'); diff --git a/src/ParsePushAdapter.js b/src/ParsePushAdapter.js index 0f2eace2..51867697 100644 --- a/src/ParsePushAdapter.js +++ b/src/ParsePushAdapter.js @@ -15,7 +15,7 @@ export default class ParsePushAdapter { supportsPushTracking = true; constructor(pushConfig = {}) { - this.validPushTypes = ['ios', 'osx', 'tvos', 'android', 'fcm', 'web', 'expo']; + this.validPushTypes = ['ios', 'osx', 'tvos', 'watchos', 'android', 'fcm', 'web', 'expo']; this.senderMap = {}; // used in PushController for Dashboard Features this.feature = { @@ -32,6 +32,7 @@ export default class ParsePushAdapter { switch (pushType) { case 'ios': case 'tvos': + case 'watchos': case 'osx': if (pushConfig[pushType].hasOwnProperty('firebaseServiceAccount')) { this.senderMap[pushType] = new FCM(pushConfig[pushType], 'apple'); From f6d921e8f9ffa164de01ad6554bfca3ed4b3db2f Mon Sep 17 00:00:00 2001 From: Corey Baker Date: Fri, 17 Jan 2025 06:30:24 -0800 Subject: [PATCH 2/4] nit --- spec/ParsePushAdapter.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/ParsePushAdapter.spec.js b/spec/ParsePushAdapter.spec.js index 602aae3b..356e8859 100644 --- a/spec/ParsePushAdapter.spec.js +++ b/spec/ParsePushAdapter.spec.js @@ -455,13 +455,13 @@ describe('ParsePushAdapter', () => { appIdentifier: 'osxbundleId' }, { - deviceType: 'watchos', - deviceToken: '8f72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6', + deviceType: 'tvos', + deviceToken: '3e72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6', appIdentifier: 'iosbundleId' // ios and tvos share the same bundleid }, { deviceType: 'watchos', - deviceToken: '3e72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6', + deviceToken: '8f72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6', appIdentifier: 'iosbundleId' // ios and watchos share the same bundleid }, { From 4cdbc8296e133e7edce42ba37e27829d26e4aeaa Mon Sep 17 00:00:00 2001 From: Corey Date: Fri, 17 Jan 2025 06:34:38 -0800 Subject: [PATCH 3/4] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e398d69c..d2297eb6 100644 --- a/README.md +++ b/README.md @@ -72,10 +72,11 @@ Parse Server Push Adapter currently supports these types of Apple ecosystems: - `ios`: iPhone, iPad, and iPod touch apps - `osx`: macOS, and macCatalyst apps - `tvos`: tvOS apps +- `watchos`: watchOS apps -Delivering push notifications to Apple devices can be done either via Apple Push Notification Service (APNS), or via Firebase Cloud Messaging (FMC). Note that each category of Apple devices require their own configuration section: +Push notifications can be delivered to Apple devices either via Apple Push Notification Service (APNS) or Firebase Cloud Messaging (FMC). Note that each category of Apple devices requires their own configuration section: -- APNS requires a private key that can be downloaded from the Apple Developer Center at https://developer.apple.com/account under _Certificates > Identifiers & Profiles._ The adapter options also require the app ID and team ID which can be found there. +- APNS requires a private key that can be downloaded from the Apple Developer Center at https://developer.apple.com/account under _Certificates > Identifiers & Profiles._ The adapter options also require the app ID and team ID, which can be found there. - FCM requires a private key that can be downloaded from the Firebase Console at https://console.firebase.google.com in your project under _Settings > Cloud Messaging._ Example options: From 5d5eb52f1b1ab996d81a18ba455b3eb9dfc0d984 Mon Sep 17 00:00:00 2001 From: Corey Baker Date: Fri, 17 Jan 2025 06:53:37 -0800 Subject: [PATCH 4/4] nit --- spec/ParsePushAdapter.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ParsePushAdapter.spec.js b/spec/ParsePushAdapter.spec.js index 356e8859..40d8d0bf 100644 --- a/spec/ParsePushAdapter.spec.js +++ b/spec/ParsePushAdapter.spec.js @@ -487,7 +487,7 @@ describe('ParsePushAdapter', () => { parsePushAdapter.send({ data: { alert: 'some' } }, installations).then((results) => { expect(Array.isArray(results)).toBe(true); - // 2x iOS, 1x android, 1x osx, 1x tvos, 1xwatchos, 1x web, 1x expo + // 2x iOS, 1x android, 1x osx, 1x tvos, 1x watchos, 1x web, 1x expo expect(results.length).toBe(8); results.forEach((result) => { expect(typeof result.device).toBe('object');