react-native-push-signal 0.1.6 → 0.1.8

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.
Files changed (97) hide show
  1. package/LICENSE +1 -1
  2. package/PushSignal.podspec +2 -12
  3. package/README.md +1 -3
  4. package/README.ru.md +1 -3
  5. package/android/build.gradle +1 -62
  6. package/android/consumer-rules.pro +3 -3
  7. package/android/src/main/AndroidManifest.xml +2 -2
  8. package/android/src/main/java/com/pushsignal/PushModels.kt +15 -0
  9. package/android/src/main/java/com/{margelo/nitro/pushsignal → pushsignal}/PushSignalCenter.kt +2 -3
  10. package/android/src/main/java/com/{margelo/nitro/pushsignal → pushsignal}/PushSignalInitProvider.kt +1 -1
  11. package/android/src/main/java/com/{margelo/nitro/pushsignal → pushsignal}/PushSignalMessagingService.kt +1 -1
  12. package/android/src/main/java/com/pushsignal/PushSignalModule.kt +88 -0
  13. package/android/src/main/java/com/pushsignal/PushSignalPackage.kt +30 -0
  14. package/ios/PushSignal.h +4 -0
  15. package/ios/PushSignal.mm +57 -0
  16. package/ios/PushSignalCenter.h +26 -0
  17. package/ios/PushSignalCenter.m +583 -0
  18. package/ios/PushSignalLaunchStore.m +3 -14
  19. package/lib/module/NativePushSignal.js +5 -0
  20. package/lib/module/NativePushSignal.js.map +1 -0
  21. package/lib/module/pushSignal.native.js +33 -7
  22. package/lib/module/pushSignal.native.js.map +1 -1
  23. package/lib/module/types.js +2 -0
  24. package/lib/module/types.js.map +1 -0
  25. package/lib/typescript/src/NativePushSignal.d.ts +22 -0
  26. package/lib/typescript/src/NativePushSignal.d.ts.map +1 -0
  27. package/lib/typescript/src/index.d.ts +1 -1
  28. package/lib/typescript/src/index.d.ts.map +1 -1
  29. package/lib/typescript/src/pushSignal.d.ts +1 -1
  30. package/lib/typescript/src/pushSignal.d.ts.map +1 -1
  31. package/lib/typescript/src/pushSignal.native.d.ts +1 -1
  32. package/lib/typescript/src/pushSignal.native.d.ts.map +1 -1
  33. package/lib/typescript/src/{PushSignal.nitro.d.ts → types.d.ts} +2 -12
  34. package/lib/typescript/src/types.d.ts.map +1 -0
  35. package/package.json +14 -19
  36. package/src/NativePushSignal.ts +25 -0
  37. package/src/index.tsx +1 -1
  38. package/src/pushSignal.native.tsx +54 -11
  39. package/src/pushSignal.tsx +1 -1
  40. package/src/types.ts +25 -0
  41. package/android/CMakeLists.txt +0 -24
  42. package/android/src/main/cpp/cpp-adapter.cpp +0 -11
  43. package/android/src/main/java/com/margelo/nitro/pushsignal/PushSignal.kt +0 -38
  44. package/android/src/main/java/com/margelo/nitro/pushsignal/PushSignalPackage.kt +0 -22
  45. package/ios/PushSignal.swift +0 -29
  46. package/ios/PushSignalCenter.swift +0 -604
  47. package/lib/module/PushSignal.nitro.js +0 -4
  48. package/lib/module/PushSignal.nitro.js.map +0 -1
  49. package/lib/typescript/src/PushSignal.nitro.d.ts.map +0 -1
  50. package/nitro.json +0 -23
  51. package/nitrogen/generated/android/c++/JAndroidFirebaseConfig.hpp +0 -70
  52. package/nitrogen/generated/android/c++/JFunc_void_PushMessage.hpp +0 -80
  53. package/nitrogen/generated/android/c++/JHybridPushSignalSpec.cpp +0 -114
  54. package/nitrogen/generated/android/c++/JHybridPushSignalSpec.hpp +0 -66
  55. package/nitrogen/generated/android/c++/JPushCredentials.hpp +0 -70
  56. package/nitrogen/generated/android/c++/JPushEnvironment.hpp +0 -58
  57. package/nitrogen/generated/android/c++/JPushMessage.hpp +0 -84
  58. package/nitrogen/generated/android/c++/JPushPlatform.hpp +0 -58
  59. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/AndroidFirebaseConfig.kt +0 -66
  60. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/Func_void_PushMessage.kt +0 -78
  61. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/HybridPushSignalSpec.kt +0 -79
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/PushCredentials.kt +0 -61
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/PushEnvironment.kt +0 -23
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/PushMessage.kt +0 -66
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/PushPlatform.kt +0 -23
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/pushsignalOnLoad.kt +0 -35
  67. package/nitrogen/generated/android/pushsignal+autolinking.cmake +0 -81
  68. package/nitrogen/generated/android/pushsignal+autolinking.gradle +0 -27
  69. package/nitrogen/generated/android/pushsignalOnLoad.cpp +0 -56
  70. package/nitrogen/generated/android/pushsignalOnLoad.hpp +0 -34
  71. package/nitrogen/generated/ios/PushSignal+autolinking.rb +0 -62
  72. package/nitrogen/generated/ios/PushSignal-Swift-Cxx-Bridge.cpp +0 -65
  73. package/nitrogen/generated/ios/PushSignal-Swift-Cxx-Bridge.hpp +0 -254
  74. package/nitrogen/generated/ios/PushSignal-Swift-Cxx-Umbrella.hpp +0 -63
  75. package/nitrogen/generated/ios/PushSignalAutolinking.mm +0 -33
  76. package/nitrogen/generated/ios/PushSignalAutolinking.swift +0 -26
  77. package/nitrogen/generated/ios/c++/HybridPushSignalSpecSwift.cpp +0 -11
  78. package/nitrogen/generated/ios/c++/HybridPushSignalSpecSwift.hpp +0 -120
  79. package/nitrogen/generated/ios/swift/AndroidFirebaseConfig.swift +0 -96
  80. package/nitrogen/generated/ios/swift/Func_void.swift +0 -46
  81. package/nitrogen/generated/ios/swift/Func_void_PushCredentials.swift +0 -46
  82. package/nitrogen/generated/ios/swift/Func_void_PushMessage.swift +0 -46
  83. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +0 -46
  84. package/nitrogen/generated/ios/swift/HybridPushSignalSpec.swift +0 -58
  85. package/nitrogen/generated/ios/swift/HybridPushSignalSpec_cxx.swift +0 -196
  86. package/nitrogen/generated/ios/swift/PushCredentials.swift +0 -45
  87. package/nitrogen/generated/ios/swift/PushEnvironment.swift +0 -40
  88. package/nitrogen/generated/ios/swift/PushMessage.swift +0 -97
  89. package/nitrogen/generated/ios/swift/PushPlatform.swift +0 -40
  90. package/nitrogen/generated/shared/c++/AndroidFirebaseConfig.hpp +0 -96
  91. package/nitrogen/generated/shared/c++/HybridPushSignalSpec.cpp +0 -24
  92. package/nitrogen/generated/shared/c++/HybridPushSignalSpec.hpp +0 -74
  93. package/nitrogen/generated/shared/c++/PushCredentials.hpp +0 -97
  94. package/nitrogen/generated/shared/c++/PushEnvironment.hpp +0 -76
  95. package/nitrogen/generated/shared/c++/PushMessage.hpp +0 -97
  96. package/nitrogen/generated/shared/c++/PushPlatform.hpp +0 -76
  97. package/src/PushSignal.nitro.ts +0 -39
