赞
踩
flutter
有多火这废话这里就不多说了,几乎所有大厂的app
都在用,我们开始吧
flutter
可以分层三层,第一层是我们 dart
的代码,包括 UI
组件、动画、Gesture
等等,也就是每次我们新建 dart
文件,需要 import
的那些包里的类:
引擎层在 github
上有一个单独的仓库 flutter/engine,这里面负责页面底层渲染,native api
的调用,包括 cpu
、 gpu
的管理调度之类。
平台相关实现 层,Flutter
会针对与渲染引擎层(engine)
约定好的接口进行对应平台(iOS、Android、Windows、 Linux)
的实现,常见不同平台的 RunLoop
、Thread
以及 Surface
绘制相关的实现 差异会在该层中体现。
值得留意的是,flutter
还使用了些 third_party
,比如页面渲染是用的 Skia
,就是 Google
的一套跨平台图形库。flutter
之所以称为自绘渲染引擎,也正是因为 Skia
保证了不同平台上渲染的强统一性
提个问题思考:
FlutterActivity
这些Java
类是属于哪一层呢?是framework
还是 engine 亦或是platform
呢?请在评论区给你出的答案~
flutter
的知识点,flutter_interviews 持续更新中~这里已 android
为例,iOS
也是类似的一通百通。flutter
可以分为两种情况,一种是纯 flutter
项目 new flutter project
另一种是已 module
的形式集成到现有项目里
纯 flutter
项目:编译前会调用 flutter create .
在项目下 init
一个 android
目录,这里包含了 Manifest
、build.gradle
、MainActivity
(继承了 FlutterActivity
) ,完全是一个 android
的项目,所以打包的 app
运行时,入口类就会是 /android
目录下的 mainActivity
已 module
形式继承的话,需要我们自定义一个 Activity
并让他继承自 FlutterActivity
作为 flutter
的入口,在这个路径里制定一个 engine
,这个 engine
所加载的 page
会通过 setContent
设置到这个 Activity
上
不论是纯 flutter app
,还是以 module
形式继承,我们显示 Flutter
页面的 Activity
都继承自 FlutterActivity
所以当 Activity
启动时,就会调到 FlutterActivity
里的 onCreate
方法中去,那我们看看这里面做了什么
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { switchLaunchThemeForNormalTheme(); super.onCreate(savedInstanceState); lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); delegate = new FlutterActivityAndFragmentDelegate(this); delegate.onAttach(this); delegate.onActivityCreated(savedInstanceState); configureWindowForTransparency(); setContentView(createFlutterView()); configureStatusBarForFullscreenFlutterExperience(); }
我们来一一解析下:
FlutterActivity
继承 Activity
并实现了 FlutterActivityAndFragmentDelegate
这个代理类中的Host接口及获取生命周期的LifecycleOwner接口,由此就可以对生命周期进行监听configureWindowForTransparency
:如果 FlutterActivity
背景模式是透明(默认是不透明的模式),则设置整个 FlutterActivity
窗口透明及隐藏状态栏。其实如果我们不在原生项目中使用FlutterModule
进行混合开发的话,是不需要关注这个方法的。因为默认就是非透明模式。onAttach 主要做了各种初始化操作,代码逻辑如下
void onAttach(@NonNull Context context) {
ensureAlive();
if (flutterEngine == null) {
setupFlutterEngine();
}
platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
if (host.shouldAttachEngineToActivity()) {
flutterEngine
.getActivityControlSurface()
.attachToActivity(host.getActivity(), host.getLifecycle());
}
host.configureFlutterEngine(flutterEngine);
}
FlutterView 的作用是在 Android 设备上显示一个 Flutter UI,绘制内容来自于 FlutterEngine 提供。android 中 flutterview 有四种沿伸,首先是用于显示我们app对象的 FlutterSurfaceView 或者 FlutterTextureView ,但是除了这两个之外还有 FlutterSplashView 和 FlutterImageView
@NonNull View onCreateView( ... if (host.getRenderMode() == RenderMode.surface) { ... flutterView = new FlutterView(host.getActivity(), flutterSurfaceView); } else { ... flutterView = new FlutterView(host.getActivity(), flutterTextureView); } flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener); flutterSplashView = new FlutterSplashView(host.getContext()); ... flutterView.attachToFlutterEngine(flutterEngine); return flutterSplashView; }
FlutterEngine 是一个独立的 Flutter 运行环境容器,通过它可以在 Android 应用程序中运行 Dart 代码。FlutterEngine 中的 Dart 代码可以在后台执行,也可以使用附带的 FlutterRenderer 和 Dart 代码将 Dart 端 UI 效果渲染到屏幕上,渲染可以开始和停止,从而允许 FlutterEngine 从 UI 交互转移到仅进行数据处理,然后又返回到 UI 交互的能力。
public FlutterEngine( @NonNull Context context, @NonNull FlutterLoader flutterLoader, @NonNull FlutterJNI flutterJNI, @NonNull PlatformViewsController platformViewsController, @Nullable String[] dartVmArgs, boolean automaticallyRegisterPlugins) { this.flutterJNI = flutterJNI; flutterLoader.startInitialization(context.getApplicationContext()); ... attachToJni(); this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets()); this.dartExecutor.onAttachedToJNI(); this.renderer = new FlutterRenderer(flutterJNI); ... xxxChannel = new XxxChannel(...); // 创建各个消息通道,用于传递事件、消息 ... }
这里 FlutterEngine 与 DartExecutor、Dart VM、Isolate 的关系大致可以归纳如下:
FlutterJNI 的作用就是架起 Android 端 Java 与 Flutter Engine C/C++ 端的一座接口桥梁。为了方便 JNI 接口的管理,这里将所有的 JNI 接口都封装在了 FlutterJNI 里,方便使用
大部分FlutterJNI中的调用都与特定的“platform view”相关,而“platform view”的数量可能会很多。所以,在执行了attachToNative方法后,每个FlutterJNI实例都持有一个本地“platform view”的ID,且这个ID与bendingC/C++引擎代码共享。这个ID会被传递到所有的具体platform view的本地方法。
public class FlutterJNI { ... public FlutterJNI() { // We cache the main looper so that we can ensure calls are made on the main thread // without consistently paying the synchronization cost of getMainLooper(). mainLooper = Looper.getMainLooper(); } ... @UiThread public void attachToNative(boolean isBackgroundView) { ensureRunningOnMainThread(); ensureNotAttachedToNative(); nativePlatformViewId = nativeAttach(this, isBackgroundView); } private native long nativeAttach(@NonNull FlutterJNI flutterJNI, boolean isBackgroundView); ... }
在 platform 层也会针对 android/ios 实现对应的 flutter_jni 类,那 android 举例就是 platform_view_android_jni.cc,这里面注册了 FlutterJNI 中调用的 c/c++ 层实现
bool RegisterApi(JNIEnv* env) { static const JNINativeMethod flutter_jni_methods[] = { { .name = "nativeAttach", .signature = "(Lio/flutter/embedding/engine/FlutterJNI;Z)J", .fnPtr = reinterpret_cast<void*>(&AttachJNI), }, ... }; if (env->RegisterNatives(g_flutter_jni_class->obj(), flutter_jni_methods, fml::size(flutter_jni_methods)) != 0) { FML_LOG(ERROR) << "Failed to RegisterNatives with FlutterJNI"; return false; } ... } 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>( // [6] FlutterMain::Get().GetSettings(), java_object, is_background_view); if (shell_holder->IsValid()) { return reinterpret_cast<jlong>(shell_holder.release()); } else { return 0; } }
在AndroidShellHolder中保存有Flutter设置参数、FlutterJNI的Java引用、PlatformViewAndroid对象(该对象在后续创建)、Shell对象等。
AndroidShellHolder::AndroidShellHolder( flutter::Settings settings, fml::jni::JavaObjectWeakGlobalRef java_object, bool is_background_view) : settings_(std::move(settings)), java_object_(java_object) { ... // 创建三个线程:UI线程、GPU线程、IO线程 thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | ThreadHost::Type::IO}; ... 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; ... platform_view_android = std::make_unique<PlatformViewAndroid>( // [7] 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; }; ... // [8] shell_ = Shell::Create(task_runners, // task runners GetDefaultWindowData(), // window data settings_, // settings on_create_platform_view, // platform view create callback on_create_rasterizer // rasterizer create callback ); platform_view_ = weak_platform_view; ... }
Shell是Flutter应用的“中枢神经系统”,包含了多个组件,并继承它们相应的Delegate类。
std::unique_ptr<Shell> Shell::Create( TaskRunners task_runners, const WindowData window_data, Settings settings, Shell::CreateCallback<PlatformView> on_create_platform_view, Shell::CreateCallback<Rasterizer> on_create_rasterizer) { ... auto vm = DartVMRef::Create(settings); // 创建Dart虚拟机 auto vm_data = vm->GetVMData(); return Shell::Create(std::move(task_runners), // std::move(window_data), // std::move(settings), // vm_data->GetIsolateSnapshot(), // isolate snapshot on_create_platform_view, // on_create_rasterizer, // std::move(vm) // ); }
在platform线程中创建了Shell,之后分别在栅格化线程中创建Rasterizer,在platform线程中创建PlatformView,在IO线程中创建ShellIOManager,在UI线程中创建Engine,并将这四者设置到Shell中去。Shell分别继承了四者的Delegate,四者通过相应的Delegate将事件传递到Shell。
void PlatformViewAndroid::NotifyCreated( fml::RefPtr<AndroidNativeWindow> native_window) { if (android_surface_) { InstallFirstFrameCallback(); ... fml::TaskRunner::RunNowOrPostTask( task_runners_.GetRasterTaskRunner(), [&latch, surface = android_surface_.get(), native_window = std::move(native_window)]() { surface->SetNativeWindow(native_window); ... }); ... } PlatformView::NotifyCreated(); } void PlatformView::NotifyCreated() { std::unique_ptr<Surface> surface; auto* platform_view = this; ... fml::TaskRunner::RunNowOrPostTask( task_runners_.GetRasterTaskRunner(), [platform_view, &surface, &latch]() { surface = platform_view->CreateRenderingSurface(); ... }); ... delegate_.OnPlatformViewCreated(std::move(surface)); }
我们知道 gpu线程的主要工作是将layer tree进行光栅化再发送给GPU,其中最为核心方法ScopedFrame::Raster(),这里就涉及到了 Rasterizer (光栅)
Rasterizer持有一个当前活动的在屏幕中显示的绘制Surface。Rasterizer在这个Surface上绘制从Engine中提交的layer tree
Rasterizer::Rasterizer(Delegate& delegate, TaskRunners task_runners) : Rasterizer(delegate, std::move(task_runners), std::make_unique<flutter::CompositorContext>( delegate.GetFrameBudget())) {} ... void Rasterizer::Draw( fml::RefPtr<flutter::Pipeline<flow::LayerTree>> pipeline) { TRACE_EVENT0("flutter", "GPURasterizer::Draw"); flutter::Pipeline<flow::LayerTree>::Consumer consumer = std::bind(&Rasterizer::DoDraw, this, std::placeholders::_1); //消费pipeline的任务 [见小节2.3] switch (pipeline->Consume(consumer)) { case flutter::PipelineConsumeResult::MoreAvailable: { task_runners_.GetGPUTaskRunner()->PostTask( [weak_this = weak_factory_.GetWeakPtr(), pipeline]() { if (weak_this) { weak_this->Draw(pipeline); } }); break; } default: break; } }
ShellIOManager、GrContext、SkiaUnrefQueue 都在 io 线程中创建
class ShellIOManager final : public IOManager {
...
void NotifyResourceContextAvailable(sk_sp<GrContext> resource_context);
void UpdateResourceContext(sk_sp<GrContext> resource_context);
...
fml::WeakPtr<GrContext> GetResourceContext() const override;
fml::RefPtr<flutter::SkiaUnrefQueue> GetSkiaUnrefQueue() const override;
}
初始化完毕,万事俱备只欠东风门,我们看看 flutter 是怎么启动的!
当我们创建一个 flutter_app 时,这里会生成一个 kotlin 类(已经是 Java 看来 Google 对推 kt 态度很强硬)
class MainActivity: FlutterActivity() {
}
这里默认没有实现,所以会直接调到 FlutterActivity 中,我们的启动流程主要在 onStart 里开始
@Override
protected void onStart() {
super.onStart();
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
delegate.onStart();
}
可以看到,这里通过 lifecycle 首先将生命周期设置为 ON_START ,然后 就调用了 FlutterActivityAndFragmentDelegate 的 onStart方法
这里主要有两个方法,ensureAlive 之前讲过了,这里主要看看 doInitialFlutterViewRun
void onStart() { ensureAlive(); doInitialFlutterViewRun(); } ... private void doInitialFlutterViewRun() { ... if (flutterEngine.getDartExecutor().isExecutingDart()) { // No warning is logged because this situation will happen on every config // change if the developer does not choose to retain the Fragment instance. // So this is expected behavior in many cases. return; } ... // Configure the Dart entrypoint and execute it. DartExecutor.DartEntrypoint entrypoint = new DartExecutor.DartEntrypoint( host.getAppBundlePath(), host.getDartEntrypointFunctionName()); flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint); // [9] }
由于 FlutterView 中不支持重新加载,或者重启 dart 。所以要先判断当前是否转载执行 dart 代码
前面我们说过,DartExecutor在FlutterEngine创建的时候创建出来,并在dartExecutor.onAttachedToJNI方法中,将DartMessager设置到FlutterJNI中,这里我们重点看看 executeDartEntrypoint 方法
public void executeDartEntrypoint(@NonNull DartEntrypoint dartEntrypoint) {
...
flutterJNI.runBundleAndSnapshotFromLibrary(
dartEntrypoint.pathToBundle, dartEntrypoint.dartEntrypointFunctionName, null, assetManager);
...
}
我们来看看 runBundleAndSnapshotFromLibrary 方法
@UiThread
public void runBundleAndSnapshotFromLibrary( @NonNull String bundlePath, @Nullable String entrypointFunctionName, @Nullable String @NonNull AssetManager assetManager) {
ensureRunningOnMainThread();
ensureAttachedToNative();
nativeRunBundleAndSnapshotFromLibrary(
nativeShellHolderId,
bundlePath,
entrypointFunctionName,
pathToEntrypointFunction,
assetManager);
}
private native void nativeRunBundleAndSnapshotFromLibrary(
long nativeShellHolderId,
@NonNull String bundlePath,
@Nullable String entrypointFunctionName,
@Nullable String pathToEntrypointFunction,
@NonNull AssetManager manager);
Launch 方法会做一些列的配置,最终调用Shell的RunEngine方法
void AndroidShellHolder::Launch(std::shared_ptr<AssetManager> asset_manager,
const std::string& entrypoint,
const std::string& libraryUrl) {
...
shell_->RunEngine(std::move(config.value()));
}
由此进入最核心的 Shell 层
值得注意的是,我们前面看过,前文中已经提到,Engine是创建、运行都在UI线程中的。所以此处Engine执行Dart代码需要在UI线程中执行。下面我们先看看 RunEngine 方法做了什么:
void Shell::RunEngine(
RunConfiguration run_configuration,
const std::function<void(Engine::RunStatus)>& result_callback) {
...
fml::TaskRunner::RunNowOrPostTask(
task_runners_.GetUITaskRunner(), // [10]
fml::MakeCopyable(
[run_configuration = std::move(run_configuration),
weak_engine = weak_engine_, result]() mutable {
...
auto run_result = weak_engine->Run(std::move(run_configuration));
...
result(run_result);
}));
}
我们再来看下这个 Run 方法中做了什么:
// ./shell/common/engine.cc Engine::RunStatus Engine::Run(RunConfiguration configuration) { ... last_entry_point_ = configuration.GetEntrypoint(); last_entry_point_library_ = configuration.GetEntrypointLibrary(); auto isolate_launch_status = PrepareAndLaunchIsolate(std::move(configuration)); // [11] ... std::shared_ptr<DartIsolate> isolate = runtime_controller_->GetRootIsolate().lock(); bool isolate_running = isolate && isolate->GetPhase() == DartIsolate::Phase::Running; if (isolate_running) { ... std::string service_id = isolate->GetServiceId(); fml::RefPtr<PlatformMessage> service_id_message = fml::MakeRefCounted<flutter::PlatformMessage>( kIsolateChannel, // 此处设置为IsolateChannel std::vector<uint8_t>(service_id.begin(), service_id.end()), nullptr); HandlePlatformMessage(service_id_message); // [12] } return isolate_running ? Engine::RunStatus::Success : Engine::RunStatus::Failure; }
Engine::RunStatus Engine::PrepareAndLaunchIsolate( RunConfiguration configuration) { UpdateAssetManager(configuration.GetAssetManager()); auto isolate_configuration = configuration.TakeIsolateConfiguration(); std::shared_ptr<DartIsolate> isolate = runtime_controller_->GetRootIsolate().lock(); ... if (!isolate_configuration->PrepareIsolate(*isolate)) { return RunStatus::Failure; } if (configuration.GetEntrypointLibrary().empty()) { // 之前传入的library为空,进入该分支 if (!isolate->Run(configuration.GetEntrypoint(), settings_.dart_entrypoint_args)) { return RunStatus::Failure; } } else { if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(), configuration.GetEntrypoint(), settings_.dart_entrypoint_args)) { return RunStatus::Failure; } } }
[[nodiscard]] bool DartIsolate::Run(const std::string& entrypoint_name, const std::vector<std::string>& args, const fml::closure& on_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())); auto entrypoint_args = tonic::ToDart(args); if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) { return false; } phase_ = Phase::Running; if (on_run) { on_run(); } return true; }
[[nodiscard]] static bool InvokeMainEntrypoint(
Dart_Handle user_entrypoint_function,
Dart_Handle args) {
...
Dart_Handle start_main_isolate_function =
tonic::DartInvokeField(Dart_LookupLibrary(tonic::ToDart("dart:isolate")),
"_getStartMainIsolateFunction", {});
...
if (tonic::LogIfError(tonic::DartInvokeField(
Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
{start_main_isolate_function, user_entrypoint_function, args}))) {
return false;
}
return true;
}
大功告成,到这里 dart 代码就运行起来啦!
前面 FlutterJNIAndroidShellHolder 里我们看到,它创建出了三个线程 ui、gpu、io 在后面运行过程中,比如光栅那里,他们都被反复的使用,那么他们到底是什么又有什么作用呢?
Flutter引擎本身并不创建也不管理自己的线程,线程的管控是由embedder层负责的。引擎要求Embedder提供4个task runner的引用,但是并不关心每个runner所在的线程是否是独立的。
可是我们上面只看到了三个呀?其实还有一个 platform 线程,指的是我们平台的主线程,拿 android 为例,就是我们的 main 线程,那么四个线程是做什么用呢,这里简要分享一下:
注意:每个引擎有一份独立的UI, GPU,IO Runnter独立线程;所有共享引擎共用platform runner的线程
Platform Task Runner (或者叫 Platform Thread)的功能是要处理平台(android/iOS)的消息。举个简单的例子,我们 MethodChannel 的回调方法 onMethodCall 就是在这个线程上
UI Task Runner用于执行Root Isolate代码,它运行在线程对应平台的线程上,属于子线程。同时,Root isolate在引擎启动时会绑定了不少Flutter需要的函数方法,以便进行渲染操作。
GPU Task Runner主要用于执行设备GPU的指令。在UI Task Runner 创建layer tree,在GPU Task Runner将Layer Tree提供的信息转化为平台可执行的GPU指令。除了将Layer Tree提供的信息转化为平台可执行的GPU指令,GPU Task Runner同时也负责管理每一帧绘制所需要的GPU资源,包括平台Framebuffer的创建,Surface生命周期管理,以及Texture和Buffers的绘制时机等
IO Task Runner也运行在平台对应的子线程中,主要作用是做一些预先处理的读取操作,为GPU Runner的渲染操作做准备。我们可以认为IO Task Runner是GPU Task Runner的助手,它可以减少GPU Task Runner的额外工作。例如,在Texture的准备过程中,IO Runner首先会读取压缩的图片二进制数据,并将其解压转换成GPU能够处理的格式,然后再将数据传递给GPU进行渲染。
答案:FlutterActivity、FlutterVC 等嵌入在歌平台原生层的业务类,都属于 platform 层。你答对了吗?
其实对于 flutter 的架构图,native 开发者需要从下往上看 platform - engine - framework,而 flutter 开发者则是从上往下看 framework - engine - platform 这样啦
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。