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.
- package/LICENSE +1 -1
- package/PushSignal.podspec +2 -12
- package/README.md +1 -3
- package/README.ru.md +1 -3
- package/android/build.gradle +1 -62
- package/android/consumer-rules.pro +3 -3
- package/android/src/main/AndroidManifest.xml +2 -2
- package/android/src/main/java/com/pushsignal/PushModels.kt +15 -0
- package/android/src/main/java/com/{margelo/nitro/pushsignal → pushsignal}/PushSignalCenter.kt +2 -3
- package/android/src/main/java/com/{margelo/nitro/pushsignal → pushsignal}/PushSignalInitProvider.kt +1 -1
- package/android/src/main/java/com/{margelo/nitro/pushsignal → pushsignal}/PushSignalMessagingService.kt +1 -1
- package/android/src/main/java/com/pushsignal/PushSignalModule.kt +88 -0
- package/android/src/main/java/com/pushsignal/PushSignalPackage.kt +30 -0
- package/ios/PushSignal.h +4 -0
- package/ios/PushSignal.mm +57 -0
- package/ios/PushSignalCenter.h +26 -0
- package/ios/PushSignalCenter.m +583 -0
- package/ios/PushSignalLaunchStore.m +3 -14
- package/lib/module/NativePushSignal.js +5 -0
- package/lib/module/NativePushSignal.js.map +1 -0
- package/lib/module/pushSignal.native.js +33 -7
- package/lib/module/pushSignal.native.js.map +1 -1
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/src/NativePushSignal.d.ts +22 -0
- package/lib/typescript/src/NativePushSignal.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/pushSignal.d.ts +1 -1
- package/lib/typescript/src/pushSignal.d.ts.map +1 -1
- package/lib/typescript/src/pushSignal.native.d.ts +1 -1
- package/lib/typescript/src/pushSignal.native.d.ts.map +1 -1
- package/lib/typescript/src/{PushSignal.nitro.d.ts → types.d.ts} +2 -12
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +14 -19
- package/src/NativePushSignal.ts +25 -0
- package/src/index.tsx +1 -1
- package/src/pushSignal.native.tsx +54 -11
- package/src/pushSignal.tsx +1 -1
- package/src/types.ts +25 -0
- package/android/CMakeLists.txt +0 -24
- package/android/src/main/cpp/cpp-adapter.cpp +0 -11
- package/android/src/main/java/com/margelo/nitro/pushsignal/PushSignal.kt +0 -38
- package/android/src/main/java/com/margelo/nitro/pushsignal/PushSignalPackage.kt +0 -22
- package/ios/PushSignal.swift +0 -29
- package/ios/PushSignalCenter.swift +0 -604
- package/lib/module/PushSignal.nitro.js +0 -4
- package/lib/module/PushSignal.nitro.js.map +0 -1
- package/lib/typescript/src/PushSignal.nitro.d.ts.map +0 -1
- package/nitro.json +0 -23
- package/nitrogen/generated/android/c++/JAndroidFirebaseConfig.hpp +0 -70
- package/nitrogen/generated/android/c++/JFunc_void_PushMessage.hpp +0 -80
- package/nitrogen/generated/android/c++/JHybridPushSignalSpec.cpp +0 -114
- package/nitrogen/generated/android/c++/JHybridPushSignalSpec.hpp +0 -66
- package/nitrogen/generated/android/c++/JPushCredentials.hpp +0 -70
- package/nitrogen/generated/android/c++/JPushEnvironment.hpp +0 -58
- package/nitrogen/generated/android/c++/JPushMessage.hpp +0 -84
- package/nitrogen/generated/android/c++/JPushPlatform.hpp +0 -58
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/AndroidFirebaseConfig.kt +0 -66
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/Func_void_PushMessage.kt +0 -78
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/HybridPushSignalSpec.kt +0 -79
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/PushCredentials.kt +0 -61
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/PushEnvironment.kt +0 -23
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/PushMessage.kt +0 -66
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/PushPlatform.kt +0 -23
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pushsignal/pushsignalOnLoad.kt +0 -35
- package/nitrogen/generated/android/pushsignal+autolinking.cmake +0 -81
- package/nitrogen/generated/android/pushsignal+autolinking.gradle +0 -27
- package/nitrogen/generated/android/pushsignalOnLoad.cpp +0 -56
- package/nitrogen/generated/android/pushsignalOnLoad.hpp +0 -34
- package/nitrogen/generated/ios/PushSignal+autolinking.rb +0 -62
- package/nitrogen/generated/ios/PushSignal-Swift-Cxx-Bridge.cpp +0 -65
- package/nitrogen/generated/ios/PushSignal-Swift-Cxx-Bridge.hpp +0 -254
- package/nitrogen/generated/ios/PushSignal-Swift-Cxx-Umbrella.hpp +0 -63
- package/nitrogen/generated/ios/PushSignalAutolinking.mm +0 -33
- package/nitrogen/generated/ios/PushSignalAutolinking.swift +0 -26
- package/nitrogen/generated/ios/c++/HybridPushSignalSpecSwift.cpp +0 -11
- package/nitrogen/generated/ios/c++/HybridPushSignalSpecSwift.hpp +0 -120
- package/nitrogen/generated/ios/swift/AndroidFirebaseConfig.swift +0 -96
- package/nitrogen/generated/ios/swift/Func_void.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_PushCredentials.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_PushMessage.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +0 -46
- package/nitrogen/generated/ios/swift/HybridPushSignalSpec.swift +0 -58
- package/nitrogen/generated/ios/swift/HybridPushSignalSpec_cxx.swift +0 -196
- package/nitrogen/generated/ios/swift/PushCredentials.swift +0 -45
- package/nitrogen/generated/ios/swift/PushEnvironment.swift +0 -40
- package/nitrogen/generated/ios/swift/PushMessage.swift +0 -97
- package/nitrogen/generated/ios/swift/PushPlatform.swift +0 -40
- package/nitrogen/generated/shared/c++/AndroidFirebaseConfig.hpp +0 -96
- package/nitrogen/generated/shared/c++/HybridPushSignalSpec.cpp +0 -24
- package/nitrogen/generated/shared/c++/HybridPushSignalSpec.hpp +0 -74
- package/nitrogen/generated/shared/c++/PushCredentials.hpp +0 -97
- package/nitrogen/generated/shared/c++/PushEnvironment.hpp +0 -76
- package/nitrogen/generated/shared/c++/PushMessage.hpp +0 -97
- package/nitrogen/generated/shared/c++/PushPlatform.hpp +0 -76
- 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
|
-
|
|
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
|
-
|
|
39
|
-
if ([center respondsToSelector:@selector(bootstrapWithLaunchOptions:)]) {
|
|
40
|
-
[center bootstrapWithLaunchOptions:sLaunchOptions];
|
|
41
|
-
}
|
|
30
|
+
[PushSignalCenter bootstrapWithLaunchOptions:sLaunchOptions];
|
|
42
31
|
}];
|
|
43
32
|
}
|
|
44
33
|
|
|
@@ -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
|
|
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
|
-
|
|
36
|
+
NativePushSignal.onMessage(raw => {
|
|
37
|
+
const message = normalizeMessage(raw);
|
|
14
38
|
for (const listener of [...messageListeners]) {
|
|
15
39
|
try {
|
|
16
|
-
|
|
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
|
-
|
|
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
|
|
53
|
+
return NativePushSignal.initialize(config);
|
|
28
54
|
}
|
|
29
55
|
export function getCredentials() {
|
|
30
|
-
return
|
|
56
|
+
return NativePushSignal.getCredentials().then(normalizeCredentials);
|
|
31
57
|
}
|
|
32
58
|
export function onMessage(listener) {
|
|
33
59
|
bindNativeCallbacks();
|