@react-native-firebase/messaging 23.8.0 → 23.8.2

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 (48) hide show
  1. package/CHANGELOG.md +1197 -0
  2. package/RNFBMessaging.podspec +50 -0
  3. package/android/.editorconfig +10 -0
  4. package/android/build.gradle +149 -0
  5. package/android/lint.xml +5 -0
  6. package/android/settings.gradle +1 -0
  7. package/android/src/main/AndroidManifest.xml +43 -0
  8. package/android/src/main/java/io/invertase/firebase/messaging/JsonConvert.java +127 -0
  9. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingHeadlessService.java +30 -0
  10. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingModule.java +332 -0
  11. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingPackage.java +41 -0
  12. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingReceiver.java +66 -0
  13. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingSerializer.java +225 -0
  14. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingService.java +37 -0
  15. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingStore.java +15 -0
  16. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingStoreHelper.java +23 -0
  17. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingStoreImpl.java +97 -0
  18. package/android/src/main/res/values/colors.xml +143 -0
  19. package/app.plugin.js +1 -0
  20. package/dist/commonjs/version.js +1 -1
  21. package/dist/module/version.js +1 -1
  22. package/dist/typescript/commonjs/lib/namespaced.d.ts +1 -1
  23. package/dist/typescript/commonjs/lib/version.d.ts +1 -1
  24. package/dist/typescript/module/lib/namespaced.d.ts +1 -1
  25. package/dist/typescript/module/lib/version.d.ts +1 -1
  26. package/ios/RNFBMessaging/RNFBMessaging+AppDelegate.h +54 -0
  27. package/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m +251 -0
  28. package/ios/RNFBMessaging/RNFBMessaging+FIRMessagingDelegate.h +31 -0
  29. package/ios/RNFBMessaging/RNFBMessaging+FIRMessagingDelegate.m +70 -0
  30. package/ios/RNFBMessaging/RNFBMessaging+NSNotificationCenter.h +29 -0
  31. package/ios/RNFBMessaging/RNFBMessaging+NSNotificationCenter.m +173 -0
  32. package/ios/RNFBMessaging/RNFBMessaging+UNUserNotificationCenter.h +37 -0
  33. package/ios/RNFBMessaging/RNFBMessaging+UNUserNotificationCenter.m +185 -0
  34. package/ios/RNFBMessaging/RNFBMessagingModule.h +26 -0
  35. package/ios/RNFBMessaging/RNFBMessagingModule.m +431 -0
  36. package/ios/RNFBMessaging/RNFBMessagingSerializer.h +32 -0
  37. package/ios/RNFBMessaging/RNFBMessagingSerializer.m +235 -0
  38. package/ios/RNFBMessaging.xcodeproj/project.pbxproj +384 -0
  39. package/ios/RNFBMessaging.xcodeproj/xcshareddata/IDETemplateMacros.plist +24 -0
  40. package/lib/version.ts +1 -1
  41. package/package.json +5 -15
  42. package/plugin/build/android/index.d.ts +2 -0
  43. package/plugin/build/android/index.js +5 -0
  44. package/plugin/build/android/setupFirebaseNotifationIcon.d.ts +8 -0
  45. package/plugin/build/android/setupFirebaseNotifationIcon.js +62 -0
  46. package/plugin/build/index.d.ts +3 -0
  47. package/plugin/build/index.js +16 -0
  48. package/plugin/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <Firebase/Firebase.h>
