From c603816b4ab48f5f59bd036ffd21fcadd6ad7919 Mon Sep 17 00:00:00 2001 From: Beat YT <66485277+Beat-YT@users.noreply.github.com> Date: Thu, 21 Nov 2024 21:14:56 -0500 Subject: [PATCH 1/2] feat(messaging, ios): Background Completion Handler from JS --- .../RNFBMessaging/RNFBMessaging+AppDelegate.h | 2 ++ .../RNFBMessaging/RNFBMessaging+AppDelegate.m | 32 +++++++++++-------- .../ios/RNFBMessaging/RNFBMessagingModule.m | 13 ++++++++ packages/messaging/lib/index.js | 8 ++++- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.h b/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.h index c66e3e9ba6..708ff24edc 100644 --- a/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.h +++ b/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.h @@ -27,6 +27,8 @@ NS_ASSUME_NONNULL_BEGIN @property _Nullable RCTPromiseResolveBlock registerPromiseResolver; @property(nonatomic, strong) NSCondition *conditionBackgroundMessageHandlerSet; @property(nonatomic) BOOL backgroundMessageHandlerSet; +@property(nonatomic, copy) void (^completionHandler)(UIBackgroundFetchResult); +@property(nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskId; + (_Nonnull instancetype)sharedInstance; diff --git a/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m b/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m index 97de5ae361..e92939af53 100644 --- a/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m +++ b/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m @@ -156,30 +156,34 @@ - (void)application:(UIApplication *)application DLog(@"didReceiveRemoteNotification gcm.message_id was present %@", userInfo); if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { + // Store the completion handler to call later when the JS code finishes + RNFBMessagingAppDelegate *sharedInstance = [RNFBMessagingAppDelegate sharedInstance]; + sharedInstance.completionHandler = completionHandler; + // If app is in background state, register background task to guarantee async queues aren't // frozen. - UIBackgroundTaskIdentifier __block backgroundTaskId = - [application beginBackgroundTaskWithExpirationHandler:^{ - if (backgroundTaskId != UIBackgroundTaskInvalid) { - [application endBackgroundTask:backgroundTaskId]; - backgroundTaskId = UIBackgroundTaskInvalid; - } - }]; - // TODO add support in a later version for calling completion handler directly from JS when - // user JS code complete + sharedInstance.backgroundTaskId = [application beginBackgroundTaskWithExpirationHandler:^{ + if (backgroundTaskId != UIBackgroundTaskInvalid) { + [application endBackgroundTask:backgroundTaskId]; + backgroundTaskId = UIBackgroundTaskInvalid; + } + }]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(25 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - completionHandler(UIBackgroundFetchResultNewData); + if (sharedInstance.completionHandler) { + sharedInstance.completionHandler(UIBackgroundFetchResultNewData); + sharedInstance.completionHandler = nil; + } // Stop background task after the longest timeout, async queue is okay to // freeze again after handling period - if (backgroundTaskId != UIBackgroundTaskInvalid) { - [application endBackgroundTask:backgroundTaskId]; - backgroundTaskId = UIBackgroundTaskInvalid; + if (sharedInstance.backgroundTaskId != UIBackgroundTaskInvalid) { + [application endBackgroundTask:sharedInstance.backgroundTaskId]; + sharedInstance.backgroundTaskId = UIBackgroundTaskInvalid; } }); - RNFBMessagingAppDelegate *sharedInstance = [RNFBMessagingAppDelegate sharedInstance]; [sharedInstance.conditionBackgroundMessageHandlerSet lock]; @try { DLog(@"didReceiveRemoteNotification sharedInstance.backgroundMessageHandlerSet = %@", diff --git a/packages/messaging/ios/RNFBMessaging/RNFBMessagingModule.m b/packages/messaging/ios/RNFBMessaging/RNFBMessagingModule.m index 4bdfbd2a50..d7afc4a245 100644 --- a/packages/messaging/ios/RNFBMessaging/RNFBMessagingModule.m +++ b/packages/messaging/ios/RNFBMessaging/RNFBMessagingModule.m @@ -219,6 +219,19 @@ - (NSDictionary *)constantsToExport { return resolve(@([RCTConvert BOOL:@(notifCenter.isHeadless)])); } +RCT_EXPORT_METHOD(completeNotificationProcessing) { + RNFBMessagingAppDelegate *appDelegate = [RNFBMessagingAppDelegate sharedInstance]; + if (appDelegate.completionHandler) { + appDelegate.completionHandler(UIBackgroundFetchResultNewData); + appDelegate.completionHandler = nil; + } + + if (appDelegate.backgroundTaskId != UIBackgroundTaskInvalid) { + [[UIApplication sharedApplication] endBackgroundTask:appDelegate.backgroundTaskId]; + appDelegate.backgroundTaskId = UIBackgroundTaskInvalid; + } +} + RCT_EXPORT_METHOD(requestPermission : (NSDictionary *)permissions : (RCTPromiseResolveBlock)resolve diff --git a/packages/messaging/lib/index.js b/packages/messaging/lib/index.js index 50a48a0495..d75e589d4c 100644 --- a/packages/messaging/lib/index.js +++ b/packages/messaging/lib/index.js @@ -98,7 +98,13 @@ class FirebaseMessagingModule extends FirebaseModule { return Promise.resolve(); } - return backgroundMessageHandler(remoteMessage); + // Ensure the handler is a promise + const handlerPromise = Promise.resolve(backgroundMessageHandler(remoteMessage)); + handlerPromise.finally(() => { + this.native.completeNotificationProcessing(); + }); + + return handlerPromise; }); this.emitter.addListener('messaging_settings_for_notification_opened', remoteMessage => { From d49fbe0a688c55f50491aba6bd6cfcac24d8a5e8 Mon Sep 17 00:00:00 2001 From: Beat <66485277+Beat-YT@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:02:52 -0500 Subject: [PATCH 2/2] Update RNFBMessaging+AppDelegate.m --- .../ios/RNFBMessaging/RNFBMessaging+AppDelegate.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m b/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m index e92939af53..660b16fc5a 100644 --- a/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m +++ b/packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m @@ -163,9 +163,9 @@ - (void)application:(UIApplication *)application // If app is in background state, register background task to guarantee async queues aren't // frozen. sharedInstance.backgroundTaskId = [application beginBackgroundTaskWithExpirationHandler:^{ - if (backgroundTaskId != UIBackgroundTaskInvalid) { - [application endBackgroundTask:backgroundTaskId]; - backgroundTaskId = UIBackgroundTaskInvalid; + if (sharedInstance.backgroundTaskId != UIBackgroundTaskInvalid) { + [application endBackgroundTask:sharedInstance.backgroundTaskId]; + sharedInstance.backgroundTaskId = UIBackgroundTaskInvalid; } }]; @@ -246,4 +246,4 @@ - (void)application:(UIApplication *)application } } -@end \ No newline at end of file +@end