appambit-push-notifications 0.3.1 → 1.0.1
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/AppAmbitSdkPushNotifications.podspec +14 -4
- package/README.md +184 -105
- package/android/build.gradle +21 -3
- package/android/src/main/AndroidManifest.xml +107 -1
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitContextHolder.kt +22 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitHeadlessService.kt +177 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitInitProvider.kt +73 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitMessagingService.kt +12 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitNotificationSerializer.kt +88 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitPayloadUtils.kt +59 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitPushEventEmitter.kt +100 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitRNServiceExtension.kt +75 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitRemoteMessageStore.kt +26 -0
- package/android/src/main/java/com/appambitpushnotifications/AppambitPushNotificationsModule.kt +377 -76
- package/ios/AppAmbitNotificationSwizzler.m +290 -0
- package/ios/AppAmbitPushWrapper.swift +165 -25
- package/ios/AppAmbitRNNotificationService.swift +46 -0
- package/ios/AppambitPushNotifications.mm +264 -10
- package/lib/module/NativeAppambitPushNotifications.js.map +1 -1
- package/lib/module/index.js +46 -10
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeAppambitPushNotifications.d.ts +2 -1
- package/lib/typescript/src/NativeAppambitPushNotifications.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +32 -6
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeAppambitPushNotifications.ts +7 -1
- package/src/index.tsx +93 -20
|
@@ -1,12 +1,67 @@
|
|
|
1
1
|
#import "AppambitPushNotifications.h"
|
|
2
2
|
#import <AppAmbitSdkPushNotifications-Swift.h>
|
|
3
3
|
|
|
4
|
+
// Defined in AppAmbitNotificationSwizzler.m — call when JS background handler resolves
|
|
5
|
+
extern "C" void AppAmbitNotifyJSBackgroundHandlerCompleted(void);
|
|
6
|
+
|
|
7
|
+
static NSString * const kPushEnabledStateKey = @"appambit_push_enabled_state";
|
|
8
|
+
static NSString * const kPushHasStateKey = @"appambit_push_has_enabled_state";
|
|
9
|
+
// Pending consumer-sync intent: the last value the user toggled that has not yet
|
|
10
|
+
// been confirmed as delivered to the backend. Replayed when connectivity returns.
|
|
11
|
+
static NSString * const kPushPendingKey = @"appambit_push_pending_sync";
|
|
12
|
+
static NSString * const kPushPendingValueKey = @"appambit_push_pending_value";
|
|
13
|
+
|
|
4
14
|
@implementation AppambitPushNotifications {
|
|
5
15
|
BOOL _hasListeners;
|
|
16
|
+
BOOL _sdkListenerInstalled;
|
|
17
|
+
NSMutableArray<NSDictionary *> *_pendingBackgroundEvents;
|
|
18
|
+
NSMutableArray<NSDictionary *> *_pendingOpenedEvents;
|
|
19
|
+
NSMutableArray<NSDictionary *> *_pendingForegroundEvents;
|
|
6
20
|
}
|
|
7
21
|
|
|
8
22
|
RCT_EXPORT_MODULE(AppambitPushNotifications)
|
|
9
23
|
|
|
24
|
+
- (instancetype)init {
|
|
25
|
+
self = [super init];
|
|
26
|
+
if (self) {
|
|
27
|
+
_pendingBackgroundEvents = [NSMutableArray new];
|
|
28
|
+
_pendingOpenedEvents = [NSMutableArray new];
|
|
29
|
+
_pendingForegroundEvents = [NSMutableArray new];
|
|
30
|
+
NSArray<NSDictionary *> *earlyBackground = [AppAmbitPushWrapper getAndClearPendingBackgroundPayloads];
|
|
31
|
+
if (earlyBackground.count > 0) {
|
|
32
|
+
[_pendingBackgroundEvents addObjectsFromArray:earlyBackground];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
NSArray<NSDictionary *> *earlyOpened = [AppAmbitPushWrapper getAndClearPendingOpenedPayloads];
|
|
36
|
+
if (earlyOpened.count > 0) {
|
|
37
|
+
[_pendingOpenedEvents addObjectsFromArray:earlyOpened];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
41
|
+
selector:@selector(handleBackgroundNotification:)
|
|
42
|
+
name:@"AppAmbit_onBackgroundNotification"
|
|
43
|
+
object:nil];
|
|
44
|
+
|
|
45
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
46
|
+
selector:@selector(handleOpenedNotification:)
|
|
47
|
+
name:@"AppAmbit_onOpenedNotification"
|
|
48
|
+
object:nil];
|
|
49
|
+
|
|
50
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
51
|
+
selector:@selector(handleAppBecameActive:)
|
|
52
|
+
name:UIApplicationDidBecomeActiveNotification
|
|
53
|
+
object:nil];
|
|
54
|
+
|
|
55
|
+
// Replay any deferred consumer sync as soon as the network comes back.
|
|
56
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
57
|
+
selector:@selector(handleNetworkAvailable:)
|
|
58
|
+
name:@"AppAmbit_networkAvailable"
|
|
59
|
+
object:nil];
|
|
60
|
+
[AppAmbitPushWrapper startNetworkMonitor];
|
|
61
|
+
}
|
|
62
|
+
return self;
|
|
63
|
+
}
|
|
64
|
+
|
|
10
65
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
11
66
|
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
12
67
|
{
|
|
@@ -16,20 +71,131 @@ RCT_EXPORT_MODULE(AppambitPushNotifications)
|
|
|
16
71
|
// MARK: - Event Emitter
|
|
17
72
|
|
|
18
73
|
- (NSArray<NSString *> *)supportedEvents {
|
|
19
|
-
return @[
|
|
74
|
+
return @[
|
|
75
|
+
@"AppAmbit_onForegroundNotification",
|
|
76
|
+
@"AppAmbit_onBackgroundNotification",
|
|
77
|
+
@"AppAmbit_onOpenedNotification"
|
|
78
|
+
];
|
|
20
79
|
}
|
|
21
80
|
|
|
22
81
|
- (void)startObserving {
|
|
23
82
|
_hasListeners = YES;
|
|
24
83
|
}
|
|
25
84
|
|
|
85
|
+
// Called lazily the first time JS subscribes to any event — mirrors Flutter's
|
|
86
|
+
// installNotificationListenerIfNeeded. At this point _hasListeners is already
|
|
87
|
+
// YES (set by startObserving via [super addListener:]) so SDK cold-start replay
|
|
88
|
+
// can be sent immediately, exactly like Flutter's DispatchQueue.main.async trick.
|
|
89
|
+
- (void)installSDKListenerIfNeeded {
|
|
90
|
+
if (_sdkListenerInstalled) return;
|
|
91
|
+
_sdkListenerInstalled = YES;
|
|
92
|
+
|
|
93
|
+
__weak AppambitPushNotifications *weakSelf = self;
|
|
94
|
+
[AppAmbitPushWrapper setNotificationListener:^(NSDictionary * _Nonnull payload, NSInteger state) {
|
|
95
|
+
AppambitPushNotifications *strongSelf = weakSelf;
|
|
96
|
+
if (!strongSelf) return;
|
|
97
|
+
|
|
98
|
+
if (state == 0) {
|
|
99
|
+
// Foreground
|
|
100
|
+
if (strongSelf->_hasListeners) {
|
|
101
|
+
[strongSelf sendEventWithName:@"AppAmbit_onForegroundNotification" body:payload];
|
|
102
|
+
} else {
|
|
103
|
+
[strongSelf->_pendingForegroundEvents addObject:payload];
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
// Opened/tapped — queue if app is still transitioning; applicationDidBecomeActive: flushes.
|
|
107
|
+
// Do NOT call isDuplicateOpenedPayload: here — it marks the payload as seen even when
|
|
108
|
+
// _hasListeners is NO, which would cause the subsequent flush in addListener: to skip it.
|
|
109
|
+
BOOL appIsActive = [UIApplication sharedApplication].applicationState == UIApplicationStateActive;
|
|
110
|
+
if (strongSelf->_hasListeners && appIsActive) {
|
|
111
|
+
if (![strongSelf isDuplicateOpenedPayload:payload]) {
|
|
112
|
+
[strongSelf sendEventWithName:@"AppAmbit_onOpenedNotification" body:payload];
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
[strongSelf->_pendingOpenedEvents addObject:payload];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
- (void)handleBackgroundNotification:(NSNotification *)notification {
|
|
122
|
+
if (!notification.userInfo) return;
|
|
123
|
+
if (_hasListeners) {
|
|
124
|
+
[self sendEventWithName:@"AppAmbit_onBackgroundNotification" body:notification.userInfo];
|
|
125
|
+
} else {
|
|
126
|
+
[_pendingBackgroundEvents addObject:notification.userInfo];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
- (void)handleAppBecameActive:(NSNotification *)notification {
|
|
131
|
+
// The SDK has had time to finish its async init (and register the device token)
|
|
132
|
+
// by the time the app becomes active, so this is a safe place to replay a
|
|
133
|
+
// deferred consumer sync (covers "toggle offline → reopen online").
|
|
134
|
+
[self flushPendingConsumerSync];
|
|
135
|
+
|
|
136
|
+
if (!_hasListeners || _pendingOpenedEvents.count == 0) return;
|
|
137
|
+
NSArray<NSDictionary *> *toSend = [_pendingOpenedEvents copy];
|
|
138
|
+
[_pendingOpenedEvents removeAllObjects];
|
|
139
|
+
for (NSDictionary *payload in toSend) {
|
|
140
|
+
if (![self isDuplicateOpenedPayload:payload]) {
|
|
141
|
+
[self sendEventWithName:@"AppAmbit_onOpenedNotification" body:payload];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
- (void)handleNetworkAvailable:(NSNotification *)notification {
|
|
147
|
+
[self flushPendingConsumerSync];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
- (void)handleOpenedNotification:(NSNotification *)notification {
|
|
151
|
+
if (!notification.userInfo) return;
|
|
152
|
+
// Only call isDuplicateOpenedPayload: when actually sending to JS.
|
|
153
|
+
// Calling it when _hasListeners is NO would mark the payload as seen before it's
|
|
154
|
+
// delivered, causing the addListener: flush to skip it (the payload never reaches JS).
|
|
155
|
+
if (_hasListeners) {
|
|
156
|
+
if (![self isDuplicateOpenedPayload:notification.userInfo]) {
|
|
157
|
+
[self sendEventWithName:@"AppAmbit_onOpenedNotification" body:notification.userInfo];
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
[_pendingOpenedEvents addObject:notification.userInfo];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
- (BOOL)isDuplicateOpenedPayload:(NSDictionary *)payload {
|
|
165
|
+
static NSMutableArray<NSDictionary *> *sentPayloads = nil;
|
|
166
|
+
static dispatch_once_t onceToken;
|
|
167
|
+
dispatch_once(&onceToken, ^{
|
|
168
|
+
sentPayloads = [NSMutableArray new];
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
for (NSDictionary *sent in sentPayloads) {
|
|
172
|
+
if ([sent isEqualToDictionary:payload]) {
|
|
173
|
+
return YES;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
[sentPayloads addObject:payload];
|
|
178
|
+
if (sentPayloads.count > 10) {
|
|
179
|
+
[sentPayloads removeObjectAtIndex:0];
|
|
180
|
+
}
|
|
181
|
+
return NO;
|
|
182
|
+
}
|
|
183
|
+
|
|
26
184
|
- (void)stopObserving {
|
|
27
185
|
_hasListeners = NO;
|
|
28
186
|
}
|
|
29
187
|
|
|
188
|
+
- (void)dealloc {
|
|
189
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
190
|
+
}
|
|
191
|
+
|
|
30
192
|
// MARK: - TurboModule Methods
|
|
31
193
|
|
|
32
194
|
- (void)start {
|
|
195
|
+
// Initialize the SDK. Do NOT call flushPendingSyncIfNeeded here — PushNotifications.start()
|
|
196
|
+
// registers the device token asynchronously, so getCurrentToken() returns nil immediately
|
|
197
|
+
// after start(), causing updateConsumer to fail. handleAppBecameActive: fires after the SDK
|
|
198
|
+
// has had time to complete its async init and is the correct place to flush pending sync.
|
|
33
199
|
[AppAmbitPushWrapper start];
|
|
34
200
|
}
|
|
35
201
|
|
|
@@ -40,31 +206,119 @@ RCT_EXPORT_MODULE(AppambitPushNotifications)
|
|
|
40
206
|
- (void)requestNotificationPermissionWithResult:(RCTPromiseResolveBlock)resolve
|
|
41
207
|
reject:(RCTPromiseRejectBlock)reject {
|
|
42
208
|
[AppAmbitPushWrapper requestNotificationPermissionWithListener:^(BOOL granted) {
|
|
209
|
+
if (granted) {
|
|
210
|
+
// Cache immediately so hasNotificationPermission() returns true on next
|
|
211
|
+
// restart even if the system permission resets (e.g. simulator reinstall).
|
|
212
|
+
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"appambit_push_has_permission"];
|
|
213
|
+
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
214
|
+
}
|
|
43
215
|
resolve(@(granted));
|
|
44
216
|
}];
|
|
45
217
|
}
|
|
46
218
|
|
|
47
219
|
- (void)setNotificationsEnabled:(BOOL)enabled {
|
|
48
|
-
[
|
|
220
|
+
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
|
221
|
+
// 1. Persist the user's intended state for UI consistency across restarts.
|
|
222
|
+
[ud setBool:enabled forKey:kPushEnabledStateKey];
|
|
223
|
+
[ud setBool:YES forKey:kPushHasStateKey];
|
|
224
|
+
// 2. Record a pending consumer-sync intent. It is cleared only once the
|
|
225
|
+
// backend update actually succeeds (see flushPendingConsumerSync).
|
|
226
|
+
[ud setBool:enabled forKey:kPushPendingValueKey];
|
|
227
|
+
[ud setBool:YES forKey:kPushPendingKey];
|
|
228
|
+
[ud synchronize];
|
|
229
|
+
// 3. Update the SDK's local enabled flag (no network) so cold-start token
|
|
230
|
+
// sync knows the user's intent.
|
|
231
|
+
[AppAmbitPushWrapper setNotificationsEnabledLocal:enabled];
|
|
232
|
+
// 4. Try to push it to the backend now. When offline this is a no-op: calling
|
|
233
|
+
// updateConsumer offline poisons the SDK's dedup cache (it writes the new
|
|
234
|
+
// state to its DB before the failed network send, so identical retries are
|
|
235
|
+
// skipped as "already synced"). The pending intent is replayed when the
|
|
236
|
+
// network returns or the app becomes active.
|
|
237
|
+
[self flushPendingConsumerSync];
|
|
49
238
|
}
|
|
50
239
|
|
|
51
240
|
- (void)isNotificationsEnabled:(RCTPromiseResolveBlock)resolve
|
|
52
241
|
reject:(RCTPromiseRejectBlock)reject {
|
|
53
|
-
|
|
242
|
+
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
|
243
|
+
if ([ud boolForKey:kPushHasStateKey]) {
|
|
244
|
+
// Return our own persisted state — this is always the last value the user
|
|
245
|
+
// explicitly set, survives cold restarts and SDK state inconsistencies.
|
|
246
|
+
resolve(@([ud boolForKey:kPushEnabledStateKey]));
|
|
247
|
+
} else {
|
|
248
|
+
// First-ever launch: no stored state yet, ask the SDK.
|
|
249
|
+
resolve(@([AppAmbitPushWrapper isNotificationsEnabled]));
|
|
250
|
+
}
|
|
54
251
|
}
|
|
55
252
|
|
|
56
|
-
- (void)
|
|
57
|
-
|
|
58
|
-
[AppAmbitPushWrapper
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
253
|
+
- (void)hasNotificationPermission:(RCTPromiseResolveBlock)resolve
|
|
254
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
255
|
+
[AppAmbitPushWrapper hasNotificationPermissionWithCompletion:^(BOOL granted) {
|
|
256
|
+
resolve(@(granted));
|
|
257
|
+
}];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Called by JS when the background notification async handler Promise resolves.
|
|
261
|
+
// Signals the iOS system that background processing is complete so iOS can reclaim
|
|
262
|
+
// time and allow future background wake-ups.
|
|
263
|
+
- (void)backgroundHandlerCompleted {
|
|
264
|
+
AppAmbitNotifyJSBackgroundHandlerCompleted();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// MARK: - Offline-resilient consumer sync
|
|
268
|
+
|
|
269
|
+
// Replays the pending consumer-sync intent to the backend when online. The SDK
|
|
270
|
+
// has no offline retry queue and dedups consumer updates against its local DB,
|
|
271
|
+
// so we must only call updateConsumer with real connectivity. The pending flag
|
|
272
|
+
// is cleared only on a confirmed successful backend update.
|
|
273
|
+
- (void)flushPendingConsumerSync {
|
|
274
|
+
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
|
275
|
+
if (![ud boolForKey:kPushPendingKey]) return;
|
|
276
|
+
if (![AppAmbitPushWrapper isNetworkAvailable]) return;
|
|
277
|
+
|
|
278
|
+
BOOL desired = [ud boolForKey:kPushPendingValueKey];
|
|
279
|
+
[AppAmbitPushWrapper setNotificationsEnabled:desired completion:^(BOOL success) {
|
|
280
|
+
if (!success) return;
|
|
281
|
+
NSUserDefaults *u = [NSUserDefaults standardUserDefaults];
|
|
282
|
+
// Only clear if the pending value still matches what we just synced — a
|
|
283
|
+
// newer toggle during the network call must keep its own pending intent.
|
|
284
|
+
if ([u boolForKey:kPushPendingKey] && [u boolForKey:kPushPendingValueKey] == desired) {
|
|
285
|
+
[u removeObjectForKey:kPushPendingKey];
|
|
286
|
+
[u removeObjectForKey:kPushPendingValueKey];
|
|
287
|
+
[u synchronize];
|
|
62
288
|
}
|
|
63
289
|
}];
|
|
64
290
|
}
|
|
65
291
|
|
|
66
292
|
- (void)addListener:(NSString *)eventName {
|
|
67
|
-
[super addListener:eventName];
|
|
293
|
+
[super addListener:eventName]; // sets _hasListeners = YES via startObserving
|
|
294
|
+
|
|
295
|
+
// Install SDK listener once JS is ready — same as Flutter's installNotificationListenerIfNeeded.
|
|
296
|
+
// _hasListeners is now YES so SDK cold-start replay fires sendEventWithName: directly.
|
|
297
|
+
[self installSDKListenerIfNeeded];
|
|
298
|
+
|
|
299
|
+
if ([eventName isEqualToString:@"AppAmbit_onBackgroundNotification"]) {
|
|
300
|
+
for (NSDictionary *payload in _pendingBackgroundEvents) {
|
|
301
|
+
[self sendEventWithName:@"AppAmbit_onBackgroundNotification" body:payload];
|
|
302
|
+
}
|
|
303
|
+
[_pendingBackgroundEvents removeAllObjects];
|
|
304
|
+
} else if ([eventName isEqualToString:@"AppAmbit_onForegroundNotification"]) {
|
|
305
|
+
for (NSDictionary *payload in _pendingForegroundEvents) {
|
|
306
|
+
[self sendEventWithName:@"AppAmbit_onForegroundNotification" body:payload];
|
|
307
|
+
}
|
|
308
|
+
[_pendingForegroundEvents removeAllObjects];
|
|
309
|
+
} else if ([eventName isEqualToString:@"AppAmbit_onOpenedNotification"]) {
|
|
310
|
+
NSArray<NSDictionary *> *earlyOpened = [AppAmbitPushWrapper getAndClearPendingOpenedPayloads];
|
|
311
|
+
if (earlyOpened.count > 0) {
|
|
312
|
+
[_pendingOpenedEvents addObjectsFromArray:earlyOpened];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
for (NSDictionary *payload in _pendingOpenedEvents) {
|
|
316
|
+
if (![self isDuplicateOpenedPayload:payload]) {
|
|
317
|
+
[self sendEventWithName:@"AppAmbit_onOpenedNotification" body:payload];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
[_pendingOpenedEvents removeAllObjects];
|
|
321
|
+
}
|
|
68
322
|
}
|
|
69
323
|
|
|
70
324
|
- (void)removeListeners:(double)count {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeAppambitPushNotifications.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAA0B,cAAc;
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeAppambitPushNotifications.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAA0B,cAAc;AAoBpE,eAAeA,mBAAmB,CAACC,YAAY,CAAO,2BAA2B,CAAC","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { NativeEventEmitter } from 'react-native';
|
|
3
|
+
import { NativeEventEmitter, Platform } from 'react-native';
|
|
4
4
|
import AppambitPushNotifications from "./NativeAppambitPushNotifications.js";
|
|
5
|
+
export const BACKGROUND_NOTIFICATION_TASK = 'AppAmbitBackgroundNotification';
|
|
6
|
+
const EVENT_FOREGROUND = 'AppAmbit_onForegroundNotification';
|
|
7
|
+
const EVENT_BACKGROUND = 'AppAmbit_onBackgroundNotification';
|
|
8
|
+
const EVENT_OPENED = 'AppAmbit_onOpenedNotification';
|
|
5
9
|
const eventEmitter = new NativeEventEmitter(AppambitPushNotifications);
|
|
10
|
+
let foregroundSub = null;
|
|
11
|
+
let backgroundSub = null;
|
|
12
|
+
let openedSub = null;
|
|
6
13
|
export const start = () => {
|
|
7
14
|
AppambitPushNotifications.start();
|
|
8
15
|
};
|
|
@@ -10,19 +17,48 @@ export const requestNotificationPermission = () => {
|
|
|
10
17
|
AppambitPushNotifications.requestNotificationPermission();
|
|
11
18
|
};
|
|
12
19
|
export const requestNotificationPermissionWithResult = async () => {
|
|
13
|
-
return
|
|
20
|
+
return AppambitPushNotifications.requestNotificationPermissionWithResult();
|
|
14
21
|
};
|
|
15
22
|
export const setNotificationsEnabled = enabled => {
|
|
16
23
|
AppambitPushNotifications.setNotificationsEnabled(enabled);
|
|
17
24
|
};
|
|
18
25
|
export const isNotificationsEnabled = async () => {
|
|
19
|
-
return
|
|
20
|
-
};
|
|
21
|
-
export const
|
|
22
|
-
AppambitPushNotifications.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
return AppambitPushNotifications.isNotificationsEnabled();
|
|
27
|
+
};
|
|
28
|
+
export const hasNotificationPermission = async () => {
|
|
29
|
+
return AppambitPushNotifications.hasNotificationPermission();
|
|
30
|
+
};
|
|
31
|
+
export const setForegroundListener = callback => {
|
|
32
|
+
foregroundSub?.remove();
|
|
33
|
+
foregroundSub = eventEmitter.addListener(EVENT_FOREGROUND, callback);
|
|
34
|
+
return () => {
|
|
35
|
+
foregroundSub?.remove();
|
|
36
|
+
foregroundSub = null;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export const setOpenedListener = callback => {
|
|
40
|
+
openedSub?.remove();
|
|
41
|
+
openedSub = eventEmitter.addListener(EVENT_OPENED, callback);
|
|
42
|
+
return () => {
|
|
43
|
+
openedSub?.remove();
|
|
44
|
+
openedSub = null;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export const Android = {
|
|
48
|
+
setBackgroundListener: callback => {
|
|
49
|
+
if (Platform.OS !== 'android') {
|
|
50
|
+
return () => {};
|
|
51
|
+
}
|
|
52
|
+
backgroundSub?.remove();
|
|
53
|
+
backgroundSub = eventEmitter.addListener(EVENT_BACKGROUND, payload => {
|
|
54
|
+
void callback(payload).finally(() => {
|
|
55
|
+
AppambitPushNotifications.backgroundHandlerCompleted();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
return () => {
|
|
59
|
+
backgroundSub?.remove();
|
|
60
|
+
backgroundSub = null;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
27
63
|
};
|
|
28
64
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEventEmitter","AppambitPushNotifications","eventEmitter","start","requestNotificationPermission","requestNotificationPermissionWithResult","setNotificationsEnabled","enabled","isNotificationsEnabled","
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","Platform","AppambitPushNotifications","BACKGROUND_NOTIFICATION_TASK","EVENT_FOREGROUND","EVENT_BACKGROUND","EVENT_OPENED","eventEmitter","foregroundSub","backgroundSub","openedSub","start","requestNotificationPermission","requestNotificationPermissionWithResult","setNotificationsEnabled","enabled","isNotificationsEnabled","hasNotificationPermission","setForegroundListener","callback","remove","addListener","setOpenedListener","Android","setBackgroundListener","OS","payload","finally","backgroundHandlerCompleted"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,kBAAkB,EAAEC,QAAQ,QAAQ,cAAc;AAC3D,OAAOC,yBAAyB,MAAM,sCAAmC;AAiCzE,OAAO,MAAMC,4BAA4B,GAAG,gCAAgC;AAE5E,MAAMC,gBAAgB,GAAG,mCAAmC;AAC5D,MAAMC,gBAAgB,GAAG,mCAAmC;AAC5D,MAAMC,YAAY,GAAO,+BAA+B;AAExD,MAAMC,YAAY,GAAG,IAAIP,kBAAkB,CAACE,yBAAyB,CAAC;AAEtE,IAAIM,aAAiE,GAAG,IAAI;AAC5E,IAAIC,aAAiE,GAAG,IAAI;AAC5E,IAAIC,SAAiE,GAAG,IAAI;AAE5E,OAAO,MAAMC,KAAK,GAAGA,CAAA,KAAY;EAC/BT,yBAAyB,CAACS,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,OAAO,MAAMC,6BAA6B,GAAGA,CAAA,KAAY;EACvDV,yBAAyB,CAACU,6BAA6B,CAAC,CAAC;AAC3D,CAAC;AAED,OAAO,MAAMC,uCAAuC,GAClD,MAAAA,CAAA,KAA8B;EAC5B,OAAOX,yBAAyB,CAACW,uCAAuC,CAAC,CAAC;AAC5E,CAAC;AAEH,OAAO,MAAMC,uBAAuB,GAAIC,OAAgB,IAAW;EACjEb,yBAAyB,CAACY,uBAAuB,CAACC,OAAO,CAAC;AAC5D,CAAC;AAED,OAAO,MAAMC,sBAAsB,GAAG,MAAAA,CAAA,KAA8B;EAClE,OAAOd,yBAAyB,CAACc,sBAAsB,CAAC,CAAC;AAC3D,CAAC;AAED,OAAO,MAAMC,yBAAyB,GAAG,MAAAA,CAAA,KAA8B;EACrE,OAAOf,yBAAyB,CAACe,yBAAyB,CAAC,CAAC;AAC9D,CAAC;AAED,OAAO,MAAMC,qBAAqB,GAChCC,QAA8B,IACb;EACjBX,aAAa,EAAEY,MAAM,CAAC,CAAC;EACvBZ,aAAa,GAAGD,YAAY,CAACc,WAAW,CAACjB,gBAAgB,EAAEe,QAAe,CAAC;EAC3E,OAAO,MAAM;IACXX,aAAa,EAAEY,MAAM,CAAC,CAAC;IACvBZ,aAAa,GAAG,IAAI;EACtB,CAAC;AACH,CAAC;AAED,OAAO,MAAMc,iBAAiB,GAC5BH,QAA8B,IACb;EACjBT,SAAS,EAAEU,MAAM,CAAC,CAAC;EACnBV,SAAS,GAAGH,YAAY,CAACc,WAAW,CAACf,YAAY,EAAEa,QAAe,CAAC;EACnE,OAAO,MAAM;IACXT,SAAS,EAAEU,MAAM,CAAC,CAAC;IACnBV,SAAS,GAAG,IAAI;EAClB,CAAC;AACH,CAAC;AAED,OAAO,MAAMa,OAAO,GAAG;EACrBC,qBAAqB,EACnBL,QAAwC,IACvB;IACjB,IAAIlB,QAAQ,CAACwB,EAAE,KAAK,SAAS,EAAE;MAC7B,OAAO,MAAM,CAAC,CAAC;IACjB;IACAhB,aAAa,EAAEW,MAAM,CAAC,CAAC;IACvBX,aAAa,GAAGF,YAAY,CAACc,WAAW,CACtChB,gBAAgB,EACdqB,OAA4B,IAAK;MACjC,KAAKP,QAAQ,CAACO,OAAO,CAAC,CAACC,OAAO,CAAC,MAAM;QACnCzB,yBAAyB,CAAC0B,0BAA0B,CAAC,CAAC;MACxD,CAAC,CAAC;IACJ,CACF,CAAC;IACD,OAAO,MAAM;MACXnB,aAAa,EAAEW,MAAM,CAAC,CAAC;MACvBX,aAAa,GAAG,IAAI;IACtB,CAAC;EACH;AACF,CAAC","ignoreList":[]}
|
|
@@ -5,7 +5,8 @@ export interface Spec extends TurboModule {
|
|
|
5
5
|
requestNotificationPermissionWithResult(): Promise<boolean>;
|
|
6
6
|
setNotificationsEnabled(enabled: boolean): void;
|
|
7
7
|
isNotificationsEnabled(): Promise<boolean>;
|
|
8
|
-
|
|
8
|
+
hasNotificationPermission(): Promise<boolean>;
|
|
9
|
+
backgroundHandlerCompleted(): void;
|
|
9
10
|
addListener(eventName: string): void;
|
|
10
11
|
removeListeners(count: number): void;
|
|
11
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeAppambitPushNotifications.d.ts","sourceRoot":"","sources":["../../../src/NativeAppambitPushNotifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,KAAK,IAAI,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"NativeAppambitPushNotifications.d.ts","sourceRoot":"","sources":["../../../src/NativeAppambitPushNotifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,KAAK,IAAI,IAAI,CAAC;IAEd,6BAA6B,IAAI,IAAI,CAAC;IACtC,uCAAuC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAChD,sBAAsB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,yBAAyB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAK9C,0BAA0B,IAAI,IAAI,CAAC;IAEnC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;;AAED,wBAAmF"}
|
|
@@ -1,14 +1,40 @@
|
|
|
1
|
+
export interface AndroidNotificationData {
|
|
2
|
+
color: string | null;
|
|
3
|
+
smallIconName: string | null;
|
|
4
|
+
ticker: string | null;
|
|
5
|
+
sticky: boolean | null;
|
|
6
|
+
visibility: string | null;
|
|
7
|
+
channelId: string | null;
|
|
8
|
+
tag: string | null;
|
|
9
|
+
sound: string | null;
|
|
10
|
+
clickAction: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface IosNotificationData {
|
|
13
|
+
badge: number | null;
|
|
14
|
+
sound: string | null;
|
|
15
|
+
category: string | null;
|
|
16
|
+
threadId: string | null;
|
|
17
|
+
}
|
|
1
18
|
export interface NotificationPayload {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
19
|
+
title: string | null;
|
|
20
|
+
body: string | null;
|
|
21
|
+
imageUrl: string | null;
|
|
22
|
+
data: Record<string, any>;
|
|
23
|
+
android: AndroidNotificationData | null;
|
|
24
|
+
ios: IosNotificationData | null;
|
|
7
25
|
}
|
|
26
|
+
export type NotificationListener = (notification: NotificationPayload) => void;
|
|
27
|
+
export type BackgroundNotificationListener = (notification: NotificationPayload) => Promise<void>;
|
|
28
|
+
export declare const BACKGROUND_NOTIFICATION_TASK = "AppAmbitBackgroundNotification";
|
|
8
29
|
export declare const start: () => void;
|
|
9
30
|
export declare const requestNotificationPermission: () => void;
|
|
10
31
|
export declare const requestNotificationPermissionWithResult: () => Promise<boolean>;
|
|
11
32
|
export declare const setNotificationsEnabled: (enabled: boolean) => void;
|
|
12
33
|
export declare const isNotificationsEnabled: () => Promise<boolean>;
|
|
13
|
-
export declare const
|
|
34
|
+
export declare const hasNotificationPermission: () => Promise<boolean>;
|
|
35
|
+
export declare const setForegroundListener: (callback: NotificationListener) => (() => void);
|
|
36
|
+
export declare const setOpenedListener: (callback: NotificationListener) => (() => void);
|
|
37
|
+
export declare const Android: {
|
|
38
|
+
setBackgroundListener: (callback: BackgroundNotificationListener) => (() => void);
|
|
39
|
+
};
|
|
14
40
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACxC,GAAG,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,YAAY,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAC/E,MAAM,MAAM,8BAA8B,GAAG,CAAC,YAAY,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAElG,eAAO,MAAM,4BAA4B,mCAAmC,CAAC;AAY7E,eAAO,MAAM,KAAK,QAAO,IAExB,CAAC;AAEF,eAAO,MAAM,6BAA6B,QAAO,IAEhD,CAAC;AAEF,eAAO,MAAM,uCAAuC,QACxC,OAAO,CAAC,OAAO,CAExB,CAAC;AAEJ,eAAO,MAAM,uBAAuB,GAAI,SAAS,OAAO,KAAG,IAE1D,CAAC;AAEF,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,OAAO,CAE9D,CAAC;AAEF,eAAO,MAAM,yBAAyB,QAAa,OAAO,CAAC,OAAO,CAEjE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,UAAU,oBAAoB,KAC7B,CAAC,MAAM,IAAI,CAOb,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,UAAU,oBAAoB,KAC7B,CAAC,MAAM,IAAI,CAOb,CAAC;AAEF,eAAO,MAAM,OAAO;sCAEN,8BAA8B,KACvC,CAAC,MAAM,IAAI,CAAC;CAkBhB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appambit-push-notifications",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Push Notifications SDK for Android to send push notifications via AppAmbit platform.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -2,12 +2,18 @@ import { TurboModuleRegistry, type TurboModule } from 'react-native';
|
|
|
2
2
|
|
|
3
3
|
export interface Spec extends TurboModule {
|
|
4
4
|
start(): void;
|
|
5
|
+
|
|
5
6
|
requestNotificationPermission(): void;
|
|
6
7
|
requestNotificationPermissionWithResult(): Promise<boolean>;
|
|
7
8
|
setNotificationsEnabled(enabled: boolean): void;
|
|
8
9
|
isNotificationsEnabled(): Promise<boolean>;
|
|
10
|
+
hasNotificationPermission(): Promise<boolean>;
|
|
11
|
+
|
|
12
|
+
// iOS: call when the background notification async handler Promise resolves.
|
|
13
|
+
// Signals iOS that background processing is complete so the system can reclaim
|
|
14
|
+
// time and continue scheduling background wake-ups.
|
|
15
|
+
backgroundHandlerCompleted(): void;
|
|
9
16
|
|
|
10
|
-
setNotificationCustomizer(): void;
|
|
11
17
|
addListener(eventName: string): void;
|
|
12
18
|
removeListeners(count: number): void;
|
|
13
19
|
}
|
package/src/index.tsx
CHANGED
|
@@ -1,16 +1,49 @@
|
|
|
1
|
-
import { NativeEventEmitter } from 'react-native';
|
|
1
|
+
import { NativeEventEmitter, Platform } from 'react-native';
|
|
2
2
|
import AppambitPushNotifications from './NativeAppambitPushNotifications';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
export interface AndroidNotificationData {
|
|
5
|
+
color: string | null;
|
|
6
|
+
smallIconName: string | null;
|
|
7
|
+
ticker: string | null;
|
|
8
|
+
sticky: boolean | null;
|
|
9
|
+
visibility: string | null;
|
|
10
|
+
channelId: string | null;
|
|
11
|
+
tag: string | null;
|
|
12
|
+
sound: string | null;
|
|
13
|
+
clickAction: string | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface IosNotificationData {
|
|
17
|
+
badge: number | null;
|
|
18
|
+
sound: string | null;
|
|
19
|
+
category: string | null;
|
|
20
|
+
threadId: string | null;
|
|
21
|
+
}
|
|
5
22
|
|
|
6
23
|
export interface NotificationPayload {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
24
|
+
title: string | null;
|
|
25
|
+
body: string | null;
|
|
26
|
+
imageUrl: string | null;
|
|
27
|
+
data: Record<string, any>;
|
|
28
|
+
android: AndroidNotificationData | null;
|
|
29
|
+
ios: IosNotificationData | null;
|
|
12
30
|
}
|
|
13
31
|
|
|
32
|
+
export type NotificationListener = (notification: NotificationPayload) => void;
|
|
33
|
+
export type BackgroundNotificationListener = (notification: NotificationPayload) => Promise<void>;
|
|
34
|
+
|
|
35
|
+
export const BACKGROUND_NOTIFICATION_TASK = 'AppAmbitBackgroundNotification';
|
|
36
|
+
|
|
37
|
+
const EVENT_FOREGROUND = 'AppAmbit_onForegroundNotification';
|
|
38
|
+
const EVENT_BACKGROUND = 'AppAmbit_onBackgroundNotification';
|
|
39
|
+
const EVENT_OPENED = 'AppAmbit_onOpenedNotification';
|
|
40
|
+
|
|
41
|
+
const eventEmitter = new NativeEventEmitter(AppambitPushNotifications);
|
|
42
|
+
|
|
43
|
+
let foregroundSub: ReturnType<typeof eventEmitter.addListener> | null = null;
|
|
44
|
+
let backgroundSub: ReturnType<typeof eventEmitter.addListener> | null = null;
|
|
45
|
+
let openedSub: ReturnType<typeof eventEmitter.addListener> | null = null;
|
|
46
|
+
|
|
14
47
|
export const start = (): void => {
|
|
15
48
|
AppambitPushNotifications.start();
|
|
16
49
|
};
|
|
@@ -19,24 +52,64 @@ export const requestNotificationPermission = (): void => {
|
|
|
19
52
|
AppambitPushNotifications.requestNotificationPermission();
|
|
20
53
|
};
|
|
21
54
|
|
|
22
|
-
export const requestNotificationPermissionWithResult =
|
|
23
|
-
|
|
24
|
-
|
|
55
|
+
export const requestNotificationPermissionWithResult =
|
|
56
|
+
async (): Promise<boolean> => {
|
|
57
|
+
return AppambitPushNotifications.requestNotificationPermissionWithResult();
|
|
58
|
+
};
|
|
25
59
|
|
|
26
60
|
export const setNotificationsEnabled = (enabled: boolean): void => {
|
|
27
61
|
AppambitPushNotifications.setNotificationsEnabled(enabled);
|
|
28
62
|
};
|
|
29
63
|
|
|
30
64
|
export const isNotificationsEnabled = async (): Promise<boolean> => {
|
|
31
|
-
return
|
|
65
|
+
return AppambitPushNotifications.isNotificationsEnabled();
|
|
32
66
|
};
|
|
33
67
|
|
|
34
|
-
export const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
68
|
+
export const hasNotificationPermission = async (): Promise<boolean> => {
|
|
69
|
+
return AppambitPushNotifications.hasNotificationPermission();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const setForegroundListener = (
|
|
73
|
+
callback: NotificationListener
|
|
74
|
+
): (() => void) => {
|
|
75
|
+
foregroundSub?.remove();
|
|
76
|
+
foregroundSub = eventEmitter.addListener(EVENT_FOREGROUND, callback as any);
|
|
77
|
+
return () => {
|
|
78
|
+
foregroundSub?.remove();
|
|
79
|
+
foregroundSub = null;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const setOpenedListener = (
|
|
84
|
+
callback: NotificationListener
|
|
85
|
+
): (() => void) => {
|
|
86
|
+
openedSub?.remove();
|
|
87
|
+
openedSub = eventEmitter.addListener(EVENT_OPENED, callback as any);
|
|
88
|
+
return () => {
|
|
89
|
+
openedSub?.remove();
|
|
90
|
+
openedSub = null;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const Android = {
|
|
95
|
+
setBackgroundListener: (
|
|
96
|
+
callback: BackgroundNotificationListener
|
|
97
|
+
): (() => void) => {
|
|
98
|
+
if (Platform.OS !== 'android') {
|
|
99
|
+
return () => {};
|
|
100
|
+
}
|
|
101
|
+
backgroundSub?.remove();
|
|
102
|
+
backgroundSub = eventEmitter.addListener(
|
|
103
|
+
EVENT_BACKGROUND,
|
|
104
|
+
((payload: NotificationPayload) => {
|
|
105
|
+
void callback(payload).finally(() => {
|
|
106
|
+
AppambitPushNotifications.backgroundHandlerCompleted();
|
|
107
|
+
});
|
|
108
|
+
}) as any
|
|
109
|
+
);
|
|
110
|
+
return () => {
|
|
111
|
+
backgroundSub?.remove();
|
|
112
|
+
backgroundSub = null;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
};
|