@@ -0,0 +1,583 @@
1
+ #import "PushSignalCenter.h"
2
+ #import "PushSignalLaunchStore.h"
3
+ #import <objc/runtime.h>
4
+ #import <UIKit/UIKit.h>
5
+
6
+ @interface PushSignalAppDelegateHook : NSObject
7
+ @end
8
+
9
+ @interface UNUserNotificationCenter (PushSignal)
10
+ - (void)pushSignal_setDelegate:(id<UNUserNotificationCenterDelegate>)delegate;
11
+ @end
12
+
13
+ @implementation PushSignalCenter {
14
+ NSLock *_lock;
15
+ BOOL _didInstall;
16
+ BOOL _didSwizzleAppDelegate;
17
+ BOOL _didSwizzleNotificationCenter;
18
+ NSString *_deviceToken;
19
+ NSError *_registrationError;
20
+ NSMutableArray<void (^)(NSString *_Nullable, NSError *_Nullable)> *_tokenWaiters;
21
+ NSDictionary *_pendingPress;
22
+ NSMutableArray<NSDictionary *> *_pendingMessages;
23
+ NSDictionary *_pendingLaunchOptions;
24
+ BOOL _didCaptureLaunchNotification;
25
+ NSMutableDictionary<NSString *, NSDate *> *_recentMessageIds;
26
+ __weak id<UNUserNotificationCenterDelegate> _forwardingDelegate;
27
+ void (^_onMessage)(NSDictionary *);
28
+ void (^_onNotificationPress)(NSDictionary *);
29
+ }
30
+
31
+ + (instancetype)shared {
32
+ static PushSignalCenter *sharedInstance = nil;
33
+ static dispatch_once_t onceToken;
34
+ dispatch_once(&onceToken, ^{
35
+ sharedInstance = [[PushSignalCenter alloc] init];
36
+ });
37
+ return sharedInstance;
38
+ }
39
+
40
+ + (void)installEarly {
41
+ [[PushSignalCenter shared] install];
42
+ }
43
+
44
+ + (void)bootstrapWithLaunchOptions:(NSDictionary *)launchOptions {
45
+ PushSignalCenter *center = [PushSignalCenter shared];
46
+ center->_pendingLaunchOptions = [launchOptions copy];
47
+ [center install];
48
+ }
49
+
50
+ - (instancetype)init {
51
+ if (self = [super init]) {
52
+ _lock = [[NSLock alloc] init];
53
+ _tokenWaiters = [NSMutableArray array];
54
+ _pendingMessages = [NSMutableArray array];
55
+ _recentMessageIds = [NSMutableDictionary dictionary];
56
+ }
57
+ return self;
58
+ }
59
+
60
+ - (void)install {
61
+ if ([NSThread isMainThread]) {
62
+ [self installOnMain];
63
+ } else {
64
+ dispatch_async(dispatch_get_main_queue(), ^{
65
+ [self installOnMain];
66
+ });
67
+ }
68
+ }
69
+
70
+ - (void)installOnMain {
71
+ [self swizzleNotificationCenterDelegateIfNeeded];
72
+
73
+ if (_didInstall) {
74
+ [UNUserNotificationCenter currentNotificationCenter].delegate = self;
75
+ [self swizzleAppDelegate];
76
+ [self captureLaunchNotificationIfNeeded];
77
+ return;
78
+ }
79
+
80
+ _didInstall = YES;
81
+ [UNUserNotificationCenter currentNotificationCenter].delegate = self;
82
+ [self swizzleAppDelegate];
83
+ [self captureLaunchNotificationIfNeeded];
84
+ }
85
+
86
+ - (void)rememberForwardingDelegate:(id<UNUserNotificationCenterDelegate>)delegate {
87
+ if (delegate != nil && delegate != self) {
88
+ _forwardingDelegate = delegate;
89
+ }
90
+ }
91
+
92
+ - (void)setOnMessage:(void (^)(NSDictionary *))callback {
93
+ _onMessage = [callback copy];
94
+ [self flushPendingMessages];
95
+ }
96
+
97
+ - (void)setOnNotificationPress:(void (^)(NSDictionary *))callback {
98
+ _onNotificationPress = [callback copy];
99
+ [self flushPendingPress];
100
+ }
101
+
102
+ - (void)fetchCredentialsWithResolver:(void (^)(NSDictionary *))resolve
103
+ rejecter:(void (^)(NSError *))reject {
104
+ dispatch_async(dispatch_get_main_queue(), ^{
105
+ [self installOnMain];
106
+ [[UIApplication sharedApplication] registerForRemoteNotifications];
107
+
108
+ [self waitForTokenWithCompletion:^(NSString *token, NSError *error) {
109
+ if (error != nil) {
110
+ reject(error);
111
+ return;
112
+ }
113
+ NSMutableDictionary *credentials = [NSMutableDictionary dictionary];
114
+ credentials[@"platform"] = @"ios";
115
+ credentials[@"token"] = token ?: @"";
116
+ credentials[@"environment"] = [self currentEnvironment];
117
+ resolve(credentials);
118
+ }];
119
+ });
120
+ }
121
+
122
+ - (void)handleDeviceToken:(NSData *)deviceToken {
123
+ const unsigned char *bytes = (const unsigned char *)deviceToken.bytes;
124
+ NSMutableString *token = [NSMutableString stringWithCapacity:deviceToken.length * 2];
125
+ for (NSUInteger i = 0; i < deviceToken.length; i++) {
126
+ [token appendFormat:@"%02x", bytes[i]];
127
+ }
128
+ [self finishRegistrationWithToken:token error:nil];
129
+ }
130
+
131
+ - (void)handleRegistrationError:(NSError *)error {
132
+ [self finishRegistrationWithToken:nil error:error];
133
+ }
134
+
135
+ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
136
+ willPresentNotification:(UNNotification *)notification
137
+ withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
138
+ [self deliverMessage:[PushSignalCenter messageFromNotification:notification]];
139
+ [self forwardWillPresent:center
140
+ notification:notification
141
+ ourOptions:[PushSignalCenter foregroundPresentationOptions]
142
+ completionHandler:completionHandler];
143
+ }
144
+
145
+ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
146
+ didReceiveNotificationResponse:(UNNotificationResponse *)response
147
+ withCompletionHandler:(void (^)(void))completionHandler {
148
+ [self emitPress:[PushSignalCenter messageFromNotification:response.notification]];
149
+ SEL selector = @selector(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:);
150
+ id<UNUserNotificationCenterDelegate> forwarding = _forwardingDelegate;
151
+ if (forwarding != nil && [forwarding respondsToSelector:selector]) {
152
+ [forwarding userNotificationCenter:center
153
+ didReceiveNotificationResponse:response
154
+ withCompletionHandler:completionHandler];
155
+ } else {
156
+ completionHandler();
157
+ }
158
+ }
159
+
160
+ #pragma mark - Token
161
+
162
+ - (void)waitForTokenWithCompletion:(void (^)(NSString *_Nullable, NSError *_Nullable))completion {
163
+ [_lock lock];
164
+ if (_deviceToken != nil) {
165
+ NSString *token = _deviceToken;
166
+ [_lock unlock];
167
+ completion(token, nil);
168
+ return;
169
+ }
170
+ if (_registrationError != nil) {
171
+ NSError *error = _registrationError;
172
+ [_lock unlock];
173
+ completion(nil, error);
174
+ return;
175
+ }
176
+ [_tokenWaiters addObject:[completion copy]];
177
+ [_lock unlock];
178
+
179
+ __weak PushSignalCenter *weakSelf = self;
180
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
181
+ NSError *timeout = [NSError errorWithDomain:@"PushSignal"
182
+ code:1
183
+ userInfo:@{
184
+ NSLocalizedDescriptionKey :
185
+ @"APNs registration timed out. Use a physical iOS device and enable the Push Notifications capability."
186
+ }];
187
+ [weakSelf finishRegistrationWithToken:nil error:timeout];
188
+ });
189
+ }
190
+
191
+ - (void)finishRegistrationWithToken:(NSString *)token error:(NSError *)error {
192
+ [_lock lock];
193
+ if (token != nil) {
194
+ _deviceToken = token;
195
+ _registrationError = nil;
196
+ } else if (_deviceToken == nil) {
197
+ _registrationError = error;
198
+ }
199
+ NSArray *waiters = [_tokenWaiters copy];
200
+ [_tokenWaiters removeAllObjects];
201
+ [_lock unlock];
202
+
203
+ for (void (^waiter)(NSString *, NSError *) in waiters) {
204
+ waiter(token, error);
205
+ }
206
+ }
207
+
208
+ #pragma mark - Messages
209
+
210
+ - (void)deliverMessage:(NSDictionary *)message {
211
+ if (![self shouldEmit:message]) {
212
+ return;
213
+ }
214
+
215
+ void (^callback)(NSDictionary *) = nil;
216
+ [_lock lock];
217
+ callback = _onMessage;
218
+ if (callback == nil) {
219
+ [_pendingMessages addObject:message];
220
+ [_lock unlock];
221
+ return;
222
+ }
223
+ [_lock unlock];
224
+
225
+ [self emitToJs:callback message:message];
226
+ }
227
+
228
+ - (void)emitToJs:(void (^)(NSDictionary *))callback message:(NSDictionary *)message {
229
+ dispatch_async(dispatch_get_main_queue(), ^{
230
+ callback(message);
231
+ });
232
+ }
233
+
234
+ - (void)flushPendingMessages {
235
+ dispatch_async(dispatch_get_main_queue(), ^{
236
+ void (^callback)(NSDictionary *) = nil;
237
+ NSArray<NSDictionary *> *queued = nil;
238
+ [self->_lock lock];
239
+ callback = self->_onMessage;
240
+ queued = [self->_pendingMessages copy];
241
+ [self->_pendingMessages removeAllObjects];
242
+ [self->_lock unlock];
243
+
244
+ if (callback == nil || queued.count == 0) {
245
+ return;
246
+ }
247
+ for (NSDictionary *message in queued) {
248
+ [self emitToJs:callback message:message];
249
+ }
250
+ });
251
+ }
252
+
253
+ - (BOOL)shouldEmit:(NSDictionary *)message {
254
+ NSString *messageId = message[@"id"];
255
+ NSString *title = message[@"title"] ?: @"";
256
+ NSString *body = message[@"body"] ?: @"";
257
+ NSString *key = messageId ?: [NSString stringWithFormat:@"%@|%@", title, body];
258
+
259
+ [_lock lock];
260
+ NSDate *now = [NSDate date];
261
+ NSMutableArray<NSString *> *expired = [NSMutableArray array];
262
+ [_recentMessageIds enumerateKeysAndObjectsUsingBlock:^(NSString *k, NSDate *date, BOOL *stop) {
263
+ if ([now timeIntervalSinceDate:date] >= 5) {
264
+ [expired addObject:k];
265
+ }
266
+ }];
267
+ [_recentMessageIds removeObjectsForKeys:expired];
268
+
269
+ NSDate *last = _recentMessageIds[key];
270
+ if (last != nil && [now timeIntervalSinceDate:last] < 2) {
271
+ [_lock unlock];
272
+ return NO;
273
+ }
274
+ _recentMessageIds[key] = now;
275
+ [_lock unlock];
276
+ return YES;
277
+ }
278
+
279
+ - (void)forwardWillPresent:(UNUserNotificationCenter *)center
280
+ notification:(UNNotification *)notification
281
+ ourOptions:(UNNotificationPresentationOptions)ourOptions
282
+ completionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
283
+ SEL selector = @selector(userNotificationCenter:willPresentNotification:withCompletionHandler:);
284
+ id<UNUserNotificationCenterDelegate> forwarding = _forwardingDelegate;
285
+ if (forwarding == nil || ![forwarding respondsToSelector:selector]) {
286
+ completionHandler(ourOptions);
287
+ return;
288
+ }
289
+
290
+ [forwarding userNotificationCenter:center
291
+ willPresentNotification:notification
292
+ withCompletionHandler:^(UNNotificationPresentationOptions forwarded) {
293
+ completionHandler(ourOptions | forwarded);
294
+ }];
295
+ }
296
+
297
+ + (UNNotificationPresentationOptions)foregroundPresentationOptions {
298
+ if (@available(iOS 14.0, *)) {
299
+ return UNNotificationPresentationOptionBanner | UNNotificationPresentationOptionList |
300
+ UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBadge;
301
+ }
302
+ return UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound |
303
+ UNNotificationPresentationOptionBadge;
304
+ }
305
+
306
+ - (void)emitPress:(NSDictionary *)message {
307
+ dispatch_async(dispatch_get_main_queue(), ^{
308
+ if (self->_onNotificationPress != nil) {
309
+ self->_onNotificationPress(message);
310
+ } else {
311
+ self->_pendingPress = message;
312
+ }
313
+ });
314
+ }
315
+
316
+ - (void)flushPendingPress {
317
+ dispatch_async(dispatch_get_main_queue(), ^{
318
+ if (self->_pendingPress == nil || self->_onNotificationPress == nil) {
319
+ return;
320
+ }
321
+ NSDictionary *pending = self->_pendingPress;
322
+ self->_pendingPress = nil;
323
+ self->_onNotificationPress(pending);
324
+ });
325
+ }
326
+
327
+ - (void)captureLaunchNotificationIfNeeded {
328
+ if (_didCaptureLaunchNotification) {
329
+ return;
330
+ }
331
+
332
+ if (_pendingLaunchOptions == nil) {
333
+ _pendingLaunchOptions = PushSignalCopyLaunchOptions();
334
+ }
335
+
336
+ NSDictionary *launchOptions = _pendingLaunchOptions;
337
+ if (launchOptions == nil) {
338
+ return;
339
+ }
340
+
341
+ _didCaptureLaunchNotification = YES;
342
+
343
+ id payload = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
344
+ if (![payload isKindOfClass:[NSDictionary class]]) {
345
+ return;
346
+ }
347
+
348
+ [self emitPress:[PushSignalCenter messageFromUserInfo:payload
349
+ fallbackId:@"launch"
350
+ title:nil
351
+ body:nil]];
352
+ }
353
+
354
+ - (NSString *)currentEnvironment {
355
+ NSString *environment = [PushSignalCenter apsEnvironment];
356
+ if (environment != nil) {
357
+ return environment;
358
+ }
359
+ #if DEBUG
360
+ return @"sandbox";
361
+ #else
362
+ return @"production";
363
+ #endif
364
+ }
365
+
366
+ + (nullable NSString *)apsEnvironment {
367
+ NSURL *url = [[NSBundle mainBundle] URLForResource:@"embedded" withExtension:@"mobileprovision"];
368
+ if (url == nil) {
369
+ return nil;
370
+ }
371
+ NSData *data = [NSData dataWithContentsOfURL:url];
372
+ if (data == nil) {
373
+ return nil;
374
+ }
375
+ NSString *contents = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
376
+ if (contents == nil) {
377
+ return nil;
378
+ }
379
+
380
+ NSRegularExpression *regex =
381
+ [NSRegularExpression regularExpressionWithPattern:@"<key>aps-environment</key>\\s*<string>(\\w+)</string>"
382
+ options:0
383
+ error:nil];
384
+ NSTextCheckingResult *match =
385
+ [regex firstMatchInString:contents options:0 range:NSMakeRange(0, contents.length)];
386
+ if (match == nil || match.numberOfRanges < 2) {
387
+ return nil;
388
+ }
389
+
390
+ NSString *value = [contents substringWithRange:[match rangeAtIndex:1]];
391
+ if ([value isEqualToString:@"development"]) {
392
+ return @"sandbox";
393
+ }
394
+ if ([value isEqualToString:@"production"]) {
395
+ return @"production";
396
+ }
397
+ return nil;
398
+ }
399
+
400
+ + (NSDictionary *)messageFromNotification:(UNNotification *)notification {
401
+ UNNotificationContent *content = notification.request.content;
402
+ return [self messageFromUserInfo:content.userInfo
403
+ fallbackId:notification.request.identifier
404
+ title:content.title.length > 0 ? content.title : nil
405
+ body:content.body.length > 0 ? content.body : nil];
406
+ }
407
+
408
+ + (NSDictionary *)messageFromUserInfo:(NSDictionary *)userInfo
409
+ fallbackId:(NSString *)fallbackId
410
+ title:(NSString *)title
411
+ body:(NSString *)body {
412
+ id aps = userInfo[@"aps"];
413
+ id alert = [aps isKindOfClass:[NSDictionary class]] ? aps[@"alert"] : nil;
414
+ NSString *resolvedTitle = title;
415
+ NSString *resolvedBody = body;
416
+
417
+ if ([alert isKindOfClass:[NSString class]]) {
418
+ resolvedBody = resolvedBody ?: (NSString *)alert;
419
+ } else if ([alert isKindOfClass:[NSDictionary class]]) {
420
+ resolvedTitle = resolvedTitle ?: [self stringify:alert[@"title"]];
421
+ resolvedBody = resolvedBody ?: [self stringify:alert[@"body"]];
422
+ }
423
+
424
+ NSMutableDictionary *data = [NSMutableDictionary dictionary];
425
+ [userInfo enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
426
+ NSString *stringKey = [NSString stringWithFormat:@"%@", key];
427
+ if ([stringKey isEqualToString:@"aps"]) {
428
+ return;
429
+ }
430
+ NSString *stringValue = [self stringify:value];
431
+ if (stringValue != nil) {
432
+ data[stringKey] = stringValue;
433
+ }
434
+ }];
435
+
436
+ NSMutableDictionary *message = [NSMutableDictionary dictionary];
437
+ NSString *messageId = [self stringify:userInfo[@"gcm.message_id"]] ?: fallbackId;
438
+ if (messageId != nil) {
439
+ message[@"id"] = messageId;
440
+ }
441
+ if (resolvedTitle != nil) {
442
+ message[@"title"] = resolvedTitle;
443
+ }
444
+ if (resolvedBody != nil) {
445
+ message[@"body"] = resolvedBody;
446
+ }
447
+ message[@"data"] = data;
448
+ return message;
449
+ }
450
+
451
+ + (nullable NSString *)stringify:(id)value {
452
+ if (value == nil || value == [NSNull null]) {
453
+ return nil;
454
+ }
455
+ if ([value isKindOfClass:[NSString class]]) {
456
+ return (NSString *)value;
457
+ }
458
+ if ([value isKindOfClass:[NSNumber class]]) {
459
+ return [(NSNumber *)value stringValue];
460
+ }
461
+ if ([NSJSONSerialization isValidJSONObject:value]) {
462
+ NSData *jsonData = [NSJSONSerialization dataWithJSONObject:value options:0 error:nil];
463
+ if (jsonData != nil) {
464
+ return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
465
+ }
466
+ }
467
+ return [NSString stringWithFormat:@"%@", value];
468
+ }
469
+
470
+ #pragma mark - Swizzling
471
+
472
+ - (void)swizzleAppDelegate {
473
+ if (_didSwizzleAppDelegate) {
474
+ return;
475
+ }
476
+ id appDelegate = [UIApplication sharedApplication].delegate;
477
+ if (appDelegate == nil) {
478
+ return;
479
+ }
480
+ _didSwizzleAppDelegate = YES;
481
+
482
+ Class target = object_getClass(appDelegate);
483
+ Class source = [PushSignalAppDelegateHook class];
484
+
485
+ [self swizzleTarget:target
486
+ original:@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)
487
+ replacement:@selector(pushSignal_application:didRegisterForRemoteNotificationsWithDeviceToken:)
488
+ source:source];
489
+ [self swizzleTarget:target
490
+ original:@selector(application:didFailToRegisterForRemoteNotificationsWithError:)
491
+ replacement:@selector(pushSignal_application:didFailToRegisterForRemoteNotificationsWithError:)
492
+ source:source];
493
+ }
494
+
495
+ - (void)swizzleNotificationCenterDelegateIfNeeded {
496
+ if (_didSwizzleNotificationCenter) {
497
+ return;
498
+ }
499
+ _didSwizzleNotificationCenter = YES;
500
+
501
+ Class target = [UNUserNotificationCenter class];
502
+ SEL original = @selector(setDelegate:);
503
+ SEL replacement = @selector(pushSignal_setDelegate:);
504
+
505
+ Method originalMethod = class_getInstanceMethod(target, original);
506
+ Method replacementMethod = class_getInstanceMethod(target, replacement);
507
+ if (originalMethod == NULL || replacementMethod == NULL) {
508
+ return;
509
+ }
510
+ method_exchangeImplementations(originalMethod, replacementMethod);
511
+ }
512
+
513
+ - (void)swizzleTarget:(Class)target
514
+ original:(SEL)original
515
+ replacement:(SEL)replacement
516
+ source:(Class)source {
517
+ Method replacementMethod = class_getInstanceMethod(source, replacement);
518
+ if (replacementMethod == NULL) {
519
+ return;
520
+ }
521
+
522
+ IMP replacementImp = method_getImplementation(replacementMethod);
523
+ const char *types = method_getTypeEncoding(replacementMethod);
524
+ Class superClass = class_getSuperclass(target);
525
+ Method superMethod = superClass != Nil ? class_getInstanceMethod(superClass, original) : NULL;
526
+
527
+ if (class_addMethod(target, original, replacementImp, types)) {
528
+ if (superMethod != NULL) {
529
+ class_addMethod(
530
+ target, replacement, method_getImplementation(superMethod), method_getTypeEncoding(superMethod));
531
+ }
532
+ return;
533
+ }
534
+
535
+ if (!class_addMethod(target, replacement, replacementImp, types)) {
536
+ return;
537
+ }
538
+ Method originalMethod = class_getInstanceMethod(target, original);
539
+ Method addedReplacement = class_getInstanceMethod(target, replacement);
540
+ if (originalMethod == NULL || addedReplacement == NULL) {
541
+ return;
542
+ }
543
+ method_exchangeImplementations(originalMethod, addedReplacement);
544
+ }
545
+
546
+ @end
547
+
548
+ @implementation PushSignalAppDelegateHook
549
+
550
+ - (void)pushSignal_application:(UIApplication *)application
551
+ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
552
+ [[PushSignalCenter shared] handleDeviceToken:deviceToken];
553
+ // After swizzle, this selector holds the original AppDelegate implementation (if any).
554
+ SEL original = @selector(pushSignal_application:didRegisterForRemoteNotificationsWithDeviceToken:);
555
+ if ([self respondsToSelector:original]) {
556
+ [self pushSignal_application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
557
+ }
558
+ }
559
+
560
+ - (void)pushSignal_application:(UIApplication *)application
561
+ didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
562
+ [[PushSignalCenter shared] handleRegistrationError:error];
563
+ SEL original = @selector(pushSignal_application:didFailToRegisterForRemoteNotificationsWithError:);
564
+ if ([self respondsToSelector:original]) {
565
+ [self pushSignal_application:application didFailToRegisterForRemoteNotificationsWithError:error];
566
+ }
567
+ }
568
+
569
+ @end
570
+
571
+ @implementation UNUserNotificationCenter (PushSignal)
572
+
573
+ - (void)pushSignal_setDelegate:(id<UNUserNotificationCenterDelegate>)delegate {
574
+ if (delegate != nil && [delegate isKindOfClass:[PushSignalCenter class]]) {
575
+ [self pushSignal_setDelegate:delegate];
576
+ return;
577
+ }
578
+
579
+ [[PushSignalCenter shared] rememberForwardingDelegate:delegate];
580
+ [self pushSignal_setDelegate:[PushSignalCenter shared]];
581
+ }
582
+
583
+ @end
@@ -1,12 +1,7 @@
1
1
  #import "PushSignalLaunchStore.h"
