React Native - 本机模块在应用程序之外不可用

问题描述 投票:0回答:1

我在使用react-native访问NativeModules.OverlayModule时遇到问题。 在 App.tsx 中它显示数据,在 LeftSidebar.tsx 中它是空的。 我使用 LeftSidebar 作为其他应用程序之上的叠加层。 这是代码。

我有这个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(我可以在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(我无法在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);

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    left: 15,
  },
  buttonText: {
    color: 'white', // Set the text color to contrast with the background
    textAlign: 'center', // Center the text horizontally
  },
  icon: {
    width: 20,
    height: 20,
  },
});

这是我的 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),
            ClickerModule(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)
        }
    }
}
react-native react-native-modules
1个回答
0
投票

添加 MyAppPackage() 后问题解决。

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()
© www.soinside.com 2019 - 2024. All rights reserved.