如何注入非静态,按需NativeModules到React Native Android?

在混合应用程序中,多个Activity / Fragment实例嵌套自己的ReactRootView共享一个ReactInstanceManager实例,似乎没有官方的方式为每个Activity / Fragment实例注入本地模块。 就本质而言,本地模块是单独的,就像驻留在.js文件中的javascript模块一样。 如果在同一个Fragment不同实例中运行的JS代码想要访问Java / Kotlin端与Fragment的本地属性进行交互,那么这不是预期的行为。

我尝试使用ReactInstanceManager registerAdditionalPackages()方法,但它失败,像下面的断言错误,如果多个Fragment s / Activity s同时使用。

"Extending native modules with non-matching application contexts."

这不是线程安全问题,而是registerAdditionalPackages()实现的设计结果。 有没有其他的方法,如果是的话,你如何访问JS端的注入模块?

这个问题让我几天都不清醒。 最后,我有一个解决方案。 我希望它能帮助未来的人。 解决方案在Kotlin中,但将其翻译成Java是相当简单的。 someVariable!! 是一个“非空”的断言,大写的SomeObject()调用是实例创建, SomeType:SomeOtherType是inheritance或实现, val someVar:SomeType是一个variables声明。 其余的是一样的。

脚步:

1)在想要将模块注入到RN运行时的时候运行下面的代码。 Activity.onCreate()Fragment.onCreateView()是一些很好的候选人。 mReactInstanceManager是你的单例,全局反应运行时。 packageToInject定义将在稍后给出。

 synchronized(mReactInstanceManager!!.currentReactContext!!) { val nativeModuleRegistryBuilder = NativeModuleRegistryBuilder( mReactInstanceManager!!.currentReactContext as ReactApplicationContext?, mReactInstanceManager!!, false ) nativeModuleRegistryBuilder.processPackage(packageToInject) mReactInstanceManager!!.currentReactContext!!.catalystInstance!!.extendNativeModules(nativeModuleRegistryBuilder.build()) } 

2) packageToInject内部的packageToInject必须像下面那样准备,每个Fragment / Activity实例都有一个唯一的名称模块。 使这些FragmentActivity内部类。

 class ReactManagerPackage : ReactPackage { override fun createViewManagers(reactContext: ReactApplicationContext): List> { return emptyList() } override fun createNativeModules(reactContext: ReactApplicationContext): List { val modules = ArrayList() modules.add(ReactBridge(reactContext)) return modules } } class ReactBridge(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { override fun getName(): String { return myFragmentOrActivity.hashCode().toString() } @ReactMethod fun showToast(text: String) { Toast.makeText(text, Toast.LENGTH_SHORT).show() } } 

3)当你在你的Activity.onCreate()Fragment.onCreateView()启动mReactRootView.startReactApplication()时,传递myFragmentOrActivity.hashCode().toString()作为道具。 把它放在你给mReactRootView.startReactApplication()作为第三个参数的包中。

 val bundle = Bundle() bundle.putString("fragmentOrActivityHash", myFragmentOrActivity.hashCode().toString()) mReactRootView.startReactApplication(mReactInstanceManager, "MyRootComponent", bundle ) 

4)使用你的组件中的道具(本例中为MyRootComponent )来检索你的特定的桥梁。 (JavaScript)的

 NativeModules[this.props.fragmentOrActivityHash].showToast("It works") 

利润!