Flutter Androidのソースコードを読む(FlutterApplication編)
こんにちは、tkyです。
今日はFlutter Androidのソースコードを読んで、調べた軌跡を残したいと思います。
本記事は確定的は情報はなく、tkyが右往左往しながら調べたことと感じたことをまとめたもので、仕組みを解説するような内容ではないことを予めここに明記致します。
また、リアルタイムで勉強しながら記事を書いているので誤りがある場合、随時訂正していきます。
(というか正直難しい・・・いろいろ読み進めてみて、dartと dart VMのことを知らないと理解できないのではないかと感じました。)
今回読んでいくのはこれ
flutter.jar
Android Studioにはjarのclassファイルに定義ジャンプすることができるので⌘ + クリック(winの場合は ctrl + クリック)で読めますが、 ここで読めるのはあくまでjavaで書かれた領域だけなのでネイティブコード(C/C++の領域のことを指します)も見ることを考慮して flutter/engineもcloneしておきます。
目次
- まずはAndroidManifest.xmlから
- そもそもflutter.jarはどこにあるのか?
- FlutterApplication
- FlutterMain
- startInitialization
- VM snapshotとは
- instrって何
- isolateって何
- app.soとは
- app.flxって何
- startInitialization
FlutterActivityについては別途調べて見ようと思います。
まずはAndroidManifest.xmlから
とにもかくにもこれから見るのが最初の足がかりとしては良いかと思います。
どうやらFlutterApplication
とMainActivity
によって構成されていることがわかりました。
MainActivity
はFlutterActivity
を継承しているようですね。
AndroidManifest.xml抜粋
<application android:name="io.flutter.app.FlutterApplication" android:label="kasikari_memo" android:icon="@mipmap/ic_launcher"> <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <meta-data android:name="io.flutter.app.android.SplashScreenUntilFirstFrame" android:value="true" /> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application>
MainActivity.kt抜粋
class MainActivity: FlutterActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) GeneratedPluginRegistrant.registerWith(this) } }
ここで新しいワードが3つ出てきています。上から順番に調べていきますが、本記事ではFlutterApplication
だけフォーカスします。
- FlutterApplication
- FlutterActivity
- GeneratedPluginRegistrant
このクラス郡がflutter.jar
内に格納されている、ということですね。
そもそもflutter.jarはどこにあるのか?
調べたところ、こちらにあるようでした。android-arm
の部分はアーキテクチャによってパスが変わりそうです。
Androidの場合: /Users/${username}/flutter/bin/cache/artifacts/engine/android-arm iOSの場合: /Users/t.takenaka/flutter/bin/cache/artifacts/engine/ios
試しにJD-GUIツール(jarファイル内の.classファイルの可視化ツール)で見るとたしかに、ちゃんとFlutterActivityなどの存在が確認できました。
FlutterApplication
onCreateの処理はこの様になっていました。何かの初期化処理をしているようです。
@CallSuper public void onCreate() { super.onCreate(); FlutterMain.startInitialization(this); }
FlutterMain
ここから一気に難しくなります。startInitialization()はstaticメソッドですね。
startInitialization()
このメソッドではざっくり4つの処理をしていました。3種類の初期化メソッドと、libflutter.so
ファイルのロード処理のようです。
initConfig(applicationContext); initAot(applicationContext); initResources(applicationContext); System.loadLibrary("flutter");
この辺のinit処理で1つ1つコードを見ていくと、理解を超えそうでしたので、
initConfig()内に記述されていた、要所要所の単語を調べていく形で理解していこうと思います。
libflutter.soとは
flutter engineの以下のネイティブコードのライブラリですね。BUILD.gn
がmakefileになります。
FlutterJNI.java
がJava側の定義、
platform_view_android_jni.h
がC++側の定義です。
$ ls shell/platform/android/io/flutter/embedding/engine/ FlutterEngine.java FlutterJNI.java dart renderer $ls shell/platform/android/ AndroidManifest.xml android_surface.cc io BUILD.gn android_surface.h library_loader.cc android_context_gl.cc android_surface_gl.cc platform_message_response_android.cc android_context_gl.h android_surface_gl.h platform_message_response_android.h android_environment_gl.cc android_surface_software.cc platform_view_android.cc android_environment_gl.h android_surface_software.h platform_view_android.h android_external_texture_gl.cc android_surface_vulkan.cc platform_view_android_jni.cc android_external_texture_gl.h android_surface_vulkan.h platform_view_android_jni.h android_native_window.cc apk_asset_provider.cc vsync_waiter_android.cc android_native_window.h apk_asset_provider.h vsync_waiter_android.h android_shell_holder.cc flutter_main.cc android_shell_holder.h flutter_main.h
VM snapshotとは
wikiにちゃんと書いてあるんですね・・・すごい。VMはDart VMのことですね。
アプリの起動を高速化するため仕組みのようです。
dartコードを構文解析して得られたバイナリデータのようです。dartコードをロードしたオブジェクトが書き込まれている感じでしょうか。 そのスナップショットを実行すると短い起動時間で処理を再現できるというものみたいです。
僕らが書いたmain.dart
はapkビルド時にsnapshotになって、snapshotをDart VMに食わせているのかと推測していますが、間違っていたらスミマセン。。
github.com
以下のドキュメントも参考にしました。 https://www.cresc.co.jp/tech/java/Google_Dart/DartLanguageGuide.pdf
instrって何
instructions(命令?)
のことらしいですが、スナップショット自体と処理を別々に管理しているのでしょうか。(ヒープスナップショットと処理スナップショットとか?)
isolateって何
このことであってますかね。Flutter (dart)は基本的にはシングルスレッドですが、 isolateというライブラリを使用することで並列処理が実現できるようになるようです。
その並列の単位をisolate(アイソレート)と呼称し、dart vm上では必ず1アイソレート立ち上がる、と認識しています。 api.dartlang.org
app.soとは
libflutter.soと同じような感じで、libapp.soがapkの中にあるのかなと思いきや存在しない・・・
調べても全然出てこないので、そもそもこのapp.soが使われていない気もしてきました。 一応AOTビルドコマンドが存在します。 github.com
早速試してみましょう。
$ flutter build aot Building AOT snapshot in release mode (android-arm-release)... 14.4s Built to build/aot/. $ ls build/aot/ app.dill kernel_compile.d frontend_server.d kernel_compile.d.fingerprint gen_snapshot.d snapshot.d.fingerprint isolate_snapshot_data vm_snapshot_data isolate_snapshot_instr vm_snapshot_instr
app.soないじゃん 😇 コード検索してもそんなに出てこないし、もう使用されていないのか、根本的になにか勘違いしているのか 🤔
app.flxって何
Flutter SDK側を調べるとそれっぽいものが見つかりました。 ios側のビルドで使用するものっぽいです(flxはFiLe eXtensionの略称であっているのか?)
そもそもapp.flx自体がapkの中に入っていないですね。(app.soのときのapkのキャプチャ参照)
また、flutter build
でビルドできるコマンドを見てみるとflx Deprecated
と非推奨になっているので昔の名残なのかもしれませんね。
$ flutter build Flutter build commands. Usage: flutter build <subcommand> [arguments] -h, --help Print this usage information. Available subcommands: aot Build an ahead-of-time compiled snapshot of your app's Dart code. apk Build an Android APK file from your app. bundle Build the Flutter assets directory from your app. flx Deprecated ios Build an iOS application bundle (Mac OS X host only). Run "flutter help" to see global options.
おわりに
新年の調べもごと『Flutterってどうやって動いているのか?』を知りたくてFlutter Android側のコードを眺めてみました。 FlutterApplicationではlibflutter.soを使用するための準備とFlutterVMを起動する前の設定値やファイルの準備を行っているようでした。 調べてもそんなに出てこないし、まだまだわからないことが多くてツラミ感じていますが、次はMainActivity側のコードを読んで行こうと思います。