2017-10-25 7 views
1

複数のActivity/Fragmentのインスタンスがのインスタンスを共有するハイブリッドアプリケーションでは、ReactInstanceManagerインスタンスを共有するため、Activity/Fragmentインスタンスごとにネイティブモジュールを挿入する公式な方法はないようです。本質的に、ネイティブモジュールは、.jsファイルに存在するjavascriptモジュールのようなシングルトンです。同じFragmentの異なるインスタンス内で実行されているJSコードがFragmentのローカルプロパティと対話するためにJava/Kotlin側にアクセスしたい場合、これは意図した動作ではありません。非静的でオンデマンドのNativeModuleをネイティブAndroidに反応させる方法

registerAdditionalPackages()の方法をReactInstanceManagerにしようとしましたが、同時に複数のFragment s/Activitysを使用すると、以下のようなアサーションエラーで失敗します。

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

これは、スレッドの安全性の問題はなくregisterAdditionalPackages()実装の設計結果ではなかったです。別の方法がありますか?もしそうなら、JS側でどのように注入モジュールにアクセスしますか?

答えて

0

この問題は数日間起き続けました。最後に、私は解決策を持っています。私はそれが将来誰かを助けることを願っています。このソリューションはKotlinにありますが、Javaに変換するのは簡単です。 someVariable!!は "not null"アサーションで、大文字のSomeObject()はインスタンスの作成、SomeType:SomeOtherTypeは継承または実装、val someVar:SomeTypeは変数宣言です。残りは同じです。

ステップ:

1)を実行し、あなたのRNランタイムにモジュールを挿入したい時に以下のコード。 Activity.onCreate()またはFragment.onCreateView()の中には良い候補がいくつかあります。 mReactInstanceManagerはあなたのシングルトンのグローバル・リアクション・ランタイムです。 packageToInjectの定義については後述する。 packageToInject内部に保持

synchronized(mReactInstanceManager!!.currentReactContext!!) { 
    val nativeModuleRegistryBuilder = NativeModuleRegistryBuilder(
     mReactInstanceManager!!.currentReactContext as ReactApplicationContext?, 
     mReactInstanceManager!!, 
     false 
    ) 

    nativeModuleRegistryBuilder.processPackage(packageToInject) 
    mReactInstanceManager!!.currentReactContext!!.catalystInstance!!.extendNativeModules(nativeModuleRegistryBuilder.build()) 
} 

2)インスタンスFragment/Activityインスタンスごとに一意の名前で一意モジュールを有するように以下のように調製されなければなりません。 FragmentまたはActivityのこれらの内部クラスを作成します。あなたはどちらかあなたのActivity.onCreate()Fragment.onCreateView()mReactRootView.startReactApplication()を開始するとき

class ReactManagerPackage : ReactPackage { 
    override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> { 
     return emptyList() 
    } 

    override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> { 
     val modules = ArrayList<NativeModule>() 
     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)は小道具としてmyFragmentOrActivity.hashCode().toString()を渡します。第3引数として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") 

Profit!