19
+ #import <GoogleUtilities/GULAppDelegateSwizzler.h>
20
+ #import <objc/runtime.h>
21
+
22
+ #import <RNFBApp/RNFBRCTEventEmitter.h>
23
+ #import <RNFBApp/RNFBSharedUtils.h>
24
+ #import <React/RCTConvert.h>
25
+
26
+ #import "RNFBMessaging+AppDelegate.h"
27
+ #import "RNFBMessagingSerializer.h"
28
+
29
+ @implementation RNFBMessagingAppDelegate
30
+
31
+ + (instancetype)sharedInstance {
32
+ static dispatch_once_t once;
33
+ __strong static RNFBMessagingAppDelegate *sharedInstance;
34
+ dispatch_once(&once, ^{
35
+ sharedInstance = [[RNFBMessagingAppDelegate alloc] init];
36
+ sharedInstance.conditionBackgroundMessageHandlerSet = [[NSCondition alloc] init];
37
+ sharedInstance.backgroundMessageHandlerSet = NO;
38
+ });
39
+ return sharedInstance;
40
+ }
41
+
42
+ - (void)observe {
43
+ static dispatch_once_t once;
44
+ __weak RNFBMessagingAppDelegate *weakSelf = self;
45
+ dispatch_once(&once, ^{
46
+ RNFBMessagingAppDelegate *strongSelf = weakSelf;
47
+
48
+ [GULAppDelegateSwizzler registerAppDelegateInterceptor:strongSelf];
49
+ [GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
50
+
51
+ SEL didReceiveRemoteNotificationWithCompletionSEL =
52
+ NSSelectorFromString(@"application:didReceiveRemoteNotification:fetchCompletionHandler:");
53
+ if ([[GULAppDelegateSwizzler sharedApplication].delegate
54
+ respondsToSelector:didReceiveRemoteNotificationWithCompletionSEL]) {
55
+ // noop - user has own implementation of this method in their AppDelegate, this
56
+ // means GULAppDelegateSwizzler will have already replaced it with a donor method
57
+ } else {
58
+ // add our own donor implementation of
59
+ // application:didReceiveRemoteNotification:fetchCompletionHandler:
60
+ Method donorMethod = class_getInstanceMethod(object_getClass(strongSelf),
61
+ didReceiveRemoteNotificationWithCompletionSEL);
62
+ class_addMethod(object_getClass([GULAppDelegateSwizzler sharedApplication].delegate),
63
+ didReceiveRemoteNotificationWithCompletionSEL,
64
+ method_getImplementation(donorMethod), method_getTypeEncoding(donorMethod));
65
+ }
66
+ });
67
+ }
68
+
69
+ // used to signal that a javascript handler for background messages is set
70
+ - (void)signalBackgroundMessageHandlerSet {
71
+ RNFBMessagingAppDelegate *sharedInstance = [RNFBMessagingAppDelegate sharedInstance];
72
+ [sharedInstance.conditionBackgroundMessageHandlerSet lock];
73
+ DLog(@"signalBackgroundMessageHandlerSet sharedInstance.backgroundMessageHandlerSet was %@",
74
+ sharedInstance.backgroundMessageHandlerSet ? @"YES" : @"NO");
75
+ sharedInstance.backgroundMessageHandlerSet = YES;
76
+ [sharedInstance.conditionBackgroundMessageHandlerSet broadcast];
77
+ [sharedInstance.conditionBackgroundMessageHandlerSet unlock];
78
+ }
79
+
80
+ // used to temporarily store a promise instance to resolve calls to `registerForRemoteNotifications`
81
+ - (void)setPromiseResolve:(RCTPromiseResolveBlock)resolve
82
+ andPromiseReject:(RCTPromiseRejectBlock)reject {
83
+ _registerPromiseResolver = resolve;
84
+ _registerPromiseRejecter = reject;
85
+ }
86
+
87
+ #pragma mark -
88
+ #pragma mark AppDelegate Methods
89
+
90
+ // called when `registerForRemoteNotifications` completes successfully
91
+ - (void)application:(UIApplication *)application
92
+ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
93
+ #ifdef DEBUG
94
+ [[FIRMessaging messaging] setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeSandbox];
95
+ #else
96
+ [[FIRMessaging messaging] setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeProd];
97
+ #endif
98
+
99
+ if (_registerPromiseResolver != nil) {
100
+ _registerPromiseResolver(@(
101
+ [RCTConvert BOOL:@([UIApplication sharedApplication].isRegisteredForRemoteNotifications)]));
102
+ _registerPromiseResolver = nil;
103
+ _registerPromiseRejecter = nil;
104
+ }
105
+ }
106
+
107
+ // called when `registerForRemoteNotifications` fails to complete
108
+ - (void)application:(UIApplication *)application
109
+ didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
110
+ if (_registerPromiseRejecter != nil) {
111
+ [RNFBSharedUtils rejectPromiseWithNSError:_registerPromiseRejecter error:error];
112
+ _registerPromiseResolver = nil;
113
+ _registerPromiseRejecter = nil;
114
+ }
115
+ }
116
+
117
+ - (void)application:(UIApplication *)application
118
+ didReceiveRemoteNotification:(NSDictionary *)userInfo
119
+ fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
120
+ #if __has_include(<FirebaseAuth/FirebaseAuth.h>)
121
+
122
+ for (id appId in [FIRApp allApps]) {
123
+ FIRApp *app = [[FIRApp allApps] objectForKey:appId];
124
+ if ([[FIRAuth authWithApp:app] canHandleNotification:userInfo]) {
125
+ DLog(@"didReceiveRemoteNotification Firebase Auth handled the notification with instance: %@",
126
+ app.name);
127
+ completionHandler(UIBackgroundFetchResultNoData);
128
+ return;
129
+ }
130
+ }
131
+
132
+ // If the notification is a probe notification, always call the completion
133
+ // handler with UIBackgroundFetchResultNoData.
134
+ //
135
+ // This fixes a race condition between `FIRAuth/didReceiveRemoteNotification` and this
136
+ // module causing detox to hang when `FIRAuth/didReceiveRemoteNotification` is called first.
137
+ // see
138
+ // https://stackoverflow.com/questions/72044950/detox-tests-hang-with-pending-items-on-dispatch-queue/72989494
139
+ NSDictionary *data = userInfo[@"com.google.firebase.auth"];
140
+ if ([data isKindOfClass:[NSString class]]) {
141
+ // Deserialize in case the data is a JSON string.
142
+ NSData *JSONData = [((NSString *)data) dataUsingEncoding:NSUTF8StringEncoding];
143
+ data = [NSJSONSerialization JSONObjectWithData:JSONData options:0 error:NULL];
144
+ }
145
+ if ([data isKindOfClass:[NSDictionary class]] && data[@"warning"]) {
146
+ completionHandler(UIBackgroundFetchResultNoData);
147
+ return;
148
+ }
149
+ #endif
150
+
151
+ [[NSNotificationCenter defaultCenter]
152
+ postNotificationName:@"RNFBMessagingDidReceiveRemoteNotification"
153
+ object:userInfo];
154
+
155
+ if (userInfo[@"gcm.message_id"]) {
156
+ DLog(@"didReceiveRemoteNotification gcm.message_id was present %@", userInfo);
157
+
158
+ if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
159
+ // Store the completion handler to call later when the JS code finishes
160
+ RNFBMessagingAppDelegate *sharedInstance = [RNFBMessagingAppDelegate sharedInstance];
161
+ sharedInstance.completionHandler = completionHandler;
162
+
163
+ // If app is in background state, register background task to guarantee async queues aren't
164
+ // frozen.
165
+ sharedInstance.backgroundTaskId = [application beginBackgroundTaskWithExpirationHandler:^{
166
+ dispatch_get_main_queue(), ^{
167
+ if (sharedInstance.backgroundTaskId != UIBackgroundTaskInvalid) {
168
+ [application endBackgroundTask:sharedInstance.backgroundTaskId];
169
+ sharedInstance.backgroundTaskId = UIBackgroundTaskInvalid;
170
+ }
171
+ };
172
+ }];
173
+
174
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(25 * NSEC_PER_SEC)),
175
+ dispatch_get_main_queue(), ^{
176
+ if (sharedInstance.completionHandler) {
177
+ sharedInstance.completionHandler(UIBackgroundFetchResultNewData);
178
+ sharedInstance.completionHandler = nil;
179
+ }
180
+
181
+ // Stop background task after the longest timeout, async queue is okay to
182
+ // freeze again after handling period
183
+ if (sharedInstance.backgroundTaskId != UIBackgroundTaskInvalid) {
184
+ [application endBackgroundTask:sharedInstance.backgroundTaskId];
185
+ sharedInstance.backgroundTaskId = UIBackgroundTaskInvalid;
186
+ }
187
+ });
188
+
189
+ [sharedInstance.conditionBackgroundMessageHandlerSet lock];
190
+ @try {
191
+ DLog(@"didReceiveRemoteNotification sharedInstance.backgroundMessageHandlerSet = %@",
192
+ sharedInstance.backgroundMessageHandlerSet ? @"YES" : @"NO");
193
+ if (sharedInstance.backgroundMessageHandlerSet) {
194
+ // Normal path, backgroundMessageHandlerSet has already been set, queue the notification
195
+ // for immediate delivery
196
+ dispatch_async(dispatch_get_main_queue(), ^{
197
+ [[RNFBRCTEventEmitter shared]
198
+ sendEventWithName:@"messaging_message_received_background"
199
+ body:[RNFBMessagingSerializer remoteMessageUserInfoToDict:userInfo]];
200
+ });
201
+ DLog(@"didReceiveRemoteNotification without waiting for backgroundMessageHandlerSet to "
202
+ @"be set");
203
+ } else {
204
+ // This spin needs to be on a background/concurrent queue to await the setup of
205
+ // backgroundMessageHandlerSet and not block the main thread
206
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
207
+ // Reaquire the lock in this new closure
208
+ [sharedInstance.conditionBackgroundMessageHandlerSet lock];
209
+ @try {
210
+ // Spin/wait until backgroundMessageHandlerSet
211
+ // NB it is possible while this closure was being scheduled that
212
+ // backgroundMessageHandlerSet is already set and this loop is skipped
213
+ while (!sharedInstance.backgroundMessageHandlerSet) {
214
+ DLog(@"didReceiveRemoteNotification waiting for "
215
+ @"sharedInstance.backgroundMessageHandlerSet %@",
216
+ sharedInstance.backgroundMessageHandlerSet ? @"YES" : @"NO");
217
+ if (![sharedInstance.conditionBackgroundMessageHandlerSet
218
+ waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:25]]) {
219
+ // If after 25 seconds the client hasn't called backgroundMessageHandlerSet, give
220
+ // up on this notification
221
+ ELog(@"didReceiveRemoteNotification timed out waiting for "
222
+ @"sharedInstance.backgroundMessageHandlerSet");
223
+ return;
224
+ }
225
+ }
226
+ dispatch_async(dispatch_get_main_queue(), ^{
227
+ [[RNFBRCTEventEmitter shared]
228
+ sendEventWithName:@"messaging_message_received_background"
229
+ body:[RNFBMessagingSerializer
230
+ remoteMessageUserInfoToDict:userInfo]];
231
+ });
232
+ DLog(@"didReceiveRemoteNotification after waiting for backgroundMessageHandlerSet");
233
+ } @finally {
234
+ [sharedInstance.conditionBackgroundMessageHandlerSet unlock];
235
+ }
236
+ });
237
+ }
238
+ } @finally {
239
+ [sharedInstance.conditionBackgroundMessageHandlerSet unlock];
240
+ }
241
+ } else {
242
+ DLog(@"didReceiveRemoteNotification while app was in foreground");
243
+ [[RNFBRCTEventEmitter shared]
244
+ sendEventWithName:@"messaging_message_received"
245
+ body:[RNFBMessagingSerializer remoteMessageUserInfoToDict:userInfo]];
246
+ completionHandler(UIBackgroundFetchResultNoData);
247
+ }
248
+ }
249
+ }
250
+
251
+ @end
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <Firebase/Firebase.h>
19
+ #import <Foundation/Foundation.h>
20
+
21
+ NS_ASSUME_NONNULL_BEGIN
22
+
23
+ @interface RNFBMessagingFIRMessagingDelegate : NSObject <FIRMessagingDelegate>
24
+
25
+ + (_Nonnull instancetype)sharedInstance;
26
+
27
+ - (void)observe;
28
+
29
+ @end
30
+
31
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <GoogleUtilities/GULAppDelegateSwizzler.h>
19
+ #import <RNFBApp/RNFBRCTEventEmitter.h>
20
+ #import <objc/message.h>
21
+ #import <objc/runtime.h>
22
+
23
+ #import "RNFBMessaging+FIRMessagingDelegate.h"
24
+ #import "RNFBMessagingSerializer.h"
25
+
26
+ @implementation RNFBMessagingFIRMessagingDelegate
27
+
28
+ + (instancetype)sharedInstance {
29
+ static dispatch_once_t once;
30
+ __strong static RNFBMessagingFIRMessagingDelegate *sharedInstance;
31
+ dispatch_once(&once, ^{
32
+ sharedInstance = [[RNFBMessagingFIRMessagingDelegate alloc] init];
33
+ });
34
+ return sharedInstance;
35
+ }
36
+
37
+ - (void)observe {
38
+ static dispatch_once_t once;
39
+ __weak RNFBMessagingFIRMessagingDelegate *weakSelf = self;
40
+ dispatch_once(&once, ^{
41
+ RNFBMessagingFIRMessagingDelegate *strongSelf = weakSelf;
42
+ [FIRMessaging messaging].delegate = strongSelf;
43
+ });
44
+ }
45
+
46
+ #pragma mark -
47
+ #pragma mark FIRMessagingDelegate Methods
48
+
49
+ // JS -> `onTokenRefresh`
50
+ - (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
51
+ if (fcmToken == nil) { // Don't crash when the token is reset
52
+ return;
53
+ }
54
+ [[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_token_refresh"
55
+ body:@{@"token" : fcmToken}];
56
+
57
+ // If the users AppDelegate implements messaging:didReceiveRegistrationToken: then call it
58
+ SEL messaging_didReceiveRegistrationTokenSelector =
59
+ NSSelectorFromString(@"messaging:didReceiveRegistrationToken:");
60
+ if ([[GULAppDelegateSwizzler sharedApplication].delegate
61
+ respondsToSelector:messaging_didReceiveRegistrationTokenSelector]) {
62
+ void (*usersDidReceiveRegistrationTokenIMP)(id, SEL, FIRMessaging *, NSString *) =
63
+ (typeof(usersDidReceiveRegistrationTokenIMP))&objc_msgSend;
64
+ usersDidReceiveRegistrationTokenIMP([GULAppDelegateSwizzler sharedApplication].delegate,
65
+ messaging_didReceiveRegistrationTokenSelector, messaging,
66
+ fcmToken);
67
+ }
68
+ }
69
+
70
+ @end
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <Foundation/Foundation.h>
19
+
20
+ NS_ASSUME_NONNULL_BEGIN
21
+
22
+ @interface RNFBMessagingNSNotificationCenter : NSObject
23
+
24
+ + (_Nonnull instancetype)sharedInstance;
25
+ @property(nonatomic) BOOL isHeadless;
26
+
27
+ @end
28
+
29
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ #import <Firebase/Firebase.h>
18
+ #import <RNFBApp/RNFBJSON.h>
19
+ #import <RNFBApp/RNFBRCTEventEmitter.h>
20
+ #import <React/RCTConvert.h>
21
+ #import <React/RCTRootView.h>
22
+
23
+ #import "RNFBMessaging+AppDelegate.h"
24
+ #import "RNFBMessaging+FIRMessagingDelegate.h"
25
+ #import "RNFBMessaging+NSNotificationCenter.h"
26
+ #import "RNFBMessaging+UNUserNotificationCenter.h"
27
+
28
+ @implementation RNFBMessagingNSNotificationCenter
29
+ @synthesize isHeadless;
30
+ + (instancetype)sharedInstance {
31
+ static dispatch_once_t once;
32
+ __strong static RNFBMessagingNSNotificationCenter *sharedInstance;
33
+ dispatch_once(&once, ^{
34
+ sharedInstance = [[RNFBMessagingNSNotificationCenter alloc] init];
35
+ });
36
+ return sharedInstance;
37
+ }
38
+
39
+ - (void)observe {
40
+ static dispatch_once_t once;
41
+ __weak RNFBMessagingNSNotificationCenter *weakSelf = self;
42
+ dispatch_once(&once, ^{
43
+ RNFBMessagingNSNotificationCenter *strongSelf = weakSelf;
44
+
45
+ // Application
46
+ // JS -> `getInitialNotification`
47
+ // ObjC -> Initialize other delegates & observers
48
+ [[NSNotificationCenter defaultCenter]
49
+ addObserver:strongSelf
50
+ selector:@selector(application_onDidFinishLaunchingNotification:)
51
+ name:UIApplicationDidFinishLaunchingNotification
52
+ object:nil];
53
+
54
+ // Application
55
+ // ObjC - > Mutates the root React components initialProps to toggle `isHeadless` state
56
+ [[NSNotificationCenter defaultCenter] addObserver:strongSelf
57
+ selector:@selector(application_onDidEnterForeground)
58
+ name:UIApplicationWillEnterForegroundNotification
59
+ object:nil];
60
+ });
61
+ }
62
+
63
+ // start observing immediately on class load - specifically for
64
+ // UIApplicationDidFinishLaunchingNotification
65
+ + (void)load {
66
+ [[self sharedInstance] observe];
67
+ }
68
+
69
+ #pragma mark -
70
+ #pragma mark Application Notifications
71
+
72
+ - (void)application_onDidFinishLaunchingNotification:(nonnull NSNotification *)notification {
73
+ // setup our delegates & swizzling after app finishes launching
74
+ // these methods are idempotent so can safely be called multiple times
75
+ [[RNFBMessagingAppDelegate sharedInstance] observe];
76
+ [[RNFBMessagingUNUserNotificationCenter sharedInstance] observe];
77
+ [[RNFBMessagingFIRMessagingDelegate sharedInstance] observe];
78
+
79
+ RCTRootView *rctRootView;
80
+ if ([UIApplication sharedApplication].delegate != nil &&
81
+ [UIApplication sharedApplication].delegate.window != nil &&
82
+ [UIApplication sharedApplication].delegate.window.rootViewController != nil &&
83
+ [UIApplication sharedApplication].delegate.window.rootViewController.view != nil &&
84
+ [[UIApplication sharedApplication].delegate.window.rootViewController.view
85
+ isKindOfClass:[RCTRootView class]]) {
86
+ rctRootView =
87
+ (RCTRootView *)[UIApplication sharedApplication].delegate.window.rootViewController.view;
88
+ }
89
+
90
+ // #if !(TARGET_IPHONE_SIMULATOR)
91
+ if ([[RNFBJSON shared] getBooleanValue:@"messaging_ios_auto_register_for_remote_messages"
92
+ defaultValue:YES]) {
93
+ [[UIApplication sharedApplication] registerForRemoteNotifications];
94
+ }
95
+ // #endif
96
+
97
+ if (notification.userInfo[UIApplicationLaunchOptionsRemoteNotificationKey]) {
98
+ if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
99
+ isHeadless = YES;
100
+ if (rctRootView != nil) {
101
+ NSMutableDictionary *appPropertiesDict = rctRootView.appProperties != nil
102
+ ? [rctRootView.appProperties mutableCopy]
103
+ : [NSMutableDictionary dictionary];
104
+ if ([appPropertiesDict objectForKey:@"isHeadless"] != nil &&
105
+ [appPropertiesDict[@"isHeadless"] isEqual:@([RCTConvert BOOL:@(NO)])]) {
106
+ appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(isHeadless)]);
107
+ rctRootView.appProperties = appPropertiesDict;
108
+ }
109
+ }
110
+
111
+ // #if !(TARGET_IPHONE_SIMULATOR)
112
+ // When an app launches in the background (BG mode) and is launched with the notification
113
+ // launch option the app delegate method
114
+ // application:didReceiveRemoteNotification:fetchCompletionHandler: will not get called unless
115
+ // registerForRemoteNotifications was called early during app initialization - we call it here
116
+ // in this scenario as the user can only call this via JS, at which point it'd be too late
117
+ // resulting in the app being terminated. called irregardless of
118
+ // `messaging_ios_auto_register_for_remote_messages` as this is most likely an app launching
119
+ // as a result of a remote notification - so has been registered previously
120
+ [[UIApplication sharedApplication] registerForRemoteNotifications];
121
+ // #endif
122
+ } else {
123
+ isHeadless = NO;
124
+ if (rctRootView != nil) {
125
+ NSMutableDictionary *appPropertiesDict = rctRootView.appProperties != nil
126
+ ? [rctRootView.appProperties mutableCopy]
127
+ : [NSMutableDictionary dictionary];
128
+ if ([appPropertiesDict objectForKey:@"isHeadless"] != nil &&
129
+ [appPropertiesDict[@"isHeadless"] isEqual:@([RCTConvert BOOL:@(YES)])]) {
130
+ appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(isHeadless)]);
131
+ rctRootView.appProperties = appPropertiesDict;
132
+ }
133
+ }
134
+ }
135
+ } else {
136
+ isHeadless = NO;
137
+ if (rctRootView != nil) {
138
+ NSMutableDictionary *appPropertiesDict = rctRootView.appProperties != nil
139
+ ? [rctRootView.appProperties mutableCopy]
140
+ : [NSMutableDictionary dictionary];
141
+ if ([appPropertiesDict objectForKey:@"isHeadless"] != nil &&
142
+ [appPropertiesDict[@"isHeadless"] isEqual:@([RCTConvert BOOL:@(YES)])]) {
143
+ appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(isHeadless)]);
144
+ rctRootView.appProperties = appPropertiesDict;
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ - (void)application_onDidEnterForeground {
151
+ isHeadless = NO;
152
+ if ([UIApplication sharedApplication].delegate != nil &&
153
+ [UIApplication sharedApplication].delegate.window != nil &&
154
+ [UIApplication sharedApplication].delegate.window.rootViewController != nil &&
155
+ [UIApplication sharedApplication].delegate.window.rootViewController.view != nil &&
156
+ [[UIApplication sharedApplication].delegate.window.rootViewController.view
157
+ isKindOfClass:[RCTRootView class]]) {
158
+ RCTRootView *rctRootView =
159
+ (RCTRootView *)[UIApplication sharedApplication].delegate.window.rootViewController.view;
160
+
161
+ if (rctRootView.appProperties != nil &&
162
+ [rctRootView.appProperties[@"isHeadless"] isEqual:@(YES)]) {
163
+ NSMutableDictionary *appPropertiesDict = [rctRootView.appProperties mutableCopy];
164
+ if ([appPropertiesDict objectForKey:@"isHeadless"] != nil &&
165
+ [appPropertiesDict[@"isHeadless"] isEqual:@([RCTConvert BOOL:@(YES)])]) {
166
+ appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(isHeadless)]);
167
+ rctRootView.appProperties = appPropertiesDict;
168
+ }
169
+ }
170
+ }
171
+ }
172
+
173
+ @end
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import <UserNotifications/UserNotifications.h>
19
+
20
+ NS_ASSUME_NONNULL_BEGIN
21
+
22
+ @interface RNFBMessagingUNUserNotificationCenter : NSObject <UNUserNotificationCenterDelegate>
23
+
24
+ @property NSDictionary *_Nullable initialNotification;
25
+ @property BOOL didOpenSettingsForNotification;
26
+ @property(nonatomic, nullable, weak) id<UNUserNotificationCenterDelegate> originalDelegate;
27
+
28
+ + (_Nonnull instancetype)sharedInstance;
29
+
30
+ - (void)observe;
31
+
32
+ - (nullable NSDictionary *)getInitialNotification;
33
+
34
+ - (NSNumber *)getDidOpenSettingsForNotification;
35
+ @end
36
+
37
+ NS_ASSUME_NONNULL_END