Skip to content

Commit fd16ccc

Browse files
funkenstrahlenflovilmart
authored andcommitted
Add macOS and tvOS push notification support (#58)
* add macos and tvos types * return device type * reuse ios configuration for tvos pushes * add osx and tvos to some of the specs * add more specs * fix spec * test for tvos and ios sender reuse in separate test cases * fix typo * fix spec * fix spec * fix define args * remove comment * update spec * remove todo * change device token * Update ParsePushAdapter.spec.js * remove redundancy in push configuration * fix code style * change var back to let
1 parent b7a8459 commit fd16ccc

File tree

3 files changed

+63
-19
lines changed

3 files changed

+63
-19
lines changed

spec/ParsePushAdapter.spec.js

+55-12
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ describe('ParsePushAdapter', () => {
5454
it('can get valid push types', (done) => {
5555
var parsePushAdapter = new ParsePushAdapter();
5656

57-
expect(parsePushAdapter.getValidPushTypes()).toEqual(['ios', 'android', 'fcm']);
57+
expect(parsePushAdapter.getValidPushTypes()).toEqual(['ios', 'osx', 'tvos', 'android', 'fcm']);
5858
done();
5959
});
6060

6161
it('can classify installation', (done) => {
6262
// Mock installations
63-
var validPushTypes = ['ios', 'android', 'fcm'];
63+
var validPushTypes = ['ios', 'osx', 'tvos', 'android', 'fcm'];
6464
var installations = [
6565
{
6666
deviceType: 'android',
@@ -70,6 +70,14 @@ describe('ParsePushAdapter', () => {
7070
deviceType: 'ios',
7171
deviceToken: 'iosToken'
7272
},
73+
{
74+
deviceType: 'tvos',
75+
deviceToken: 'tvosToken'
76+
},
77+
{
78+
deviceType: 'osx',
79+
deviceToken: 'osxToken'
80+
},
7381
{
7482
deviceType: 'win',
7583
deviceToken: 'winToken'
@@ -83,21 +91,27 @@ describe('ParsePushAdapter', () => {
8391
var deviceMap = ParsePushAdapter.classifyInstallations(installations, validPushTypes);
8492
expect(deviceMap['android']).toEqual([makeDevice('androidToken', 'android')]);
8593
expect(deviceMap['ios']).toEqual([makeDevice('iosToken', 'ios')]);
94+
expect(deviceMap['osx']).toEqual([makeDevice('osxToken', 'osx')]);
95+
expect(deviceMap['tvos']).toEqual([makeDevice('tvosToken', 'tvos')]);
8696
expect(deviceMap['win']).toBe(undefined);
8797
done();
8898
});
8999

90100

91101
it('can send push notifications', (done) => {
92102
var parsePushAdapter = new ParsePushAdapter();
93-
// Mock android ios senders
103+
// Mock senders
94104
var androidSender = {
95105
send: jasmine.createSpy('send')
96106
};
97107
var iosSender = {
98108
send: jasmine.createSpy('send')
99109
};
110+
var osxSender = {
111+
send: jasmine.createSpy('send')
112+
}
100113
var senderMap = {
114+
osx: osxSender,
101115
ios: iosSender,
102116
android: androidSender
103117
};
@@ -112,6 +126,10 @@ describe('ParsePushAdapter', () => {
112126
deviceType: 'ios',
113127
deviceToken: 'iosToken'
114128
},
129+
{
130+
deviceType: 'osx',
131+
deviceToken: 'osxToken'
132+
},
115133
{
116134
deviceType: 'win',
117135
deviceToken: 'winToken'
@@ -136,14 +154,21 @@ describe('ParsePushAdapter', () => {
136154
args = iosSender.send.calls.first().args;
137155
expect(args[0]).toEqual(data);
138156
expect(args[1]).toEqual([
139-
makeDevice('iosToken', 'ios')
157+
makeDevice('iosToken', 'ios'),
158+
]);
159+
// Check osx sender
160+
expect(osxSender.send).toHaveBeenCalled();
161+
args = osxSender.send.calls.first().args;
162+
expect(args[0]).toEqual(data);
163+
expect(args[1]).toEqual([
164+
makeDevice('osxToken', 'osx')
140165
]);
141166
done();
142167
});
143168

144169
it('can send push notifications by pushType and failback by deviceType', (done) => {
145170
var parsePushAdapter = new ParsePushAdapter();
146-
// Mock android ios senders
171+
// Mock senders
147172
var androidSender = {
148173
send: jasmine.createSpy('send')
149174
};
@@ -233,7 +258,15 @@ describe('ParsePushAdapter', () => {
233258
cert: 'cert.cer',
234259
key: 'key.pem',
235260
production: false,
236-
bundleId: 'bundleId'
261+
bundleId: 'iosbundleId'
262+
}
263+
],
264+
osx: [
265+
{
266+
cert: 'cert.cer',
267+
key: 'key.pem',
268+
production: false,
269+
bundleId: 'osxbundleId'
237270
}
238271
]
239272
};
@@ -244,13 +277,23 @@ describe('ParsePushAdapter', () => {
244277
},
245278
{
246279
deviceType: 'ios',
247-
deviceToken: 'c5ee8fae0a1c',
248-
appIdentifier: 'anotherBundle'
280+
deviceToken: '0d72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6',
281+
appIdentifier: 'invalidiosbundleId'
249282
},
250283
{
251284
deviceType: 'ios',
252-
deviceToken: 'c5ee8fae0a1c5805e731cf15496d5b2b3f9b9c577353d3239429d3faaee01c79',
253-
appIdentifier: 'anotherBundle'
285+
deviceToken: 'ff3943ed0b2090c47e5d6f07d8f202a10427941d7897fda5a6b18c6d9fd07d48',
286+
appIdentifier: 'invalidiosbundleId'
287+
},
288+
{
289+
deviceType: 'osx',
290+
deviceToken: '5cda62a8d88eb48d9111a6c436f2e326a053eb0cd72dfc3a0893089342602235',
291+
appIdentifier: 'invalidosxbundleId'
292+
},
293+
{
294+
deviceType: 'tvos',
295+
deviceToken: '3e72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6',
296+
appIdentifier: 'invalidiosbundleId' // ios and tvos share the same bundleid
254297
},
255298
{
256299
deviceType: 'win',
@@ -266,8 +309,8 @@ describe('ParsePushAdapter', () => {
266309
parsePushAdapter.send({data: {alert: 'some'}}, installations).then((results) => {
267310
expect(Array.isArray(results)).toBe(true);
268311

269-
// 2x iOS, 1x android
270-
expect(results.length).toBe(3);
312+
// 2x iOS, 1x android, 1x osx, 1x tvos
313+
expect(results.length).toBe(5);
271314
results.forEach((result) => {
272315
expect(result.transmitted).toBe(false);
273316
expect(typeof result.device).toBe('object');

src/APNS.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ const LOG_PREFIX = 'parse-server-push-adapter APNS';
2020
* @param {Boolean} args.production Specifies which environment to connect to: Production (if true) or Sandbox
2121
*/
2222
function APNS(args) {
23-
// Since for ios, there maybe multiple cert/key pairs,
2423
// typePushConfig can be an array.
2524
let apnsArgsList = [];
2625
if (Array.isArray(args)) {
@@ -74,7 +73,7 @@ function APNS(args) {
7473
notification: notification,
7574
transmitted: true,
7675
device: {
77-
deviceType: 'ios',
76+
deviceType: device.deviceType,
7877
deviceToken: device.token.toString('hex')
7978
}
8079
});
@@ -115,7 +114,7 @@ APNS.prototype.send = function(data, devices) {
115114
transmitted: false,
116115
device: {
117116
deviceToken: device.deviceToken,
118-
deviceType: 'ios'
117+
deviceType: device.deviceType
119118
},
120119
result: {error: 'No connection available'}
121120
});
@@ -177,7 +176,7 @@ function handleTransmissionError(conns, errCode, notification, apnDevice) {
177176
status: errCode,
178177
transmitted: false,
179178
device: {
180-
deviceType: 'ios',
179+
deviceType: apnDevice.deviceType,
181180
deviceToken: apnDevice.token.toString('hex')
182181
}
183182
});

src/ParsePushAdapter.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export class ParsePushAdapter {
1212
supportsPushTracking = true;
1313

1414
constructor(pushConfig = {}) {
15-
this.validPushTypes = ['ios', 'android', 'fcm'];
15+
this.validPushTypes = ['ios', 'osx', 'tvos', 'android', 'fcm'];
1616
this.senderMap = {};
1717
// used in PushController for Dashboard Features
1818
this.feature = {
@@ -27,6 +27,8 @@ export class ParsePushAdapter {
2727
}
2828
switch (pushType) {
2929
case 'ios':
30+
case 'tvos':
31+
case 'osx':
3032
this.senderMap[pushType] = new APNS(pushConfig[pushType]);
3133
break;
3234
case 'android':
@@ -51,8 +53,8 @@ export class ParsePushAdapter {
5153
for (let pushType in deviceMap) {
5254
let sender = this.senderMap[pushType];
5355
let devices = deviceMap[pushType];
54-
if(Array.isArray(devices) && devices.length > 0)
55-
{
56+
57+
if(Array.isArray(devices) && devices.length > 0) {
5658
if (!sender) {
5759
log.verbose(LOG_PREFIX, `Can not find sender for push type ${pushType}, ${data}`)
5860
let results = devices.map((device) => {

0 commit comments

Comments
 (0)