pushwoosh-react-native-plugin 6.1.59 → 6.1.61

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pushwoosh-react-native-plugin",
3
- "version": "6.1.59",
3
+ "version": "6.1.61",
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.59"
3
+ s.version = "6.1.61"
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.2.3'
18
+ s.dependency 'PushwooshXCFramework', '7.2.6'
19
19
  s.dependency 'PushwooshInboxUIXCFramework'
20
20
  end
@@ -37,7 +37,7 @@ android {
37
37
  }
38
38
 
39
39
  ext {
40
- pushwoosh = "6.10.2"
40
+ pushwoosh = "6.12.0"
41
41
  }
42
42
 
43
43
  dependencies {
@@ -49,6 +49,9 @@ dependencies {
49
49
  implementation "com.pushwoosh:pushwoosh-badge:${pushwoosh}"
50
50
  implementation "com.pushwoosh:pushwoosh-inbox:${pushwoosh}"
51
51
  implementation "com.pushwoosh:pushwoosh-inbox-ui:${pushwoosh}"
52
+ // InboxActivity calls androidx.activity.EdgeToEdge, added in 1.8.0; inbox-ui itself
53
+ // resolves 1.6.0, so the inbox screen dies with ClassNotFoundException without this
54
+ implementation "androidx.activity:activity:1.8.0"
52
55
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22"
53
56
  implementation "com.google.firebase:firebase-messaging:23.1.0"
54
57
  }
@@ -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
  #
@@ -70,6 +70,7 @@ static PWEmailsCompletion emailsCompletionHandler(NSUInteger addressCount, RCTRe
70
70
 
71
71
  static NSDictionary * gStartPushData = nil;
72
72
  static NSURL * gPushDeepLinkURL = nil; // Deep link URL for New Architecture support
73
+ static NSString * gEarlyHandledHash = nil; // Last push hash the cold-start delegate accepted, to avoid double handling
73
74
  static NSString * const kRegistrationSuccesEvent = @"PWRegistrationSuccess";
74
75
  static NSString * const kRegistrationErrorEvent = @"PWRegistrationError";
75
76
  static NSString * const kPushReceivedEvent = @"PWPushReceived";
@@ -78,6 +79,38 @@ static NSString * const kPushOpenEvent = @"PWPushOpen";
78
79
  static NSString * const kPushOpenJSEvent = @"pushOpened";
79
80
  static NSString * const kPushReceivedJSEvent = @"pushReceived";
80
81
 
82
+ /// Returns the push link only when it is a deep link this app can route itself, otherwise nil.
83
+ ///
84
+ /// http/https links are left to the native SDK: it checks the host's apple-app-site-association
85
+ /// and either hands the link to the app's Universal Links handler (own domain) or opens the
86
+ /// browser (anyone else's). Handing those to RCTLinking too made every external link land in JS
87
+ /// as if it were an in-app destination.
88
+ static NSURL * pwplugin_deepLinkURLFromPushLink(id link) {
89
+ if (![link isKindOfClass:[NSString class]] || [link length] == 0) {
90
+ return nil;
91
+ }
92
+
93
+ NSURL *url = [NSURL URLWithString:link];
94
+ NSString *scheme = url.scheme.lowercaseString;
95
+
96
+ if (scheme.length == 0 || [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
97
+ return nil;
98
+ }
99
+
100
+ return url;
101
+ }
102
+
103
+ // Bridgeless hands a module an RCTBridgeProxy: an NSProxy that carries none of NSObject's KVC and
104
+ // turns an unknown selector into a logged no-op. object_getClass asks without messaging it.
105
+ static BOOL pwplugin_isRealBridge(id bridge) {
106
+ if (bridge == nil) {
107
+ return NO;
108
+ }
109
+
110
+ Class bridgeProxyClass = NSClassFromString(@"RCTBridgeProxy");
111
+ return bridgeProxyClass == nil || object_getClass(bridge) != bridgeProxyClass;
112
+ }
113
+
81
114
  @interface PushwooshPlugin (InnerPushwooshPlugin)
82
115
 
83
116
  - (void) application:(UIApplication *)application pwplugin_didRegisterWithDeviceToken:(NSData *)deviceToken;
@@ -146,6 +179,12 @@ RCT_EXPORT_MODULE(Pushwoosh);
146
179
  return dispatch_get_main_queue();
147
180
  }
148
181
 
182
+ // Overriding init makes React Native infer main queue setup on its own; saying so keeps that
183
+ // contract explicit, since the module claims the notification center delegate right away.
184
+ + (BOOL)requiresMainQueueSetup {
185
+ return YES;
186
+ }
187
+
149
188
  + (NSString *)getPluginImplementationInfoPlistKey {
150
189
  return [[NSBundle mainBundle] objectForInfoDictionaryKey:kPushwooshPluginImplementationInfoPlistKey];
151
190
  }
@@ -212,13 +251,20 @@ RCT_EXPORT_METHOD(init:(NSDictionary*)config success:(RCTResponseSenderBlock)suc
212
251
  }
213
252
 
214
253
  if (gStartPushData) {
215
- NSString *link = gStartPushData[@"l"];
216
-
217
- //get deeplink from the payload and write it to the launchOptions for proper RCTLinking behavior
218
- if (link) {
219
- NSMutableDictionary *launchOptions = self.bridge.launchOptions.mutableCopy;
220
- launchOptions[UIApplicationLaunchOptionsURLKey] = [NSURL URLWithString:link];
221
- [self.bridge setValue:launchOptions forKey:@"launchOptions"];
254
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(gStartPushData[@"l"]);
255
+
256
+ if (deepLink) {
257
+ if (!gPushDeepLinkURL) {
258
+ gPushDeepLinkURL = deepLink;
259
+ }
260
+
261
+ // Writing the link into launchOptions is what makes RCTLinking report it, but only a
262
+ // real bridge accepts the write. Bridgeless reads it from the swizzled getInitialURL.
263
+ if (pwplugin_isRealBridge(self.bridge)) {
264
+ NSMutableDictionary *launchOptions = self.bridge.launchOptions.mutableCopy;
265
+ launchOptions[UIApplicationLaunchOptionsURLKey] = deepLink;
266
+ [self.bridge setValue:launchOptions forKey:@"launchOptions"];
267
+ }
222
268
  }
223
269
 
224
270
  [self sendJSEvent:kPushReceivedJSEvent withArgs:gStartPushData];
@@ -979,9 +1025,15 @@ RCT_EXPORT_METHOD(getRichMediaType:(RCTResponseSenderBlock)callback) {
979
1025
 
980
1026
  #pragma mark - RCTEventEmitter
981
1027
 
1028
+ // RCTEventEmitter withholds events until JS subscribes through NativeEventEmitter, which is what
1029
+ // raises its listener count. The plugin's public API is DeviceEventEmitter, which never raises it,
1030
+ // so observation stays off and every event goes out.
1031
+ - (instancetype)init {
1032
+ return [super initWithDisabledObservation];
1033
+ }
1034
+
982
1035
  - (void)sendJSEvent:(NSString*)event withArgs:(NSDictionary*)args {
983
- // [self sendEventWithName:event body:args];
984
- [self.bridge.eventDispatcher sendDeviceEventWithName:event body:args];
1036
+ [self sendEventWithName:event body:args];
985
1037
  }
986
1038
 
987
1039
  - (NSArray<NSString *> *)supportedEvents {
@@ -1001,9 +1053,9 @@ RCT_EXPORT_METHOD(getRichMediaType:(RCTResponseSenderBlock)callback) {
1001
1053
  if (onStart) {
1002
1054
  gStartPushData = pushNotification;
1003
1055
  // Save deep link URL for New Architecture (Linking.getInitialURL support)
1004
- NSString *link = pushNotification[@"l"];
1005
- if (link) {
1006
- gPushDeepLinkURL = [NSURL URLWithString:link];
1056
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(pushNotification[@"l"]);
1057
+ if (deepLink) {
1058
+ gPushDeepLinkURL = deepLink;
1007
1059
  }
1008
1060
  }
1009
1061
  }
@@ -1011,9 +1063,9 @@ RCT_EXPORT_METHOD(getRichMediaType:(RCTResponseSenderBlock)callback) {
1011
1063
  if (onStart) {
1012
1064
  gStartPushData = pushNotification;
1013
1065
  // Save deep link URL for New Architecture (Linking.getInitialURL support)
1014
- NSString *link = pushNotification[@"l"];
1015
- if (link) {
1016
- gPushDeepLinkURL = [NSURL URLWithString:link];
1066
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(pushNotification[@"l"]);
1067
+ if (deepLink) {
1068
+ gPushDeepLinkURL = deepLink;
1017
1069
  }
1018
1070
  }
1019
1071
  }
@@ -1032,17 +1084,45 @@ API_AVAILABLE(ios(10.0))
1032
1084
  @property (nonatomic, weak) id<UNUserNotificationCenterDelegate> originalDelegate;
1033
1085
  @end
1034
1086
 
1087
+ // PLUGIN_NOTIFICATION_HANDLER suppresses the native delegate, and the plugin's own delegate is
1088
+ // installed in JS init — too late for a cold start, so nobody accepts the launch push. Both early
1089
+ // hooks below call this; the push hash keeps the second one from repeating it.
1090
+ static void pwplugin_acceptColdStartPushOnce(NSDictionary *userInfo) {
1091
+ if (![userInfo isKindOfClass:[NSDictionary class]]) {
1092
+ return;
1093
+ }
1094
+ if (![[[NSBundle mainBundle] objectForInfoDictionaryKey:kPushwooshPluginImplementationInfoPlistKey] boolValue]) {
1095
+ return;
1096
+ }
1097
+ if (![PWMessage isPushwooshMessage:userInfo]) {
1098
+ return;
1099
+ }
1100
+
1101
+ NSString *hash = userInfo[@"p"];
1102
+ if ([hash isKindOfClass:[NSString class]]) {
1103
+ if ([gEarlyHandledHash isEqualToString:hash]) {
1104
+ return;
1105
+ }
1106
+ gEarlyHandledHash = hash;
1107
+ }
1108
+
1109
+ [[PushNotificationManager pushManager] handlePushAccepted:userInfo onStart:YES];
1110
+ }
1111
+
1035
1112
  @implementation PWEarlyNotificationDelegate
1036
1113
 
1037
1114
  - (void)userNotificationCenter:(UNUserNotificationCenter *)center
1038
1115
  didReceiveNotificationResponse:(UNNotificationResponse *)response
1039
1116
  withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0)) {
1040
- // Capture deep link from push notification on cold start
1041
1117
  if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
1042
1118
  NSDictionary *userInfo = response.notification.request.content.userInfo;
1043
- NSString *link = userInfo[@"l"];
1044
- if (link) {
1045
- gPushDeepLinkURL = [NSURL URLWithString:link];
1119
+ NSURL *appSchemeDeepLink = pwplugin_deepLinkURLFromPushLink(userInfo[@"l"]);
1120
+
1121
+ if (appSchemeDeepLink) {
1122
+ // Routing it through the SDK too would deliver the deep link twice.
1123
+ gPushDeepLinkURL = appSchemeDeepLink;
1124
+ } else {
1125
+ pwplugin_acceptColdStartPushOnce(userInfo);
1046
1126
  }
1047
1127
  }
1048
1128
 
@@ -1101,9 +1181,13 @@ static PWEarlyNotificationDelegate *gEarlyDelegate = nil;
1101
1181
  NSDictionary *launchOptions = notification.userInfo;
1102
1182
  NSDictionary *remoteNotification = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
1103
1183
  if (remoteNotification) {
1104
- NSString *link = remoteNotification[@"l"];
1105
- if (link && !gPushDeepLinkURL) {
1106
- gPushDeepLinkURL = [NSURL URLWithString:link];
1184
+ NSURL *deepLink = pwplugin_deepLinkURLFromPushLink(remoteNotification[@"l"]);
1185
+ if (deepLink) {
1186
+ if (!gPushDeepLinkURL) {
1187
+ gPushDeepLinkURL = deepLink;
1188
+ }
1189
+ } else {
1190
+ pwplugin_acceptColdStartPushOnce(remoteNotification);
1107
1191
  }
1108
1192
  }
1109
1193
  }];
File without changes
File without changes