diff --git a/modules/background-task/android/src/main/java/com/expensify/reactnativebackgroundtask/ReactNativeBackgroundTaskModule.kt b/modules/background-task/android/src/main/java/com/expensify/reactnativebackgroundtask/ReactNativeBackgroundTaskModule.kt index 19d3e31d83c17..6b0f81c0e92d0 100644 --- a/modules/background-task/android/src/main/java/com/expensify/reactnativebackgroundtask/ReactNativeBackgroundTaskModule.kt +++ b/modules/background-task/android/src/main/java/com/expensify/reactnativebackgroundtask/ReactNativeBackgroundTaskModule.kt @@ -14,15 +14,26 @@ import android.content.IntentFilter import android.os.Build import android.os.PersistableBundle import android.util.Log +import com.facebook.react.modules.core.DeviceEventManagerModule +import com.facebook.react.bridge.WritableMap +import com.facebook.react.bridge.Arguments class ReactNativeBackgroundTaskModule internal constructor(context: ReactApplicationContext) : ReactNativeBackgroundTaskSpec(context) { + private fun sendEvent(eventName: String, params: WritableMap?) { + reactApplicationContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) + .emit(eventName, params) + } + private val taskReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val taskName = intent?.getStringExtra("taskName") Log.d("ReactNativeBackgroundTaskModule", "Received task: $taskName") - emitOnBackgroundTaskExecution(taskName) + val params = Arguments.createMap() + params.putString("taskName", taskName) + sendEvent("onBackgroundTaskExecution", params) } } @@ -80,6 +91,14 @@ class ReactNativeBackgroundTaskModule internal constructor(context: ReactApplica } } + override fun addListener(eventType: String?) { + // no-op + } + + override fun removeListeners(count: Double) { + // no-op + } + companion object { const val NAME = "ReactNativeBackgroundTask" } diff --git a/modules/background-task/ios/ReactNativeBackgroundTask.h b/modules/background-task/ios/ReactNativeBackgroundTask.h index 8f3f0e114501a..054f1019157d9 100644 --- a/modules/background-task/ios/ReactNativeBackgroundTask.h +++ b/modules/background-task/ios/ReactNativeBackgroundTask.h @@ -1,13 +1,14 @@ +#import #ifdef RCT_NEW_ARCH_ENABLED #import #import -@interface ReactNativeBackgroundTask : NativeReactNativeBackgroundTaskSpecBase +@interface ReactNativeBackgroundTask : RCTEventEmitter #else #import #import -@interface ReactNativeBackgroundTask : NSObject +@interface ReactNativeBackgroundTask : RCTEventEmitter #endif - (void)defineTask:(NSString *)taskName diff --git a/modules/background-task/ios/ReactNativeBackgroundTask.mm b/modules/background-task/ios/ReactNativeBackgroundTask.mm index f963c928a41ed..861168ae508fc 100644 --- a/modules/background-task/ios/ReactNativeBackgroundTask.mm +++ b/modules/background-task/ios/ReactNativeBackgroundTask.mm @@ -73,7 +73,7 @@ - (BOOL)scheduleNewBackgroundTask:(NSString *)identifier error:(NSError **)outEr // Execute all registered tasks [self->_taskExecutors enumerateKeysAndObjectsUsingBlock:^(NSString *taskName, RCTResponseSenderBlock executor, BOOL *stop) { NSLog(@"[ReactNativeBackgroundTask] Executing task: %@", taskName); - [self emitOnBackgroundTaskExecution:(taskName)]; + [self sendEventWithName:@"onBackgroundTaskExecution" body:@{@"taskName": taskName}]; }]; NSError *scheduleError = nil; @@ -105,6 +105,10 @@ - (BOOL)scheduleNewBackgroundTask:(NSString *)identifier error:(NSError **)outEr _taskExecutors[taskName] = taskExecutor; } +- (NSArray *)supportedEvents { + return @[@"onBackgroundTaskExecution"]; +} + // Don't compile this code when we build for the old architecture. #ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule: diff --git a/modules/background-task/src/NativeReactNativeBackgroundTask.ts b/modules/background-task/src/NativeReactNativeBackgroundTask.ts index 792fe28505522..737d783d9634c 100644 --- a/modules/background-task/src/NativeReactNativeBackgroundTask.ts +++ b/modules/background-task/src/NativeReactNativeBackgroundTask.ts @@ -1,12 +1,12 @@ import type {TurboModule} from 'react-native'; import {TurboModuleRegistry} from 'react-native'; -import type {EventEmitter} from 'react-native/Libraries/Types/CodegenTypes'; // We need to export the interface inline for proper TypeScript type inference with TurboModules // eslint-disable-next-line rulesdir/no-inline-named-export, @typescript-eslint/consistent-type-definitions export interface Spec extends TurboModule { defineTask(taskName: string, taskExecutor: (data: unknown) => void | Promise): Promise; - readonly onBackgroundTaskExecution: EventEmitter; + addListener: (eventType: string) => void; + removeListeners: (count: number) => void; } export default TurboModuleRegistry.getEnforcing('ReactNativeBackgroundTask'); diff --git a/modules/background-task/src/index.ts b/modules/background-task/src/index.ts index d3afe75a85bc2..d1254b991eeda 100644 --- a/modules/background-task/src/index.ts +++ b/modules/background-task/src/index.ts @@ -1,16 +1,27 @@ +import type {EmitterSubscription} from 'react-native'; +import {NativeEventEmitter} from 'react-native'; import NativeReactNativeBackgroundTask from './NativeReactNativeBackgroundTask'; type TaskManagerTaskExecutor = (data: T) => void | Promise; +const eventEmitter = new NativeEventEmitter(NativeReactNativeBackgroundTask); const taskExecutors = new Map(); +let subscription: EmitterSubscription | undefined; -NativeReactNativeBackgroundTask.onBackgroundTaskExecution((taskName) => { +function onBackgroundTaskExecution({taskName}: {taskName: string}) { const executor = taskExecutors.get(taskName); if (executor) { executor(taskName); } -}); +} + +function addBackgroundTaskListener() { + if (subscription) { + subscription.remove(); + } + subscription = eventEmitter.addListener('onBackgroundTaskExecution', onBackgroundTaskExecution); +} const TaskManager = { /** @@ -32,4 +43,6 @@ const TaskManager = { }, }; +addBackgroundTaskListener(); + export default TaskManager;