React NativeのNativeModuleの登録プロセスを追ってみた

参加者

@binaryta
@__syumai

前回の振り返り

  • JavaScript側でsetNativePropsが実行され、どのようにNative側に渡される値が作られるかを追い掛けた
  • 最終的に、TextInputのpropsを更新した時に、enqueueNativeCallと言うメソッドで積まれている moduleIdmethodIdparams (updatePayload) の値を特定できた
{
  moduleID: 41,
  methodID: 6,
  params: { // updatePayload
    fontSize: 40,
  },
}

ここからわかること 

  • JavaScript側で、Native側のmoduleIdとmethodIdを知っている
    • これどこに持ってる?
  • TextInputと言うのは一つのNativeModule?
  • TextInputと言うNativeModuleが登録された時に割り当てられたIDがmoduleIdなのでは?
  • 登録を行うと、JavaScriptにも、各moduleのIDが渡されている?

今回やっていくこと

  • オーバー・ザ・ブリッジ本の、NativeModulesの章を読み進めて、moduleId、methodIdがどう使われているのか突き止める

NativeModule

公式ドキュメントより

https://facebook.github.io/react-native/docs/native-modules-ios#ios-calendar-module-example

上記リンクに、iOSのCalendar APIにアクセスするNativeModuleを作成するための方法が書かれている

NativeModuleを作る方法ざっくりまとめ

  • Objective-Cのclassで、 RCTBridgeModule protocolを実装する
  • 下記の2つのマクロを使う
    • RCT_EXPORT_MODULE()
    • RCT_EXPORT_METHOD()

RCT_EXPORT_MODULE()

  • moduleの名前を吐き出して、JavaScript側から見えるようにする
  • RCT_EXPORT_MODULE(HogeManager) のように呼ぶと、HogeManagerと言う名前でexportされる
  • 名前を明示的に指定しなければ、class名がそのまま使われる
  • 接頭辞として RCT がclass名についていれば、省略した状態でexportされる (RCTHogeManager => HogeManager)

RCT_EXPORT_METHOD()

RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
  RCTLogInfo(@"Pretending to create an event %@ at %@", name, location);
}
  • methodを吐き出して、JavaScript側から呼べるようにする
  • 上記の例では、 addEvent と言うmethodがexportされ、引数としてnameとlocationの2つを受け取る設定になる
  • 実行されるmethodの実体は、 {} の中に書かれ、これをJavaScript側から呼ぶことが出来るようになる
  • 引数として指定できる型は、基本的に、JSONと相互に変換出来る型のみ
  • それ以外は、 RCTConvert helperを使って変換する

作り方を見てわかったこと

  • NativeModuleを登録する時に、moduleとmethodをそれぞれexportしていることはわかった
  • TextInputも、同様な方法でNativeModuleとして登録されている?(わからない)

TextInputの継承ツリーを追う

方針

  • この中のどこかでTextInputがRCT_EXPORT_MODULEされている?
  • であれば、TextInputのmoduleIdとmethodIdが取れるようになり、どこが具体的に呼ばれるのか特定できそう!
  • TextInputはclearisFocusedという2つのメソッドをもつので、ネイティブモジュールからexportされているのでは?(以下参照)
    https://facebook.github.io/react-native/docs/textinput#methods

見つかったもの

  • RCTSinglelineTextInputViewManager : RCTBaseTextInputViewManager
    • RCT_EXPORT_MODULE している
      • JSから直接呼べる?
    • viewメソッド
  • RCTSinglelineTextInputView : RCTBaseTextInputView
    • RCT_EXPORT_MODULE していない
  • RCTBaseTextInputView : RCTView
    • RCT_EXPORT_MODULE していない

わかったこと

  • 全然exportしてない
  • clearisFocused は、NativeModuleと一切関係なく、普通にJSだけで実装されていた

次回やりたい事

  • ネイティブモジュールのインスタンスmoduleDataById という配列に登録している、と言うことがオーバー・ザ・ブリッジ本に書かれていたので、ここの中身を直接見に行ってみる