I have following implementation (I've skipped imports and some parts):
class MainActivity : ReactActivity(), DefaultHardwareBackBtnHandler, PermissionAwareActivity {
var communicationModule: CommunicationModule? = null
fun sendMessageToNative(message: String) {
val manager = (application as MyApplication).reactNativeHost.reactInstanceManager
val reactContext = manager.currentReactContext
if (reactContext != null) {
val module = reactContext?.getNativeModule(CommunicationModule::class.java)
if (module != null) {
module.emitOnPush(message)
}
} else {
manager.addReactInstanceEventListener(object :
ReactInstanceManager.ReactInstanceEventListener {
override fun onReactContextInitialized(context: ReactContext) {
val module = context.getNativeModule(CommunicationNewModule::class.java)
if (module != null) {
module.emitOnPush(message)
}
}
})
manager.createReactContextInBackground()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(null)
// ...
}
override fun onBackPressed() {
super.onBackPressed()
sendMessageToNative("MY_MESSAGE") // this doesn't work (no event on RN side)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
// assume this is not empty
val myMessage = intent?.extras["message"]
sendMessageToNative("MY_MESSAGE") // this doesn't work (no event on RN side)
}
}
and Turbo Module (NativeCommunication.ts)
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
import type { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes';
export interface Spec extends TurboModule {
onPush: EventEmitter<string>;
}
export default TurboModuleRegistry.getEnforcing<Spec>(
'NativeCommunication',
);
and Kotlin's (CommunicationModule.kt)
@ReactModule(name = CommunicationModule.NAME)
class CommunicationModule(private val reactContext: ReactApplicationContext) : NativeCommunicationSpec(reactContext) {
override fun getName() = NAME
companion object {
const val NAME = "NativeCommunication"
}
}
and finally setting listeners on React Native side (e.g. in some page or MyPage.tsx)
const MyPage = ({ navigation }: MyPageProps): JSX.Element => {
const listenerSubscription = useRef<null | EventSubscription>(null);
const callbackMethod = (message: string) => { console.log(message) }
useEffect(() => {
listenerSubscription.current = NativeCommunication?.onPush(callbackMethod);
return () => {
listenerSubscription.current?.remove();
listenerSubscription.current = null;
}
}, []);
}
PROBLEM: events trigered in onNewIntent and onBackPressed do not arrive to React Native.
My implementation works (events arrive to React Native) only when triggered from
fun MainActivity.newSessionTimer(): CountDownTimer {
val sessionTimerFinishAfter = inMilliseconds(30, TimeUnit.Second)
val sessionTimerTickEvery = inMilliseconds(30, TimeUnit.Second)
return object : CountDownTimer(sessionTimerFinishAfter, sessionTimerTickEvery) {
override fun onTick(millisUntilFinished: Long) { /** no-op */ }
override fun onFinish() { sendMessageToNative("MY_MESSAGE") }
}
}
GOAL: Be able to send messages from onNewIntent and onBackPressed and receive them on MyPage.tsx