環境: flutter sdk v1.5.4-hotfix.1@stable 對應 flutter engine: 52c7a1e849a170be4b2b2fe34142ca2c0a6fea1f
站在平臺端的視角對通道有一個通觀概覽的認知之後就需要深入內裡對通訊機制需要一個深入剖析了,之前已經瞭解到FlutterJNI.dispatchPlatformMessage
是平臺層(java)傳送資料呼叫的最後一層,那麼繼續這個呼叫序列:
FluttereJNI.dispatchPlatformMessage
nativeDispatchPlatformMessage(FlutterJNI.java)
DispatchPlatformMessage(platform_view_android_jni.cc:56)
AndroidShellHolder::GetPlatformView(platform_view_android_jni.cc:421)
PlatformViewAndroid::DispatchPlatformMessage(platform_view_android.cc:92)
TaskRunners::GetPlatformTaskRunner => PlatformView::task_runners_
new PlatformMessageResponseAndroid()
new flutter::PlatformMessage(name, message, response)
PlatformView::DispatchPlatformMessage
PlatformView::Delegate::OnPlatformViewDispatchPlatformMessage() => Shell::On..()
::GetUITaskRunner
TaskRunner::PostTask
...Engine::DispatchPlatformMessage
複製程式碼
傳送訊息最終呼叫到了C++層的PlatformViewAndroid::DispatchPlatformMessage
方法, 又呼叫了PlatformViewAndroid
成員delegate_
的OnPlatformViewDispatchPlatformMessage
方法, 所以我們要確定PlatformView::Delegate
抽象類的實現體, 也就是要追蹤成員被建立或賦值的地方。
由建構函式可知成員PlatformView::delegate_
是建立時外部傳入,而PlatformViewAndroid
作為子類把它的delegate傳入,所以需要了解
PlatformViewAndroid
被建立時傳入的delegate物件,
android_shell_holder.cc:63
可知建立PlatformViewAndroid
時傳入的的delegate物件實際為Shell
,在其方法中又非同步呼叫了成員engine_
的方法,即Engine::DispatchPlatformMessage
方法
所以我們需要
- 明確
PlatformViewAndroid
被建立的流程 - 明確
Engine
被賦值或建立的時機
建立PlatformViewAndroid
流程:
AndroidShellHolder::AndroidShellHolder()
ThreadHost::ThreadHost
platform_thread=
fml::MessageLoop::EnsureInitializedForCurrentThread
platform_runner=fml::MessageLoop::GetCurrent().GetTaskRunner()
Shell::Create()
DartVMRef::Create(settings)
Shell::Create()
TaskRunner::RunNowOrPostTask
lamda() => Shell::CreateShellOnPlatformThread()
Shell::CreateCallback<PlatformView>(Shell&) => on_create_platform_view
new PlatformViewAndroid(Shell,...)
複製程式碼
最重要的是Shell::Create
這個方法,在呼叫時傳入了一個回撥,這個回撥呼叫了Shell::CreateShellOnPlatformThread()
, 繼續回撥了on_create_platform_view
,它的實現體在AndroidShellHolder
建構函式上下文中。
建立Shell::engine_[Engine]流程:
第二個問題剛好承接了對每一個問題的分析: 我們是在建立Shell
的時候建立了PlatformViewAndroid
物件
shell.cc:38
可知engine_
也是外部傳入
Shell::CreateShellOnPlatformThread()
new Shell()
on_create_platform_view => AndroidShellHolder.on_create_platform_view
std::make_unique<PlatformViewAndroid>()
TaskRunner::RunNowOrPostTask
...lamda => engine = std::make_unique<Engine>() (shell.cc:131)
Shell::Setup
engine_ = std::move(engine); (shell.cc:388)
複製程式碼
在Shell::CreateShellOnPlatformThread
中先建立了Shell
例項, 接著建立了PlatformView
例項,接著又非同步執行了一個lamda,建立了Engine
例項
這樣前面兩個重要物件的建立時機問題就終於明確了。
繼續我們第一階段的呼叫分析, 非同步執行了Engine::DispatchPlatformMessage
Engine::DispatchPlatformMessage
RuntimeController::DispatchPlatformMessage
Window::DispatchPlatformMessage
tonic::DartInvokeField(...,"_dispatchPlatformMessage")
複製程式碼
最終由此進行到了Dart層呼叫
因為在AndroidShellHolder
的建構函式中Flutter建立了Shell
物件,所以同樣需要明確:
建立AndroidShellHolder
流程:
FlutterActivity.onCreate (FlutterActivity.java:89)
FlutterActivityDelegate.onCreate() (FlutterActivityDelegate.java:160)
FlutterView.FlutterView() (FlutterView.java:139)
new FlutterNativeView(Context) (FlutterNativeView.java:47)
FlutterNativeView.attach(this, false) (FlutterNativeView.java:165)
FlutterJNI.attachToNative (FlutterJNI.java:423)
AttachJNI(platform_view_android_jni.cc:149)
java_object(env, flutterJNI)
std::make_unique<AndroidShellHolder>(java_object)
AndroidShellHolder::IsValid
reinterpret_cast<jlong>
複製程式碼
比較容易發現建立的時機正是FlutterJNI
繫結到FlutterNativeView
, 而FlutterJNI
的成員nativePlatformViewId
代表的正是C++AndroidShellHolder
物件,在這個過程中重要物件如Shell
和Engine
相繼被建立。
所以每次傳送資料(或者平臺呼叫dart方法)都是FlutterJNI
物件將成員nativePlatformViewId
傳入c++層,轉成AndroidShellHolder
物件通過Engine
最終呼叫到dart層