如何注入非静态,按需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
实例都有一个唯一的名称模块。 使这些Fragment
或Activity
内部类。
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")
利润!