LoginSignup
8
7

More than 5 years have passed since last update.

React Native互換でAndroidのViewを描画してみた

Last updated at Posted at 2015-03-31

内部実装から追うReact Nativeの続き。

React Native互換でAndroidにViewを描画するところまでできた。
https://github.com/MisumiRize/ReactNativeSandbox

結果的にほとんどReact Nativeの写経になってしまったが単純化のために以下は省略している。

  • props, state
  • style
  • event
  • 別スレッドでのbundle実行
  • 複数のRCTRootView

JavaScriptCoreが組み込まれていないAndroidでも手軽に扱えるJavaScript処理系としてRhino上で動かしているが、とてももっさりしている。

DOM無効化

ReactComponentをrenderするにはReactUpdates.batchedUpdates()を呼び出せばよい。しかし、require('react')するとデフォルトでDOMを操作する処理が付加されてしまう。DOM操作はReact Nativeには不要なので、まずDOM機能を無効化しなければならない。

通常のReactモジュールはReactDefaultInjection.inject()で各種DOM処理やインターフェースに対する実装を登録しているので、これらの代わりにDOM処理のない実装を登録しなければならない。ReactUpdates.batchedUpdates()を実行する前に最低限登録しておかなければならないのは、以下の二つである。

  • ReactUpdates.injection.injectReconcileTransaction()
  • ReactUpdates.injection.injectBatchingStrategy()

また、これまで書いた性質ゆえに、React NativeとしてReactの各処理を呼び出せるようにするには、Reactが持つ各機能をReactとは別にrequire()してReactDefaultInjection.inject()だけは実行せずインターフェースを登録しなければならない。この例ではrenderするために必要な最小のインターフェースしか登録していないが、実際のReact Nativeはもっと多くのインターフェースが登録されている。

https://github.com/MisumiRize/ReactNativeSandbox/blob/master/src/ReactAndroid/index.js
https://github.com/facebook/react-native/blob/3c4341084396a56d66b9ebc9fb0be1d315cd43ff/Libraries/ReactIOS/ReactIOS.js

ReactNativeComponent

React Nativeの各Componentはrender()するとReactIOSNativeComponentのElementを返す。ReactNativeComponentはMixinが定義されていて、ReactデフォルトのReactCompositeComponentではなくこのMixinのmountComponent, receiveComponent, unmountComponentが発火するようになっている。mountには関係ないだろうと思ってreceiveComponentを省略するとMixinの定義が発火せずはまる。

ReactNativeComponentはmountされた際、RCTUIManagerというネイティブモジュールにViewを生成、登録するよう、RCTUIManager.createView()を呼び出している。引数としてViewのクラス名が渡されるので、このクラス名に基づいてObjective-C側でViewを生成するようにしている。

実際のReact Nativeでは別スレッドでJavaScriptが実行されているという制約もあり、UIViewとはまた別にUIViewと対応する構造体RCTShadowViewを作っている。今回の例ではJavaScriptの実行もメインスレッドでやっているのでその辺は省略した。

Viewの表示

RCTUIManager.createView()だけではViewが生成されても、実際に表示はされない。実際にRCTRootViewへとmountするためには、ReactUpdates.batchedUpdates()中にコンテナとなる要素へmountするよう、ネイティブモジュールに対して命令しなければならない。ここでもRCTUIManagerがつかわれている。RCTUIManager.manageChildren()で先ほど登録したViewの付け外しをハンドリングしている。

React Nativeを拡張するときはRCT_EXPORT()マクロを書くとあるが(React NativeサイトのExtensibilityの項目参照)、RCTUIManager.createView()RCTUIManager.manageChildren()はまさにこの方法でJavaScriptから呼び出せるようになっている。React NativeではRCTBridgeでネイティブとJavaScript間の橋渡しが行われている。互換実装ではこの辺の手間を省くために、Rhinoでグローバル変数としてRCTUIManagerを定義してJavaオブジェクトを渡した。

まとめ

ここまで実装することで、Android Viewを表示できる。
https://github.com/MisumiRize/ReactNativeSandbox/blob/master/exampleapp/index.android.js

Screenshot_2015-03-31-22-09-51.png

  • React NativeはまだAndroidに対応していないが、構成を踏襲すれば実装できる
  • 異なる言語がインターフェースする部分は小さく保たれている
  • Rhinoでは案の定遅すぎるのでV8あたりが要る
8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7