2
+ #import "PushSignalCenter.h"
2
3
  #import <UIKit/UIKit.h>
3
4
 
4
- // Swift `@objc(PushSignalCenter)` — declared so messaging via `id` type-checks.
5
- @interface PushSignalCenter : NSObject
6
- + (void)installEarly;
7
- + (void)bootstrapWithLaunchOptions:(nullable NSDictionary *)launchOptions;
8
- @end
9
-
10
5
  static NSDictionary *sLaunchOptions;
11
6
 
12
7
  NSDictionary *PushSignalCopyLaunchOptions(void) {
@@ -23,10 +18,7 @@ NSDictionary *PushSignalCopyLaunchOptions(void) {
23
18
  object:nil
24
19
  queue:nil
25
20
  usingBlock:^(NSNotification *notification) {
26
- id center = NSClassFromString(@"PushSignalCenter");
27
- if ([center respondsToSelector:@selector(installEarly)]) {
28
- [center installEarly];
29
- }
21
+ [PushSignalCenter installEarly];
30
22
  }];
31
23
 
32
24
  [[NSNotificationCenter defaultCenter]
@@ -35,10 +27,7 @@ NSDictionary *PushSignalCopyLaunchOptions(void) {
35
27
  queue:nil
36
28
  usingBlock:^(NSNotification *notification) {
37
29
  sLaunchOptions = [notification.userInfo copy];
38
- id center = NSClassFromString(@"PushSignalCenter");
39
- if ([center respondsToSelector:@selector(bootstrapWithLaunchOptions:)]) {
40
- [center bootstrapWithLaunchOptions:sLaunchOptions];
41
- }
30
+ [PushSignalCenter bootstrapWithLaunchOptions:sLaunchOptions];
42
31
  }];
43
32
  }
44
33
 
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+ export default TurboModuleRegistry.getEnforcing('PushSignal');
5
+ //# sourceMappingURL=NativePushSignal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativePushSignal.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAuBlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,YAAY,CAAC","ignoreList":[]}
@@ -1,33 +1,59 @@
1
1
  "use strict";
2
2
 
3
- import { NitroModules } from 'react-native-nitro-modules';
4
- const PushSignalHybridObject = NitroModules.createHybridObject('PushSignal');
3
+ import NativePushSignal from "./NativePushSignal.js";
5
4
  const messageListeners = new Set();
6
5
  const pressListeners = new Set();
7
6
  let nativeCallbacksBound = false;
7
+ function normalizeMessage(raw) {
8
+ const data = {};
9
+ if (raw.data && typeof raw.data === 'object') {
10
+ for (const [key, value] of Object.entries(raw.data)) {
11
+ if (value == null) {
12
+ continue;
13
+ }
14
+ data[key] = typeof value === 'string' ? value : String(value);
15
+ }
16
+ }
17
+ return {
18
+ id: raw.id,
19
+ title: raw.title,
20
+ body: raw.body,
21
+ data
22
+ };
23
+ }
24
+ function normalizeCredentials(raw) {
25
+ return {
26
+ platform: raw.platform,
27
+ token: raw.token,
28
+ environment: raw.environment
29
+ };
30
+ }
8
31
  function bindNativeCallbacks() {
9
32
  if (nativeCallbacksBound) {
10
33
  return;
11
34
  }
12
35
  nativeCallbacksBound = true;
13
- PushSignalHybridObject.setOnMessage(message => {
36
+ NativePushSignal.onMessage(raw => {
37
+ const message = normalizeMessage(raw);
14
38
  for (const listener of [...messageListeners]) {
15
39
  try {
16
- void listener(message);
40
+ Promise.resolve(listener(message)).then(() => undefined, () => undefined);
17
41
  } catch {
18
42
  // Ignore listener failures so one bad subscriber cannot break delivery.
19
43
  }
20
44
  }
21
45
  });
22
- PushSignalHybridObject.setOnNotificationPress(message => {
46
+ NativePushSignal.onNotificationPress(raw => {
47
+ const message = normalizeMessage(raw);
23
48
  pressListeners.forEach(listener => listener(message));
24
49
  });
50
+ NativePushSignal.startListening();
25
51
  }
26
52
  export function initialize(config = {}) {
27
- return PushSignalHybridObject.initialize(config);
53
+ return NativePushSignal.initialize(config);
28
54
  }
29
55
  export function getCredentials() {
30
- return PushSignalHybridObject.getCredentials();
56
+ return NativePushSignal.getCredentials().then(normalizeCredentials);
31
57
  }
32
58
  export function onMessage(listener) {
33
59
  bindNativeCallbacks();