pushwoosh-react-native-plugin 6.1.58 → 6.1.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  - [Integration Guide](https://docs.pushwoosh.com/platform-docs/pushwoosh-sdk/cross-platform-frameworks/react-native/integrating-react-native-plugin) — step-by-step setup
27
27
  - [API Reference](docs/README.md) — full API documentation
28
- - [Sample Project](https://github.com/Pushwoosh/pushwoosh-react-native-sample) — ready-to-run demo app
28
+ - [Sample Project](https://github.com/Pushwoosh/pushwoosh-react-native-plugin/tree/master/example/demoapp) — ready-to-run demo app
29
29
 
30
30
  ## Features
31
31
 
package/docs/README.md CHANGED
@@ -46,6 +46,8 @@ DeviceEventEmitter.addListener('pushOpened', (e: Event) => {
46
46
  <tr class="even"><td><a href="#getpushtoken">getPushToken(success)</a></td></tr>
47
47
  <tr class="even"><td><a href="#gethwid">getHwid(success)</a></td></tr>
48
48
  <tr class="even"><td><a href="#setuserid">setUserId(userId, success, fail)</a></td></tr>
49
+ <tr class="even"><td><a href="#setemails">setEmails(emails, success, fail)</a></td></tr>
50
+ <tr class="even"><td><a href="#setuseremails">setUserEmails(userId, emails, success, fail)</a></td></tr>
49
51
  <tr class="even"><td><a href="#postevent">postEvent(event, attributes)</a></td></tr>
50
52
  <tr class="even"><td><a href="#setapplicationiconbadgenumber">setApplicationIconBadgeNumber(badgeNumber)</a></td></tr>
51
53
  <tr class="even"><td><a href="#getapplicationiconbadgenumber">getApplicationIconBadgeNumber(callback)</a></td></tr>
@@ -292,6 +294,75 @@ This allows data and events to be matched across multiple user devices.
292
294
  </table>
293
295
 
294
296
 
297
+ ### setEmails
298
+
299
+ ```js
300
+ setEmails(emails, success, fail)
301
+ ```
302
+
303
+ Registers email address(es) for the current user. The addresses are associated with the user identifier currently set on the device; if `setUserId` was never called, the device HWID is used as the identifier. Use `setUserEmails` to set the user identifier and the addresses in a single call.
304
+
305
+ <table width=100% style='background-color:#0EA7ED;'>
306
+ <colgroup>
307
+ <col width="10%" />
308
+ <col width="20%" />
309
+ <col width="70%" />
310
+ </colgroup>
311
+ <tbody>
312
+ <tr>
313
+ <th align="left" colspan="3"><strong>Parameters</strong></th>
314
+ </tr>
315
+ <tr class="even"><td>array</td><td><b>emails</b></td><td>Array of email addresses associated with the current user.</td></tr>
316
+ <tr class="even"><td>function</td><td><b>success</b></td><td>(optional) method success callback.</td></tr>
317
+ <tr class="even"><td>function</td><td><b>fail</b></td><td>(optional) method failure callback.</td></tr>
318
+ </tbody>
319
+ </table>
320
+
321
+ Example:
322
+
323
+ ```js
324
+ Pushwoosh.setEmails(["user@example.com"],
325
+ function() { console.warn("setEmails success"); },
326
+ function(error) { console.warn("setEmails failed: " + error); }
327
+ );
328
+ ```
329
+
330
+
331
+ ### setUserEmails
332
+
333
+ ```js
334
+ setUserEmails(userId, emails, success, fail)
335
+ ```
336
+
337
+ Registers email address(es) for a specific user identifier. The method sets the user identifier and registers the addresses in a single call, so data and events can be matched across multiple channels (push, email) for the same user. A separate `setUserId` call is not required.
338
+
339
+ <table width=100% style='background-color:#0EA7ED;'>
340
+ <colgroup>
341
+ <col width="10%" />
342
+ <col width="20%" />
343
+ <col width="70%" />
344
+ </colgroup>
345
+ <tbody>
346
+ <tr>
347
+ <th align="left" colspan="3"><strong>Parameters</strong></th>
348
+ </tr>
349
+ <tr class="even"><td>string</td><td><b>userId</b></td><td>Identifier of currently logged in user</td></tr>
350
+ <tr class="even"><td>array</td><td><b>emails</b></td><td>Array of email addresses associated with the user.</td></tr>
351
+ <tr class="even"><td>function</td><td><b>success</b></td><td>(optional) method success callback.</td></tr>
352
+ <tr class="even"><td>function</td><td><b>fail</b></td><td>(optional) method failure callback.</td></tr>
353
+ </tbody>
354
+ </table>
355
+
356
+ Example:
357
+
358
+ ```js
359
+ Pushwoosh.setUserEmails("user-123", ["user@example.com"],
360
+ function() { console.warn("setUserEmails success"); },
361
+ function(error) { console.warn("setUserEmails failed: " + error); }
362
+ );
363
+ ```
364
+
365
+
295
366
  ### postEvent
296
367
 
297
368
  ```js
package/index.d.ts CHANGED
@@ -51,8 +51,8 @@ declare module 'pushwoosh-react-native-plugin' {
51
51
  enableHuaweiPushNotifications(): void;
52
52
 
53
53
  //email methods
54
- setUserEmails(userId: string, emails: (string | string[]), success?: () => void, fail?: (error: Error) => void): void;
55
- setEmails(emails: (string | string[]), success?: () => void, fail?: (error: Error) => void): void;
54
+ setUserEmails(userId: string, emails: (string | string[]), success?: () => void, fail?: (error: string) => void): void;
55
+ setEmails(emails: (string | string[]), success?: () => void, fail?: (error: string) => void): void;
56
56
  //SMS and WhatsApp methods
57
57
  registerSMSNumber(phoneNumber: string): void;
58
58
  registerWhatsappNumber(phoneNumber: string): void;
package/index.js CHANGED
@@ -383,14 +383,26 @@ class PushNotification {
383
383
  // }
384
384
  // );
385
385
  //
386
- setUserEmails(userId: string, emails: Object, success: ?Function, fail: ?Function) {
386
+ setUserEmails(userId: string, emails: string | Array<string>, success: ?Function, fail: ?Function) {
387
387
  if (!success) {
388
388
  success = function() {};
389
389
  }
390
390
  if (!fail) {
391
391
  fail = function(error) {};
392
392
  }
393
- PushwooshModule.setUserEmails(userId, emails, success, fail);
393
+ // Both native SDKs return silently on an empty user id without touching the callback.
394
+ if (typeof userId !== 'string' || userId.length === 0) {
395
+ fail('userId must not be empty');
396
+ return;
397
+ }
398
+ // The native bridge accepts arrays only, while the public type allows a single address.
399
+ const emailsList = (Array.isArray(emails) ? emails : [emails])
400
+ .filter(email => typeof email === 'string' && email.length > 0);
401
+ if (emailsList.length === 0) {
402
+ fail('emails must be a non-empty array of strings');
403
+ return;
404
+ }
405
+ PushwooshModule.setUserEmails(userId, emailsList, success, fail);
394
406
  }
395
407
 
396
408
 
@@ -408,14 +420,21 @@ class PushNotification {
408
420
  // }
409
421
  // );
410
422
  //
411
- setEmails(emails: Object, success: ?Function, fail: ?Function) {
423
+ setEmails(emails: string | Array<string>, success: ?Function, fail: ?Function) {
412
424
  if (!success) {
413
425
  success = function() {};
414
426
  }
415
427
  if (!fail) {
416
428
  fail = function(error) {};
417
429
  }
418
- PushwooshModule.setEmails(emails, success, fail);
430
+ // The native bridge accepts arrays only, while the public type allows a single address.
431
+ const emailsList = (Array.isArray(emails) ? emails : [emails])
432
+ .filter(email => typeof email === 'string' && email.length > 0);
433
+ if (emailsList.length === 0) {
434
+ fail('emails must be a non-empty array of strings');
435
+ return;
436
+ }
437
+ PushwooshModule.setEmails(emailsList, success, fail);
419
438
  }
420
439
 
421
440
  //Function: registerSMSNumber
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pushwoosh-react-native-plugin",
3
- "version": "6.1.58",
3
+ "version": "6.1.60",
4
4
  "description": "This plugin allows you to send and receive push notifications. Powered by Pushwoosh (www.pushwoosh.com).",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = "pushwoosh-react-native-plugin"
3
- s.version = "6.1.58"
3
+ s.version = "6.1.60"
4
4
  s.summary = "React Native Pushwoosh Push Notifications module"
5
5
  s.requires_arc = true
6
6
  s.author = 'Pushwoosh'
@@ -15,6 +15,6 @@ Pod::Spec.new do |s|
15
15
  s.static_framework = true
16
16
 
17
17
  s.dependency 'React'
18
- s.dependency 'PushwooshXCFramework', '7.0.36'
18
+ s.dependency 'PushwooshXCFramework', '7.2.5'
19
19
  s.dependency 'PushwooshInboxUIXCFramework'
20
20
  end
@@ -37,7 +37,7 @@ android {
37
37
  }
38
38
 
39
39
  ext {
40
- pushwoosh = "6.7.64"
40
+ pushwoosh = "6.11.1"
41
41
  }
42
42
 
43
43
  dependencies {
@@ -1,6 +1,6 @@
1
1
  # Add project specific ProGuard rules here.
2
2
  # By default, the flags in this file are appended to flags specified
3
- # in /Users/arellomobile/Library/Android/sdk/tools/proguard/proguard-android.txt
3
+ # in $HOME/Library/Android/sdk/tools/proguard/proguard-android.txt
4
4
  # You can edit the include path and order by changing the proguardFiles
5
5
  # directive in build.gradle.
6
6
  #
@@ -34,6 +34,40 @@ static id objectOrNull(id object) {
34
34
  }
35
35
  }
36
36
 
37
+ typedef void (^PWEmailsCompletion)(NSError *error);
38
+
39
+ // The SDK invokes the completion once per address, an RCTResponseSenderBlock only once:
40
+ // the first error wins, success is reported after the last address.
41
+ static PWEmailsCompletion emailsCompletionHandler(NSUInteger addressCount, RCTResponseSenderBlock successCallback, RCTResponseSenderBlock errorCallback) {
42
+ NSObject *lock = [NSObject new];
43
+ __block NSUInteger completedCount = 0;
44
+ __block BOOL responded = NO;
45
+
46
+ return ^(NSError *error) {
47
+ @synchronized (lock) {
48
+ if (responded) {
49
+ return;
50
+ }
51
+
52
+ if (error) {
53
+ responded = YES;
54
+ if (errorCallback) {
55
+ errorCallback(@[ objectOrNull([error localizedDescription]) ]);
56
+ }
57
+ return;
58
+ }
59
+
60
+ completedCount++;
61
+ if (completedCount >= addressCount) {
62
+ responded = YES;
63
+ if (successCallback) {
64
+ successCallback(@[]);
65
+ }
66
+ }
67
+ }
68
+ };
69
+ }
70
+
37
71
  static NSDictionary * gStartPushData = nil;
38
72
  static NSURL * gPushDeepLinkURL = nil; // Deep link URL for New Architecture support
39
73
  static NSString * const kRegistrationSuccesEvent = @"PWRegistrationSuccess";
@@ -44,6 +78,27 @@ static NSString * const kPushOpenEvent = @"PWPushOpen";
44
78
  static NSString * const kPushOpenJSEvent = @"pushOpened";
45
79
  static NSString * const kPushReceivedJSEvent = @"pushReceived";
46
80
 
81
+ /// Returns the push link only when it is a deep link this app can route itself, otherwise nil.
82
+ ///
83
+ /// http/https links are left to the native SDK: it checks the host's apple-app-site-association
84
+ /// and either hands the link to the app's Universal Links handler (own domain) or opens the
85
+ /// browser (anyone else's). Handing those to RCTLinking too made every external link land in JS
86
+ /// as if it were an in-app destination.
87
+ static NSURL * pwplugin_deepLinkURLFromPushLink(id link) {
88
+ if (![link isKindOfClass:[NSString class]] || [link length] == 0) {
89
+ return nil;
90
+ }
91
+
92
+ NSURL *url = [NSURL URLWithString:link];
93
+ NSString *scheme = url.scheme.lowercaseString;
94
+
95
+ if (scheme.length == 0 || [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
96
+ return nil;
97
+ }
98
+
99
+ return url;
100
+ }
101
+
47
102
  @interface PushwooshPlugin (InnerPushwooshPlugin)
48
103
 
49
104
  - (void) application:(UIApplication *)application pwplugin_didRegisterWithDeviceToken:(NSData *)deviceToken;
@@ -178,12 +233,12 @@ RCT_EXPORT_METHOD(init:(NSDictionary*)config success:(RCTResponseSenderBlock)suc
178
233
  }
179
234
 
180
235
  if (gStartPushData) {
181
- NSString *link = gStartPushData[@"l"];
182
-
236
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(gStartPushData[@"l"]);
237
+
183
238
  //get deeplink from the payload and write it to the launchOptions for proper RCTLinking behavior
184
- if (link) {
239
+ if (deepLink) {
185
240
  NSMutableDictionary *launchOptions = self.bridge.launchOptions.mutableCopy;
186
- launchOptions[UIApplicationLaunchOptionsURLKey] = [NSURL URLWithString:link];
241
+ launchOptions[UIApplicationLaunchOptionsURLKey] = deepLink;
187
242
  [self.bridge setValue:launchOptions forKey:@"launchOptions"];
188
243
  }
189
244
 
@@ -253,35 +308,34 @@ RCT_EXPORT_METHOD(getPushToken:(RCTResponseSenderBlock)callback) {
253
308
  }
254
309
 
255
310
  RCT_EXPORT_METHOD(setEmails:(NSArray *)emails success:(RCTResponseSenderBlock)successCallback error:(RCTResponseSenderBlock)errorCallback) {
256
- __block NSError* gError = nil;
257
- [[Pushwoosh sharedInstance] setEmails:emails completion:^(NSError * _Nullable error) {
258
- if (error) {
259
- gError = error;
311
+ if (emails.count == 0) {
312
+ // The SDK ignores an empty list without invoking the completion block.
313
+ if (errorCallback) {
314
+ errorCallback(@[ @"emails must be a non-empty array" ]);
260
315
  }
261
- }];
262
- if (!gError && successCallback) {
263
- successCallback(@[]);
264
- }
265
-
266
- if (gError && errorCallback) {
267
- errorCallback(@[ objectOrNull([gError localizedDescription]) ]);
316
+ return;
268
317
  }
318
+
319
+ [[Pushwoosh sharedInstance] setEmails:emails completion:emailsCompletionHandler(emails.count, successCallback, errorCallback)];
269
320
  }
270
321
 
271
322
  RCT_EXPORT_METHOD(setUserEmails:(NSString*)userId emails:(NSArray *)emails success:(RCTResponseSenderBlock)successCallback error:(RCTResponseSenderBlock)errorCallback) {
272
- __block NSError* gError = nil;
273
- [[Pushwoosh sharedInstance] setUser:userId emails:emails completion:^(NSError * _Nullable error) {
274
- if (error) {
275
- gError = error;
323
+ if (userId.length == 0) {
324
+ // The SDK ignores an empty user id without invoking the completion block.
325
+ if (errorCallback) {
326
+ errorCallback(@[ @"userId must not be empty" ]);
276
327
  }
277
- }];
278
- if (!gError && successCallback) {
279
- successCallback(@[]);
328
+ return;
280
329
  }
281
-
282
- if (gError && errorCallback) {
283
- errorCallback(@[ objectOrNull([gError localizedDescription]) ]);
330
+
331
+ if (emails.count == 0) {
332
+ if (errorCallback) {
333
+ errorCallback(@[ @"emails must be a non-empty array" ]);
334
+ }
335
+ return;
284
336
  }
337
+
338
+ [[Pushwoosh sharedInstance] setUser:userId emails:emails completion:emailsCompletionHandler(emails.count, successCallback, errorCallback)];
285
339
  }
286
340
 
287
341
  RCT_EXPORT_METHOD(setTags:(NSDictionary*)tags success:(RCTResponseSenderBlock)successCallback error:(RCTResponseSenderBlock)errorCallback) {
@@ -968,9 +1022,9 @@ RCT_EXPORT_METHOD(getRichMediaType:(RCTResponseSenderBlock)callback) {
968
1022
  if (onStart) {
969
1023
  gStartPushData = pushNotification;
970
1024
  // Save deep link URL for New Architecture (Linking.getInitialURL support)
971
- NSString *link = pushNotification[@"l"];
972
- if (link) {
973
- gPushDeepLinkURL = [NSURL URLWithString:link];
1025
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(pushNotification[@"l"]);
1026
+ if (deepLink) {
1027
+ gPushDeepLinkURL = deepLink;
974
1028
  }
975
1029
  }
976
1030
  }
@@ -978,9 +1032,9 @@ RCT_EXPORT_METHOD(getRichMediaType:(RCTResponseSenderBlock)callback) {
978
1032
  if (onStart) {
979
1033
  gStartPushData = pushNotification;
980
1034
  // Save deep link URL for New Architecture (Linking.getInitialURL support)
981
- NSString *link = pushNotification[@"l"];
982
- if (link) {
983
- gPushDeepLinkURL = [NSURL URLWithString:link];
1035
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(pushNotification[@"l"]);
1036
+ if (deepLink) {
1037
+ gPushDeepLinkURL = deepLink;
984
1038
  }
985
1039
  }
986
1040
  }
@@ -1007,9 +1061,9 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
1007
1061
  // Capture deep link from push notification on cold start
1008
1062
  if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
1009
1063
  NSDictionary *userInfo = response.notification.request.content.userInfo;
1010
- NSString *link = userInfo[@"l"];
1011
- if (link) {
1012
- gPushDeepLinkURL = [NSURL URLWithString:link];
1064
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(userInfo[@"l"]);
1065
+ if (deepLink) {
1066
+ gPushDeepLinkURL = deepLink;
1013
1067
  }
1014
1068
  }
1015
1069
 
@@ -1068,9 +1122,9 @@ static PWEarlyNotificationDelegate *gEarlyDelegate = nil;
1068
1122
  NSDictionary *launchOptions = notification.userInfo;
1069
1123
  NSDictionary *remoteNotification = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
1070
1124
  if (remoteNotification) {
1071
- NSString *link = remoteNotification[@"l"];
1072
- if (link && !gPushDeepLinkURL) {
1073
- gPushDeepLinkURL = [NSURL URLWithString:link];
1125
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(remoteNotification[@"l"]);
1126
+ if (deepLink && !gPushDeepLinkURL) {
1127
+ gPushDeepLinkURL = deepLink;
1074
1128
  }
1075
1129
  }
1076
1130
  }];
File without changes
File without changes