I have a problem of accessing NativeModules.OverlayModule using react-native. In App.tsx it shows data, in LeftSidebar.tsx it is empty. I use LeftSidebar as overlay on top of other apps. here is the code.
I have this index.js
import {AppRegistry} from 'react-native';
import LeftSidebar from 'widgets/LeftSidebar';
import App from './App';
import {name} from './app.json';
AppRegistry.registerComponent(name, () => App);
AppRegistry.registerComponent('leftSidebar', () => LeftSidebar);
App.tsx (I can get data in console.log)
import FixedBottomButton from 'components/FixedBottomButton';
import {NativeModules} from 'react-native';
function App(): React.JSX.Element {
console.log('APP', NativeModules.OverlayModule); // {disable: {}...}
return <FixedBottomButton />;
}
export default App;
LeftSidebar.tsx (I can't get data in console.log)
import React, {memo} from 'react';
import {
View,
Image,
TouchableOpacity,
StyleSheet,
NativeModules,
} from 'react-native';
import {xLgIcon} from 'assets/icons';
import {useLeftSidebar} from './useLeftSidebar';
function LeftSidebar(): JSX.Element {
console.log('LeftSidebar', NativeModules.OverlayModule); // null
const {handleClose} = useLeftSidebar();
const list = [];
return (
<View style={styles.container}>
{list.map(({source, onPress}, index) => (
<TouchableOpacity key={index} onPress={onPress}>
<Image source={source} style={styles.icon} />
</TouchableOpacity>
))}
</View>
);
}
export default memo(LeftSidebar);
here is my OverlayModule.kt
package com.autoclickbot
class OverlayModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
override fun getName() = "OverlayModule"
@ReactMethod
fun run(state: Boolean {
val hasPermission = Settings.canDrawOverlays(reactContext)
if (!hasPermission) {
requestOverlayPermission();
return
}
}
@ReactMethod
fun requestOverlayPermission() {
Log.d("OverlayModule", "requestOverlayPermission method called")
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:${reactContext.packageName}"))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
reactContext.startActivity(intent)
}
@ReactMethod
fun enable() {
Log.d("OverlayModule", "display method called")
val intent = Intent(reactContext, OverlayService::class.java)
reactContext.startService(intent)
}
@ReactMethod
fun disable() {
Log.d("OverlayModule", "closeOverlay method called")
val intent = Intent(reactContext, OverlayService::class.java)
reactContext.stopService(intent)
}
}
MyAppPackage.kt
class MyAppPackage : ReactPackage {
override fun createViewManagers(reactContext: ReactApplicationContext): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()
override fun createNativeModules(reactContext: ReactApplicationContext): MutableList<NativeModule> {
return mutableListOf(
OverlayModule(reactContext),
)
}
}
OverlayService.kt
class OverlayService : Service() {
private var mWindowManager: WindowManager? = null
private var mReactRootView: ReactRootView? = null
private var mReactInstanceManager: ReactInstanceManager? = null
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("OverlayService", "onStartCommand called")
val type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
else WindowManager.LayoutParams.TYPE_PHONE
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
type,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT
)
params.gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL // Set gravity to top left (Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
mWindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
mReactRootView = ReactRootView(this)
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(application)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackage(MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE) // Use BEFORE_CREATE
.build()
mReactRootView?.startReactApplication(mReactInstanceManager, "leftSidebar", null)
mWindowManager?.addView(mReactRootView, params)
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
Log.d("OverlayService", "onDestroy called")
if (mReactRootView != null) {
mWindowManager?.removeView(mReactRootView)
}
}
}
problem solved after adding MyAppPackage() in OverlayService.kt
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(application)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackage(MainReactPackage())
.addPackage(MyAppPackage()) // adding my package
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE) // Use BEFORE_CREATE
.build()