今天基於Android
分析下Flutter
的啟動流程,首先看下官網提供的框架圖,最下面一層Embedder
是特定的平臺實現,Android平臺程式碼在engine/shell/platform/android
下,其中有java的嫁接層在engine/shell/platform/android/io/flutter
下面。Embedder
層是Flutter
啟動的關鍵,在應用啟動後通過該層初始化Flutter Engine
,在Engine
中會建立DartVM
,在DartVM
中執行dart編寫的入口方法main
方法,這樣Flutter
模組就啟動成功。
1.Android平臺程式碼分析
這部分程式碼是Embedder
層的,在engine/shell/platform/android/io/flutter
下面。
首先看到FlutterApplication
中的onCreate
@CallSuper
public void onCreate() {
super.onCreate();
FlutterMain.startInitialization(this);
}
複製程式碼
接著到FlutterMain
中:
public static void startInitialization(Context applicationContext, FlutterMain.Settings settings) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
} else if (sSettings == null) {
sSettings = settings;
long initStartTimestampMillis = SystemClock.uptimeMillis();
initConfig(applicationContext);
initAot(applicationContext);
initResources(applicationContext);
System.loadLibrary("flutter");
long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
nativeRecordStartTimestamp(initTimeMillis);
}
}
複製程式碼
在這裡會進行配置資訊初始化,初始化AOT模式或者JIT模式變數,資原始檔初始化,主要是將asset
目錄下的flutter
相關資源copy
到私有目錄下,看一個手機上私有目錄下的截圖
最後呼叫JNI方法nativeRecordStartTimestamp
記錄到C++層。
FlutterApplication
執行完會執行MainActivity
中的onCreate
,主要工作會在父類FlutterActivity
中,然後委託給FlutterActivityDelegate
:
// FlutterActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.eventDelegate.onCreate(savedInstanceState);
}
// FlutterActivityDelegate
@Override
public void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(0x40000000);
window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
}
String[] args = getArgsFromIntent(activity.getIntent());
FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);
flutterView = viewFactory.createFlutterView(activity);
if (flutterView == null) {
FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
flutterView = new FlutterView(activity, null, nativeView);
flutterView.setLayoutParams(matchParent);
activity.setContentView(flutterView);
launchView = createLaunchView();
if (launchView != null) {
addLaunchView();
}
}
if (loadIntent(activity.getIntent())) {
return;
}
String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext());
if (appBundlePath != null) {
runBundle(appBundlePath);
}
}
複製程式碼
可以看到有個setContentView
,就是在這裡設定內容檢視,總結下FlutterActivityDelegate
做的事:
1.根據系統版本設定狀態列樣式
2.獲取Intent
3.
FlutterMain.ensureInitializationComplete
4.
create FlutterNativeView
5.
create FlutterView
6.設定activity的內容檢視
7.執行
appBundlePath
前面2步沒什麼說的,從第3步開始看。
2.FlutterMain
public static void ensureInitializationComplete(Context applicationContext, String[] args) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
} else if (sSettings == null) {
throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
} else if (!sInitialized) {
try {
sResourceExtractor.waitForCompletion();
List<String> shellArgs = new ArrayList();
shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
if (args != null) {
Collections.addAll(shellArgs, args);
}
if (sIsPrecompiledAsSharedLibrary) {
shellArgs.add("--aot-shared-library-path=" + new File(PathUtils.getDataDirectory(applicationContext), sAotSharedLibraryPath));
} else {
if (sIsPrecompiledAsBlobs) {
shellArgs.add("--aot-snapshot-path=" + PathUtils.getDataDirectory(applicationContext));
} else {
shellArgs.add("--cache-dir-path=" + PathUtils.getCacheDirectory(applicationContext));
shellArgs.add("--aot-snapshot-path=" + PathUtils.getDataDirectory(applicationContext) + "/" + sFlutterAssetsDir);
}
shellArgs.add("--vm-snapshot-data=" + sAotVmSnapshotData);
shellArgs.add("--vm-snapshot-instr=" + sAotVmSnapshotInstr);
shellArgs.add("--isolate-snapshot-data=" + sAotIsolateSnapshotData);
shellArgs.add("--isolate-snapshot-instr=" + sAotIsolateSnapshotInstr);
}
if (sSettings.getLogTag() != null) {
shellArgs.add("--log-tag=" + sSettings.getLogTag());
}
String appBundlePath = findAppBundlePath(applicationContext);
String appStoragePath = PathUtils.getFilesDir(applicationContext);
String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), appBundlePath, appStoragePath, engineCachesPath);
sInitialized = true;
} catch (Exception var6) {
Log.e("FlutterMain", "Flutter initialization failed.", var6);
throw new RuntimeException(var6);
}
}
}
複製程式碼
該方法必須要在主執行緒中執行並且只執行一次。並且要等sResourceExtractor
把資源copy到安裝包目錄下完成後才能往下繼續:
sResourceExtractor.waitForCompletion();
void waitForCompletion() {
if (this.mExtractTask != null) {
try {
this.mExtractTask.get();
} catch (ExecutionException | InterruptedException | CancellationException var2) {
this.deleteFiles();
}
}
}
private class ExtractTask extends AsyncTask<Void, Void, Void> {...}
複製程式碼
那麼拷貝的是哪些東西呢?看一個debug下的apk:
其中vm
開頭的是dartvm
執行需要的,isolate
就是我們用dart語言編寫的業務程式碼。
看下release
包的apk,和debug有點不一樣,多出了幾個檔案。
再回到之前的程式碼那裡,就是把assets
目錄下的這些檔案拷貝到安裝包私有目錄下的flutter_assets
.
程式碼裡面有很多的路徑名:
private static final String DEFAULT_KERNEL_BLOB = "kernel_blob.bin";
private static final String DEFAULT_FLUTTER_ASSETS_DIR = "flutter_assets";
private static String sAotSharedLibraryPath = "app.so";
private static String sAotVmSnapshotData = "vm_snapshot_data";
private static String sAotVmSnapshotInstr = "vm_snapshot_instr";
private static String sAotIsolateSnapshotData = "isolate_snapshot_data";
private static String sAotIsolateSnapshotInstr = "isolate_snapshot_instr";
private static String sFlx = "app.flx";
private static String sFlutterAssetsDir = "flutter_assets";
複製程式碼
接著會初始化一些目錄,包括appBundle路徑
,應用儲存目錄
,引擎快取目錄
等。然後會呼叫JNI方法nativeInit
在C++層初始化這些資訊,在FlutterMain
中把這些路徑設定給setting
,然後傳遞構造FlutterMain
,再儲存到全域性變數g_flutter_main
中。
// shell/platform/android/flutter_main.cc
static std::unique_ptr<FlutterMain> g_flutter_main;
void FlutterMain::Init(JNIEnv* env,
jclass clazz,
jobject context,
jobjectArray jargs,
jstring bundlePath,
jstring appStoragePath,
jstring engineCachesPath) {
std::vector<std::string> args;
args.push_back("flutter");
for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
args.push_back(std::move(arg));
}
auto command_line = fml::CommandLineFromIterators(args.begin(), args.end());
auto settings = SettingsFromCommandLine(command_line);
settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);
// Restore the callback cache.
// TODO(chinmaygarde): Route all cache file access through FML and remove this
// setter.
blink::DartCallbackCache::SetCachePath(
fml::jni::JavaStringToString(env, appStoragePath));
fml::paths::InitializeAndroidCachesPath(
fml::jni::JavaStringToString(env, engineCachesPath));
blink::DartCallbackCache::LoadCacheFromDisk();
if (!blink::DartVM::IsRunningPrecompiledCode()) {
// Check to see if the appropriate kernel files are present and configure
// settings accordingly.
auto application_kernel_path =
fml::paths::JoinPaths({settings.assets_path, "kernel_blob.bin"});
if (fml::IsFile(application_kernel_path)) {
settings.application_kernel_asset = application_kernel_path;
}
}
settings.task_observer_add = [](intptr_t key, fml::closure callback) {
fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
};
settings.task_observer_remove = [](intptr_t key) {
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
};
...
// Not thread safe. Will be removed when FlutterMain is refactored to no
// longer be a singleton.
g_flutter_main.reset(new FlutterMain(std::move(settings)));
}
複製程式碼
接著看上面第四部create FlutterNativeView
.
3.FlutterNativeView
public FlutterNativeView(Context context, boolean isBackgroundView) {
this.mNextReplyId = 1;
this.mPendingReplies = new HashMap();
this.mContext = context;
this.mPluginRegistry = new FlutterPluginRegistry(this, context);
this.mFlutterJNI = new FlutterJNI();
this.mFlutterJNI.setRenderSurface(new FlutterNativeView.RenderSurfaceImpl());
this.mFlutterJNI.setPlatformMessageHandler(new FlutterNativeView.PlatformMessageHandlerImpl());
this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl());
this.attach(this, isBackgroundView);
this.assertAttached();
this.mMessageHandlers = new HashMap();
}
複製程式碼
其中FlutterJNI
是Java層和Flutter Engine
通訊的橋樑,包括建立並啟動Flutter engine、當前FlutterView的Surface生命週期的通知、傳遞platform資料給dart層、回傳dart層呼叫platform層方法返回的結果資料等待。
然後會呼叫attach
方法:
// FlutterNativeView.java
private void attach(FlutterNativeView view, boolean isBackgroundView) {
this.mFlutterJNI.attachToNative(isBackgroundView);
}
// FlutterJNI.java
@UiThread
public void attachToNative(boolean isBackgroundView) {
this.ensureNotAttachedToNative();
this.nativePlatformViewId = this.nativeAttach(this, isBackgroundView);
}
複製程式碼
attachToNative
方法中通過呼叫JNI
方法nativeAttach
將當前flutterJNI
物件傳遞給c++層(後續一些dart層呼叫java
層的方法就是通過該物件呼叫對應的方法實現的),得到c++層返回的nativePlatformViewId
,這個值非常重要,是c++層AndroidShellHolder
的物件指標值,後續會通過該值呼叫一系列c++層的方法執行操作,並將其儲存以供後續使用。
對應的C++
方法如下, 通過之前初始化儲存在g_flutter_main物件中的settings值和傳入的java
物件flutterJNI
建立std::unique_ptr
物件(該物件通過指標佔有並管理AndroidShellHolder
物件),該物件有效的情況下會呼叫release方法返回其管理物件的指標並釋放物件的所有權,reinterpret_cast()方法將該AndroidShellHolder
物件指標強制轉化為long型別的值並返回java
層儲存。
// platform_view_android_jni.cc
// Called By Java
static jlong AttachJNI(JNIEnv* env,
jclass clazz,
jobject flutterJNI,
jboolean is_background_view) {
fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterJNI);
auto shell_holder = std::make_unique<AndroidShellHolder>(
FlutterMain::Get().GetSettings(), java_object, is_background_view);
if (shell_holder->IsValid()) {
return reinterpret_cast<jlong>(shell_holder.release());
} else {
return 0;
}
}
複製程式碼
接著看下很重要的一個類AndroiudShellHolder
.
4.AndroiudShellHolder
程式碼比較長,先看下前半部分,傳入的引數is_background_view
為false,會首先通過ThreadHost
初始化三個執行緒ui_thread
,gpu_thread
, io_thread
,而當前執行緒就是platform_thread
.
platform_thread
負責和Engine
層的通訊io_thread
負責IO操作gpu_thread
執行GPU指令ui_thread
執行Dart
層isolate
程式碼
// android_shell_holder.cc
AndroidShellHolder::AndroidShellHolder(
blink::Settings settings,
fml::jni::JavaObjectWeakGlobalRef java_object,
bool is_background_view)
: settings_(std::move(settings)), java_object_(java_object) {
static size_t shell_count = 1;
auto thread_label = std::to_string(shell_count++);
FML_CHECK(pthread_key_create(&thread_destruct_key_, ThreadDestructCallback) ==
0);
if (is_background_view) {
thread_host_ = {thread_label, ThreadHost::Type::UI};
} else {
thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU |
ThreadHost::Type::IO};
}
...
}
複製程式碼
四個執行緒會持有MessageLoop
,通過他可以往執行緒新增工作任務, 具體可以參考另外一篇Flutter和原生之間的平臺通道實踐與原理的執行緒部分。接著會構造Shell
:
// android_shell_holder.cc
blink::TaskRunners task_runners(thread_label, // label
platform_runner, // platform
gpu_runner, // gpu
ui_runner, // ui
io_runner // io
);
shell_ =
Shell::Create(task_runners, // task runners
settings_, // settings
on_create_platform_view, // platform view create callback
on_create_rasterizer // rasterizer create callback
);
// shell.cc
std::unique_ptr<Shell> Shell::Create(
blink::TaskRunners task_runners,
blink::Settings settings,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
PerformInitializationTasks(settings);
TRACE_EVENT0("flutter", "Shell::Create");
auto vm = blink::DartVMRef::Create(settings);
FML_CHECK(vm) << "Must be able to initialize the VM.";
auto vm_data = vm->GetVMData();
return Shell::Create(std::move(task_runners), //
std::move(settings), //
vm_data->GetIsolateSnapshot(), // isolate snapshot
blink::DartSnapshot::Empty(), // shared snapshot
std::move(on_create_platform_view), //
std::move(on_create_rasterizer), //
std::move(vm) //
);
}
複製程式碼
在Shell Create
中會根據傳入的settings引數通過blink::DartVMRef::Create
構造Dart VM, 跟進去看看Dart VM
的建立過程, VM
只會構造一次,
// dart_vm_lifecycle.cc
DartVMRef DartVMRef::Create(Settings settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot) {
std::lock_guard<std::mutex> lifecycle_lock(gVMMutex);
// If there is already a running VM in the process, grab a strong reference to
// it.
if (auto vm = gVM.lock()) {
FML_DLOG(WARNING) << "Attempted to create a VM in a process where one was "
"already running. Ignoring arguments for current VM "
"create call and reusing the old VM.";
// There was already a running VM in the process,
return DartVMRef{std::move(vm)};
}
std::lock_guard<std::mutex> dependents_lock(gVMDependentsMutex);
gVMData.reset();
gVMServiceProtocol.reset();
gVMIsolateNameServer.reset();
gVM.reset();
// If there is no VM in the process. Initialize one, hold the weak reference
// and pass a strong reference to the caller.
auto isolate_name_server = std::make_shared<IsolateNameServer>();
auto vm = DartVM::Create(std::move(settings), //
std::move(vm_snapshot), //
std::move(isolate_snapshot), //
std::move(shared_snapshot), //
isolate_name_server //
);
if (!vm) {
FML_LOG(ERROR) << "Could not create Dart VM instance.";
return {nullptr};
}
gVMData = vm->GetVMData();
gVMServiceProtocol = vm->GetServiceProtocol();
gVMIsolateNameServer = isolate_name_server;
gVM = vm;
if (settings.leak_vm) {
gVMLeak = vm;
}
return DartVMRef{std::move(vm)};
}
複製程式碼
然後通過DartVM::Create
執行具體的構造過程,在Create
中會呼叫DartVM
建構函式, 通過執行dart::bin::BootstrapDartIo()
方法引導啟動dart:io
時間處理程式:
//dart_vm.cc
DartVM::DartVM(std::shared_ptr<const DartVMData> vm_data,
std::shared_ptr<IsolateNameServer> isolate_name_server)
: settings_(vm_data->GetSettings()),
vm_data_(vm_data),
isolate_name_server_(std::move(isolate_name_server)),
service_protocol_(std::make_shared<ServiceProtocol>()) {
TRACE_EVENT0("flutter", "DartVMInitializer");
gVMLaunchCount++;
FML_DCHECK(vm_data_);
FML_DCHECK(isolate_name_server_);
FML_DCHECK(service_protocol_);
FML_DLOG(INFO) << "Attempting Dart VM launch for mode: "
<< (IsRunningPrecompiledCode() ? "AOT" : "Interpreter");
{
TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo");
dart::bin::BootstrapDartIo();
if (!settings_.temp_directory_path.empty()) {
dart::bin::SetSystemTempDirectory(settings_.temp_directory_path.c_str());
}
}
...
DartUI::InitForGlobal();
{
TRACE_EVENT0("flutter", "Dart_Initialize");
Dart_InitializeParams params = {};
params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
params.vm_snapshot_data =
vm_data_->GetVMSnapshot().GetData()->GetSnapshotPointer();
params.vm_snapshot_instructions =
vm_data_->GetVMSnapshot().GetInstructionsIfPresent();
params.create = reinterpret_cast<decltype(params.create)>(
DartIsolate::DartIsolateCreateCallback);
params.shutdown = reinterpret_cast<decltype(params.shutdown)>(
DartIsolate::DartIsolateShutdownCallback);
params.cleanup = reinterpret_cast<decltype(params.cleanup)>(
DartIsolate::DartIsolateCleanupCallback);
params.thread_exit = ThreadExitCallback;
params.get_service_assets = GetVMServiceAssetsArchiveCallback;
params.entropy_source = DartIO::EntropySource;
char* init_error = Dart_Initialize(¶ms);
...
}
}
複製程式碼
DartUI::InitForGlobal
會註冊dart的各種本地方法,主要用於dart
呼叫c++層方法,有點類似於java中的jni註冊:
// dart_ui.cc
void DartUI::InitForGlobal() {
if (!g_natives) {
g_natives = new tonic::DartLibraryNatives();
Canvas::RegisterNatives(g_natives);
CanvasGradient::RegisterNatives(g_natives);
CanvasImage::RegisterNatives(g_natives);
CanvasPath::RegisterNatives(g_natives);
CanvasPathMeasure::RegisterNatives(g_natives);
Codec::RegisterNatives(g_natives);
DartRuntimeHooks::RegisterNatives(g_natives);
EngineLayer::RegisterNatives(g_natives);
FontCollection::RegisterNatives(g_natives);
FrameInfo::RegisterNatives(g_natives);
ImageFilter::RegisterNatives(g_natives);
ImageShader::RegisterNatives(g_natives);
IsolateNameServerNatives::RegisterNatives(g_natives);
Paragraph::RegisterNatives(g_natives);
ParagraphBuilder::RegisterNatives(g_natives);
Picture::RegisterNatives(g_natives);
PictureRecorder::RegisterNatives(g_natives);
Scene::RegisterNatives(g_natives);
SceneBuilder::RegisterNatives(g_natives);
SceneHost::RegisterNatives(g_natives);
SemanticsUpdate::RegisterNatives(g_natives);
SemanticsUpdateBuilder::RegisterNatives(g_natives);
Versions::RegisterNatives(g_natives);
Vertices::RegisterNatives(g_natives);
Window::RegisterNatives(g_natives);
// Secondary isolates do not provide UI-related APIs.
g_natives_secondary = new tonic::DartLibraryNatives();
DartRuntimeHooks::RegisterNatives(g_natives_secondary);
IsolateNameServerNatives::RegisterNatives(g_natives_secondary);
}
}
// window.cc
void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({
{"Window_defaultRouteName", DefaultRouteName, 1, true},
{"Window_scheduleFrame", ScheduleFrame, 1, true},
{"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
{"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
{"Window_render", Render, 2, true},
{"Window_updateSemantics", UpdateSemantics, 2, true},
{"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
{"Window_reportUnhandledException", ReportUnhandledException, 2, true},
});
}
複製程式碼
然後再DartVM
中通過Dart_Initialize
初始化Dart執行時環境,後面就不往下跟了,返回到shell.cc
中,構造玩vm
後會賦值給Shell, 再通過CreateShellOnPlatformThread
構造Shell
,該方法會在PlatformThread
執行緒中執行。
std::unique_ptr<Shell> Shell::Create(
blink::TaskRunners task_runners,
blink::Settings settings,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
blink::DartVMRef vm) {
PerformInitializationTasks(settings);
TRACE_EVENT0("flutter", "Shell::CreateWithSnapshots");
if (!task_runners.IsValid() || !on_create_platform_view ||
!on_create_rasterizer) {
return nullptr;
}
fml::AutoResetWaitableEvent latch;
std::unique_ptr<Shell> shell;
fml::TaskRunner::RunNowOrPostTask(
task_runners.GetPlatformTaskRunner(),
fml::MakeCopyable([&latch, //
vm = std::move(vm), //
&shell, //
task_runners = std::move(task_runners), //
settings, //
isolate_snapshot = std::move(isolate_snapshot), //
shared_snapshot = std::move(shared_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
]() mutable {
shell = CreateShellOnPlatformThread(std::move(vm),
std::move(task_runners), //
settings, //
std::move(isolate_snapshot), //
std::move(shared_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
);
latch.Signal();
}));
latch.Wait();
return shell;
}
複製程式碼
接下來到CreateShellOnPlatformThread
看看,程式碼比較多分成幾個部分來看, 首先呼叫new Shell
構造,然後呼叫on_create_platform_view
,這個方法在android_shell_holder.cc
中通過Shell::Create
傳遞過來的
// shell.cc
std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
blink::DartVMRef vm,
blink::TaskRunners task_runners,
blink::Settings settings,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
if (!task_runners.IsValid()) {
FML_LOG(ERROR) << "Task runners to run the shell were invalid.";
return nullptr;
}
auto shell =
std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));
// Create the platform view on the platform thread (this thread).
auto platform_view = on_create_platform_view(*shell.get());
if (!platform_view || !platform_view->GetWeakPtr()) {
return nullptr;
}
...
}
複製程式碼
看下on_create_platform_view
,在這裡會構造PlatformViewAndroid
並且交給platform_view
管理
// android_shell_holder.cc
fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
Shell::CreateCallback<PlatformView> on_create_platform_view =
[is_background_view, java_object, &weak_platform_view](Shell& shell) {
std::unique_ptr<PlatformViewAndroid> platform_view_android;
if (is_background_view) {
platform_view_android = std::make_unique<PlatformViewAndroid>(
shell, // delegate
shell.GetTaskRunners(), // task runners
java_object // java object handle for JNI interop
);
} else {
platform_view_android = std::make_unique<PlatformViewAndroid>(
shell, // delegate
shell.GetTaskRunners(), // task runners
java_object, // java object handle for JNI interop
shell.GetSettings()
.enable_software_rendering // use software rendering
);
}
weak_platform_view = platform_view_android->GetWeakPtr();
return platform_view_android;
};
複製程式碼
再回到shell.cc
中接著往下看,接著會在IO Thread
中構造IOManager
物件並且交給io_manager
管理:
// Create the IO manager on the IO thread. The IO manager must be initialized
// first because it has state that the other subsystems depend on. It must
// first be booted and the necessary references obtained to initialize the
// other subsystems.
fml::AutoResetWaitableEvent io_latch;
std::unique_ptr<IOManager> io_manager;
auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
fml::TaskRunner::RunNowOrPostTask(
io_task_runner,
[&io_latch, //
&io_manager, //
&platform_view, //
io_task_runner //
]() {
TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
io_manager = std::make_unique<IOManager>(
platform_view->CreateResourceContext(), io_task_runner);
io_latch.Signal();
});
io_latch.Wait();
複製程式碼
接著會在GPU Thread
中構造Rasterizer
物件並且交給rasterizer
管理,on_create_rasterizer
也是在android_shell_holder.cc
中通過Shell::Create
傳遞過來的
// Create the rasterizer on the GPU thread.
fml::AutoResetWaitableEvent gpu_latch;
std::unique_ptr<Rasterizer> rasterizer;
fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate;
fml::TaskRunner::RunNowOrPostTask(
task_runners.GetGPUTaskRunner(), [&gpu_latch, //
&rasterizer, //
on_create_rasterizer, //
shell = shell.get(), //
&snapshot_delegate //
]() {
TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
if (auto new_rasterizer = on_create_rasterizer(*shell)) {
rasterizer = std::move(new_rasterizer);
snapshot_delegate = rasterizer->GetSnapshotDelegate();
}
gpu_latch.Signal();
});
gpu_latch.Wait();
複製程式碼
接著在UIThread
中建立Engine
,並且交給engine
管理:
// Create the engine on the UI thread.
fml::AutoResetWaitableEvent ui_latch;
std::unique_ptr<Engine> engine;
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetUITaskRunner(),
fml::MakeCopyable([&ui_latch, //
&engine, //
shell = shell.get(), //
isolate_snapshot = std::move(isolate_snapshot), //
shared_snapshot = std::move(shared_snapshot), //
vsync_waiter = std::move(vsync_waiter), //
snapshot_delegate = std::move(snapshot_delegate), //
io_manager = io_manager->GetWeakPtr() //
]() mutable {
TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
const auto& task_runners = shell->GetTaskRunners();
// The animator is owned by the UI thread but it gets its vsync pulses
// from the platform.
auto animator = std::make_unique<Animator>(*shell, task_runners,
std::move(vsync_waiter));
engine = std::make_unique<Engine>(*shell, //
*shell->GetDartVM(), //
std::move(isolate_snapshot), //
std::move(shared_snapshot), //
task_runners, //
shell->GetSettings(), //
std::move(animator), //
std::move(snapshot_delegate), //
std::move(io_manager) //
);
ui_latch.Signal();
}));
ui_latch.Wait();
複製程式碼
最後通過shell->Setup
方法將platform_view engine rasterizer io_manager
四個物件交給 Shell
物件管理:
// We are already on the platform thread. So there is no platform latch to
// wait on.
if (!shell->Setup(std::move(platform_view), //
std::move(engine), //
std::move(rasterizer), //
std::move(io_manager)) //
) {
return nullptr;
}
return shell;
複製程式碼
再回到前面的android_shell_holder.cc
中,通過Shell::Create()
建立完成後的shell
物件返回給AndroidShellHolder
物件持有。到這裡整體思路就清晰了,Embedder
層通過Shell
物件與Engine層建立了連線,後續的一切操作通過Shell
物件進行。而Shell
物件又通過AndroidShellHolder
物件持有,AndroidShellHolder
物件指標值又返回給了java
層,然後java
層在呼叫JNI
方法的時候將這個指標值傳遞過去便能拿到Embedder
層的AndroidShellHolder
物件,進而通過Shell
物件向engine
層傳送一系列操作指令。
5.RunBundle
經過上面的流程,已經為dart層程式碼執行建立好了執行時環境,接下來就是載入dart
層相關的程式碼了。
再回到java
層的FlutterActivityDelegate
中的onCreate
程式碼:
//FlutterActivityDelegate.java/onCreate
if (!this.loadIntent(this.activity.getIntent())) {
String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
if (appBundlePath != null) {
this.runBundle(appBundlePath);
}
}
//FlutterActivityDelegate.java/runBundle
private void runBundle(String appBundlePath) {
if (!this.flutterView.getFlutterNativeView().isApplicationRunning()) {
FlutterRunArguments args = new FlutterRunArguments();
ArrayList<String> bundlePaths = new ArrayList();
ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater();
if (resourceUpdater != null) {
File patchFile = resourceUpdater.getInstalledPatch();
JSONObject manifest = resourceUpdater.readManifest(patchFile);
if (resourceUpdater.validateManifest(manifest)) {
bundlePaths.add(patchFile.getPath());
}
}
bundlePaths.add(appBundlePath);
args.bundlePaths = (String[])bundlePaths.toArray(new String[0]);
args.entrypoint = "main";
this.flutterView.runFromBundle(args);
}
}
複製程式碼
呼叫自己的runBundle
函式,在if
語句裡面可以看到資源提取的程式碼,這裡是Flutter
預埋的動態更新程式碼,目前應該還沒起作用,然後會呼叫FlutterView runFromBundle
:
// FlutterView.java
public void runFromBundle(FlutterRunArguments args) {
this.assertAttached();
this.preRun();
this.mNativeView.runFromBundle(args);
this.postRun();
}
複製程式碼
java
層最終會調到FlutterJNI
中,其中nativePlatformViewId
就是AndroidShellHolder
在java
層的指標值,此時的prioritizedBundlePaths
陣列中只有一個值類似/data/data/包名/flutter/flutter_assets/
的路徑值,entrypointFunctionName
為main
,pathToEntrypointFunction
為null
。
// FlutterJNI.java
@UiThread
public void runBundleAndSnapshotFromLibrary(
@NonNull String[] prioritizedBundlePaths,
@Nullable String entrypointFunctionName,
@Nullable String pathToEntrypointFunction,
@NonNull AssetManager assetManager
) {
ensureAttachedToNative();
nativeRunBundleAndSnapshotFromLibrary(
nativePlatformViewId,
prioritizedBundlePaths,
entrypointFunctionName,
pathToEntrypointFunction,
assetManager
);
}
private native void nativeRunBundleAndSnapshotFromLibrary(
long nativePlatformViewId,
@NonNull String[] prioritizedBundlePaths,
@Nullable String entrypointFunctionName,
@Nullable String pathToEntrypointFunction,
@NonNull AssetManager manager
);
複製程式碼
後面就到了JNI
層了,在PlatformViewAndrod
中:
// platform_view_android_jni.cc
{
.name = "nativeRunBundleAndSnapshotFromLibrary",
.signature = "(J[Ljava/lang/String;Ljava/lang/String;"
"Ljava/lang/String;Landroid/content/res/AssetManager;)V",
.fnPtr =
reinterpret_cast<void*>(&shell::RunBundleAndSnapshotFromLibrary),
},
// RunBundleAndSnapshotFromLibrary
static void RunBundleAndSnapshotFromLibrary(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
jobjectArray jbundlepaths,
jstring jEntrypoint,
jstring jLibraryUrl,
jobject jAssetManager) {
auto asset_manager = std::make_shared<blink::AssetManager>();
for (const auto& bundlepath :
fml::jni::StringArrayToVector(env, jbundlepaths)) {
if (bundlepath.empty()) {
continue;
}
// If we got a bundle path, attempt to use that as a directory asset
// bundle or a zip asset bundle.
const auto file_ext_index = bundlepath.rfind(".");
if (bundlepath.substr(file_ext_index) == ".zip") {
asset_manager->PushBack(std::make_unique<blink::ZipAssetStore>(
bundlepath, "assets/flutter_assets"));
} else {
asset_manager->PushBack(
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
bundlepath.c_str(), false, fml::FilePermission::kRead)));
// Use the last path component of the bundle path to determine the
// directory in the APK assets.
const auto last_slash_index = bundlepath.rfind("/", bundlepath.size());
if (last_slash_index != std::string::npos) {
auto apk_asset_dir = bundlepath.substr(
last_slash_index + 1, bundlepath.size() - last_slash_index);
asset_manager->PushBack(std::make_unique<blink::APKAssetProvider>(
env, // jni environment
jAssetManager, // asset manager
std::move(apk_asset_dir)) // apk asset dir
);
}
}
}
複製程式碼
上面邏輯首先通過bundlePath
建立DirectoryAssetBundle
物件交給asset_manager
物件管理,然後欻功能鍵執行配置物件config
,通過ANDROID_SHELL_HOLDER->Launch(std::move(config));
根據執行配置資訊啟動,ANDROID_SHELL_HOLDER
是一個巨集,通過將java
層持有的AndroidShellHolder
指標值強轉為AndroidShellHolder
物件指標,這樣就可以呼叫它的方法了。
// platform_view_android_jni.cc
#define ANDROID_SHELL_HOLDER \
(reinterpret_cast<shell::AndroidShellHolder*>(shell_holder))
複製程式碼
再看到AndroidShellHolder
中的方法Launch
,就是到shell
中取出engine
,然後在UIThread
中執行engine->Run
:
void AndroidShellHolder::Launch(RunConfiguration config) {
if (!IsValid()) {
return;
}
shell_->GetTaskRunners().GetUITaskRunner()->PostTask(
fml::MakeCopyable([engine = shell_->GetEngine(), //
config = std::move(config) //
]() mutable {
FML_LOG(INFO) << "Attempting to launch engine configuration...";
if (!engine || engine->Run(std::move(config)) ==
shell::Engine::RunStatus::Failure) {
FML_LOG(ERROR) << "Could not launch engine in configuration.";
} else {
FML_LOG(INFO) << "Isolate for engine configuration successfully "
"started and run.";
}
}));
}
複製程式碼
再看下engine->Run
:
// engine.cc
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
if (!configuration.IsValid()) {
FML_LOG(ERROR) << "Engine run configuration was invalid.";
return RunStatus::Failure;
}
auto isolate_launch_status =
PrepareAndLaunchIsolate(std::move(configuration));
...
return isolate_running ? Engine::RunStatus::Success
: Engine::RunStatus::Failure;
}
shell::Engine::RunStatus Engine::PrepareAndLaunchIsolate(
RunConfiguration configuration) {
...
if (configuration.GetEntrypointLibrary().empty()) {
if (!isolate->Run(configuration.GetEntrypoint())) {
FML_LOG(ERROR) << "Could not run the isolate.";
return RunStatus::Failure;
}
} else {
if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
configuration.GetEntrypoint())) {
FML_LOG(ERROR) << "Could not run the isolate.";
return RunStatus::Failure;
}
}
return RunStatus::Success;
}
複製程式碼
最終調到DartIsolate
的Run
方法, 通過DartInvokeField
執行到Dart
層的main()
方法入口,這樣整個Dart
程式碼就跑起來了,Flutter
介面也就顯示到FlutterView
中。
// dart_isolate.cc
FML_WARN_UNUSED_RESULT
bool DartIsolate::Run(const std::string& entrypoint_name, fml::closure on_run) {
TRACE_EVENT0("flutter", "DartIsolate::Run");
if (phase_ != Phase::Ready) {
return false;
}
tonic::DartState::Scope scope(this);
auto user_entrypoint_function =
Dart_GetField(Dart_RootLibrary(), tonic::ToDart(entrypoint_name.c_str()));
if (!InvokeMainEntrypoint(user_entrypoint_function)) {
return false;
}
phase_ = Phase::Running;
FML_DLOG(INFO) << "New isolate is in the running state.";
if (on_run) {
on_run();
}
return true;
}
FML_WARN_UNUSED_RESULT
static bool InvokeMainEntrypoint(Dart_Handle user_entrypoint_function) {
if (tonic::LogIfError(user_entrypoint_function)) {
FML_LOG(ERROR) << "Could not resolve main entrypoint function.";
return false;
}
Dart_Handle start_main_isolate_function =
tonic::DartInvokeField(Dart_LookupLibrary(tonic::ToDart("dart:isolate")),
"_getStartMainIsolateFunction", {});
if (tonic::LogIfError(start_main_isolate_function)) {
FML_LOG(ERROR) << "Could not resolve main entrypoint trampoline.";
return false;
}
if (tonic::LogIfError(tonic::DartInvokeField(
Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
{start_main_isolate_function, user_entrypoint_function}))) {
FML_LOG(ERROR) << "Could not invoke the main entrypoint.";
return false;
}
return true;
}
複製程式碼
6.總結
整個程式碼比較長,簡單總結就是在Android
平臺上Flutter
是顯示到FlutterView
上的,FlutterView
會通過FlutterNativeView
呼叫到FlutterJNI
,在FlutterJNI
會持有一個很重要的物件AndroidShellHolder
,而 AndroidShellHolder
會持有shell
物件, Embedder
層通過Shell
物件與Engine層建立了連線,後續的一切操作通過Shell
物件進行。AndroidShellHolder
物件指標值又返回給了java
層,然後FlutterJNI
在呼叫JNI
方法的時候將這個指標值傳遞過去便能拿到Embedder
層的AndroidShellHolder
物件,進而通過Shell
物件向engine
層傳送一系列操作指令。Engine
物件會呼叫dart
層程式碼執行。
參考連結: