1.简单介绍
2.整体思路
了解Flutter——boost的工作机制,以及以下几个问题:
1.FlutterBoost如何实现Engine复用?
2.FlutterBoost如何在Engine复用的情况下管理多页面插件状态同步?
3.FlutterBoost是如何打开Flutter/Native页面的?
4.FlutterBoost还有那些坑?
3.基本用法
略。。。
4.整体架构
Native层概念
- Container:Native容器,FlutterActivityAndFragmentDelegate.Host的实现,默认为BoostFlutterActivity
- Container Manager:容器的管理者,IContainerManager的实现,具体为FlutterViewContainerManager
- Messaging:基于Channel的消息通信,具体为FlutterBoostPlugin
Dart层概念
- Container:Flutter用来容纳Widget的容器,具体实现为Navigator的派生类BoostContainer
- ContainerManager:Flutter容器的管理,提供show,remove等Api,具体为BoostContainerManager
- Coordinator: 协调器,接受Messaging消息,负责调用Container Manager的状态管理。具体为ContainerCoordinator
- Messaging:基于Channel的消息通信,具体为BoostChannel
Boost中 Container、Manager对象相互映射、相互协作,Dart层根据Native同步过来的生命周期事件进行响应。 每个Container都有其独立的FlutterView,通过单例的FlutterEngine驱动渲染及插件注册通信, 并具有唯一Id,注册于Manager Map表中,通过Key-Value的形式获取而非栈结构。
5.Native启动flutter页面源码流程分析
5.1 Native端发起启动Flutter页面调用
从Java层到C++层再到Dart层
5.1发起Native启动Flutter页面调用
Intent intent=CustomBoostFlutterActivity.withNewEngine().url(pageName.get(path))
.params(params).backgroundMode(CustomBoostFlutterActivity.BackgroundMode.opaque)
.build(context);
if (context instanceof Activity) {
Activity activity = (Activity) context;
activity.startActivityForResult(intent, requestCode);
} else {
context.startActivity(intent);
}
5.2进入BoostFlutterActivity&&onCreate生命周期回调
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
switchLaunchThemeForNormalTheme();
super.onCreate(savedInstanceState);
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
//FlutterActivityAndFragmentDelegate是Flutter相关操作的代理对象,
delegate = new FlutterActivityAndFragmentDelegate(this);
//1.初始化FlutterEngine,2.初始化Activity和Engine之间的配置
delegate.onAttach(this);
configureWindowForTransparency();
//创建FlutterView并装载进Activity
setContentView(createFlutterView());
configureStatusBarForFullscreenFlutterExperience();
}
5.3.FlutterActivityAndFragmentDelegate.onAttach
public void onAttach(@NonNull Context context) {
ensureAlive();
//确保Flutter环境初始化完毕
if (FlutterBoost.instance().platform().whenEngineStart() == FlutterBoost.ConfigBuilder.FLUTTER_ACTIVITY_CREATED) {
FlutterBoost.instance().doInitialFlutter();
}
if (flutterEngine == null) {
setupFlutterEngine();
}
platformPlugin = host.providePlatformPlugin(flutterEngine);
host.configureFlutterEngine(flutterEngine);
host.getActivity().getWindow().setFormat(PixelFormat.TRANSLUCENT);
}
5.4.FlutterBoost.doInitialFlutter
//初始化FlutterEngine MyApplication$onCreate FlutterBoost.instance().init(platform);
public void doInitialFlutter() {
if (mEngine != null) {
return;
}
if (mPlatform.lifecycleListener != null) {
mPlatform.lifecycleListener.beforeCreateEngine();
}
//创建FlutterEngine
FlutterEngine flutterEngine = createEngine();
if (mPlatform.lifecycleListener != null) {
mPlatform.lifecycleListener.onEngineCreated();
}
if (flutterEngine.getDartExecutor().isExecutingDart()) {
return;
}
//设置FlutterEngine的初始化路由
if (mPlatform.initialRoute() != null) flutterEngine.getNavigationChannel().setInitialRoute(mPlatform.initialRoute());
}
//Dart代码入口
DartExecutor.DartEntrypoint entrypoint = new DartExecutor.DartEntrypoint(
FlutterMain.findAppBundlePath(),
mPlatform.dartEntrypoint() //FlutterBoost.Platform "main"
);
//执行Dart代码
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
}
当FlutterMain一调用ensureInitializationComplete,Dart代码即被加载进内存。
private FlutterEngine createEngine() {
if (mEngine == null) {
FlutterMain.startInitialization(mPlatform.getApplication());
FlutterShellArgs flutterShellArgs = new FlutterShellArgs(new String[0]);
FlutterMain.ensureInitializationComplete(
mPlatform.getApplication().getApplicationContext(), flutterShellArgs.toArray());
mEngine = new FlutterEngine(mPlatform.getApplication().getApplicationContext(), FlutterLoader.getInstance(), new FlutterJNI(), null, false);
registerPlugins(mEngine);
}
return mEngine;
}
5.5 ShimPluginRegistry
registerPlugins(mEngine)
private void registerPlugins(FlutterEngine engine) {
try {
Class<?> generatedPluginRegistrant = Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
Method registrationMethod = generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
registrationMethod.invoke(null, engine);
} catch (Exception e) {
Debuger.exception(e);
}
}
@Keep
public final class GeneratedPluginRegistrant {
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine);
com.idlefish.flutterboost.FlutterBoostPlugin.registerWith(shimPluginRegistry.registrarFor("com.idlefish.flutterboost.FlutterBoostPlugin"));
}
}
public ShimPluginRegistry(@NonNull FlutterEngine flutterEngine) {
this.flutterEngine = flutterEngine;
this.shimRegistrarAggregate = new ShimRegistrarAggregate();
this.flutterEngine.getPlugins().add(shimRegistrarAggregate);
}
@Override
public Registrar registrarFor(String pluginKey) {
Log.v(TAG, "Creating plugin Registrar for '" + pluginKey + "'");
if (pluginMap.containsKey(pluginKey)) {
throw new IllegalStateException("Plugin key " + pluginKey + " is already in use");
}
pluginMap.put(pluginKey, null);
ShimRegistrar registrar = new ShimRegistrar(pluginKey, pluginMap);
shimRegistrarAggregate.addPlugin(registrar);
return registrar;
}
想了解FlutterBoost的机制,需要理解以下几个类的含义:
- PluginRegistry:插件注册中心, 顾名思义,管理插件的注册。
- Registrar:注册者, 注册者可以被插件所使用,提供插件所需要的Context、添加事件监听API等等...
- ShimRegistrarAggregate: 插件注册者的集合,FlutterPlugin, ActivityAware 2个接口的实现者,用于与Engine交互。
5.6 BoostFlutterActivity.onResume
@Override
protected void onResume() {
super.onResume();
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
delegate.onResume();
}
5.7
public void onResume() {
//同步器,将状态通过channel同步至Dart层。
mSyncer.onAppear();
Log.v(TAG, "onResume()");
ensureAlive();
flutterEngine.getLifecycleChannel().appIsResumed();
//判断当前Activity是否为顶层Activity(即最新绑定到Registry的Binding),如是,则通过Engine触发状态分发
if(ACTIVITY_CONTROL_SURFACE_ATTACH_TO_ACTVITY_HASH_CODE==0||
ACTIVITY_CONTROL_SURFACE_ATTACH_TO_ACTVITY_HASH_CODE!=this.host.getActivity().hashCode()){
flutterEngine.getActivityControlSurface().detachFromActivityForConfigChanges();
//这里调用到插件的链路为FlutterEnginePluginRegistry.attachToActivity --> BoostRegistrarAggregate.onAttachedToActivity
// --> BoostRegistrar.onAttachedToActivity 中会将相关Registrar监听器重新添加至Binding中
flutterEngine.getActivityControlSurface().attachToActivity(
host.getActivity(),
host.getLifecycle()
);
ACTIVITY_CONTROL_SURFACE_ATTACH_TO_ACTVITY_HASH_CODE=this.host.getActivity().hashCode();
}
if(platformPlugin!=null)
platformPlugin.attachToActivity( host.getActivity());
}
5.8.ContainerRecord.onAppear
@Override
public void onAppear() {
Utils.assertCallOnMainThread();
if (mState != STATE_CREATED && mState != STATE_DISAPPEAR) {
Debuger.exception("state error");
}
mState = STATE_APPEAR;
mManager.pushRecord(this);
//调用MethodChannelProxy.appear,通知Dart层Push当前页面至顶层
mProxy.appear();
//将FlutterView与Engine绑定,触发渲染
mContainer.getBoostFlutterView().onAttach();
}
5.9.MethodChannelProxy.appear
private void appear() {//通知Dart层push当前页面至顶层
invokeChannelUnsafe("didShowPageContainer",
mContainer.getContainerUrl(), //flutterPage
mContainer.getContainerUrlParams(), //test2 -> v_test2 test1 -> v_test1
mUniqueId
);
//Debuger.log("didShowPageContainer");
mState = STATE_APPEAR;
}
5.10 XFlutterView.attachToFlutterEngine
public void attachToFlutterEngine(
@NonNull FlutterEngine flutterEngine
) {
···
this.flutterEngine = flutterEngine;
// Instruct our FlutterRenderer that we are now its designated RenderSurface.
FlutterRenderer flutterRenderer = this.flutterEngine.getRenderer();
···
//从FlutterEngine中得到Render后,绑定在RenderSurface
//Surface可指定2种类型 surface、texture, 默认为前者
//最终会调用到RenderSurface.attachToRenderer
flutterRenderer.attachToRenderSurface(renderSurface);
// Initialize various components that know how to process Android View I/O
// in a way that Flutter understands.
···
}
5.11 RenderSurface.attachToRenderer
public interface RenderSurface {
/**
* Invoked by the owner of this {@code RenderSurface} when it wants to begin rendering
* a Flutter UI to this {@code RenderSurface}.
*
* The details of how rendering is handled is an implementation detail.
*/
void attachToRenderer(@NonNull FlutterRenderer renderer);
}
通过attachToRenderer可知,绑定好后,即可开始渲染。
以下是Dart层代码
5.12 ContainerCoordinator._onMethodCall
Future<dynamic> _onMethodCall(MethodCall call) {
Logger.log('onMetohdCall ${call.method}');
final String pageName = call.arguments['pageName'] as String;
final Map<String, dynamic> params =
(call.arguments['params'] as Map<dynamic, dynamic>)
?.cast<String, dynamic>();
final String uniqueId = call.arguments['uniqueId'] as String;
switch (call.method) {
case 'didInitPageContainer':
_nativeContainerDidInit(pageName, params, uniqueId);
break;
//将当前页面展示
case 'willShowPageContainer':
_nativeContainerWillShow(pageName, params, uniqueId);
break;
case 'didShowPageContainer':
nativeContainerDidShow(pageName, params, uniqueId);
break;
case 'willDisappearPageContainer':
_nativeContainerWillDisappear(pageName, params, uniqueId);
break;
case 'didDisappearPageContainer':
_nativeContainerDidDisappear(pageName, params, uniqueId);
break;
case 'willDeallocPageContainer':
_nativeContainerWillDealloc(pageName, params, uniqueId);
break;
case 'onNativePageResult':
break;
}
return Future<dynamic>(() {});
}
Native层的Channel信息最终会被Dart层的BoostChannel所接收,转发至coordinator._onMethodCall处理。
5.13 ContainerCoordinator.nativeContainerDidShow
bool nativeContainerDidShow(
String name,
Map<String, dynamic> params,
String pageId,
) {
FlutterBoost.containerManager
?.showContainer(_createContainerSettings(name, params, pageId));
//对无障碍辅助模式的兼容
try {
final SemanticsOwner owner =
WidgetsBinding.instance.pipelineOwner?.semanticsOwner;
final SemanticsNode root = owner?.rootSemanticsNode;
root?.detach();
root?.attach(owner);
} catch (e) {
assert(false, e.toString());
}
//生命周期同步
performContainerLifeCycle(
_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Appear,
);
...
return true;
}
5.14 BoostContainerManager.showContainer
void showContainer(BoostContainerSettings settings) {
if (settings.uniqueId == _onstage.settings.uniqueId) {
_onShownContainerChanged(null, settings.uniqueId);
return;
}
final int index = _offstage.indexWhere((BoostContainer container) =>
container.settings.uniqueId == settings.uniqueId);
if (index > -1) {
_offstage.add(_onstage);
_onstage = _offstage.removeAt(index);
setState(() {});
for (final BoostContainerObserver observer in FlutterBoost
.singleton.observersHolder
.observersOf<BoostContainerObserver>()) {
observer(ContainerOperation.Onstage, _onstage.settings);
}
Logger.log('ContainerObserver#2 didOnstage');
} else {
pushContainer(settings);
}
}
5.15 BoostContainerManager.pushContainer
void pushContainer(BoostContainerSettings settings) {
assert(settings.uniqueId != _onstage.settings.uniqueId);
assert(_offstage.every((BoostContainer container) =>
container.settings.uniqueId != settings.uniqueId));
_offstage.add(_onstage);//what ?
_onstage = BoostContainer.obtain(widget.initNavigator, settings);
//触发渲染
setState(() {});
for (final BoostContainerObserver observer in FlutterBoost
.singleton.observersHolder
.observersOf<BoostContainerObserver>()) {
observer(ContainerOperation.Push, _onstage.settings);
}
Logger.log('ContainerObserver#2 didPush');
}
5.16 BoostContainerManager.setState
@override
void setState(VoidCallback fn) {
if (SchedulerBinding.instance.schedulerPhase ==
SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
Logger.log('_refreshOverlayEntries in addPostFrameCallback');
_refreshOverlayEntries();
});
} else {
Logger.log('_refreshOverlayEntries in setState');
_refreshOverlayEntries();
}
fn();
//return super.setState(fn);
}
5.17 BoostContainerManager._refreshOverlayEntries
void _refreshOverlayEntries() {
final OverlayState overlayState = _overlayKey.currentState;
if (overlayState == null) {
return;
}
if (_leastEntries != null && _leastEntries.isNotEmpty) {
for (final _ContainerOverlayEntry entry in _leastEntries) {
entry.remove();
}
}
final List<BoostContainer> containers = <BoostContainer>[];
containers.addAll(_offstage);
assert(_onstage != null, 'Should have a least one BoostContainer');
containers.add(_onstage);//_onstage插入队列最末端 ?
_leastEntries = containers
.map<_ContainerOverlayEntry>(
(BoostContainer container) => _ContainerOverlayEntry(container))
.toList(growable: false); //生成固定长度的列表
overlayState.insertAll(_leastEntries);
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
final String now = _onstage.settings.uniqueId;
if (_lastShownContainer != now) {
final String old = _lastShownContainer;
_lastShownContainer = now;
_onShownContainerChanged(old, now);
}
updateFocuse(); //更新焦点
});
}
5.18 Overlay
class Overlay extends StatefulWidget {
}
Overlay对象管理boost页面widget的展示,Overlay可以独立的管理一个栈的widget,通过overlayState.insetAll(_leastEntries)插入一系列的widget,使栈的最后一个Entry(Widget)浮在前面所有Widget的上方,如是一个全屏的Widget,即是我们所说的页面展示。
TODO 将整个流程图筛理出来然后写成文章 1.Native启动Flutter 2.Flutter启动Native 3.Flutter启动Flutter
6.总结
- Boost是如何实现Engine复用的。
由于Boost在Native层通过单例提供Engine对象,自然Engine是复用的,在多个flutter页面切换时,与Engine相绑定的surface将切换至当前Activity.XFlutterView.surface渲染,Native将状态同步至Dart,由Dart层的ContainerManager调度OverlayEntry顺序,达到Push/Pop页面的效果。
- Boost是如何在Engine复用的情况下管理多页面插件状态同步。
如上述源码分析中的描述,Boost通过保持Engine的单例来保持插件的单例,Engine与PluginRegistry、BoostRegistrarAggregate、Registrar三者紧密协作,通过层层转发回调,在每一次attach/detach 重新注册/注销监听器来响应多页面的生命周期状态,将状态同步至各插件。
- Boost是如何打开Flutter/Native页面的。
如上述源码所述,Boost无论是Dart层还是Native层打开Flutter页面最终都会转发到Native的,当从Dart层打开Flutter页面时,通过BoostChannel将参数传递至Native,Native通过打开BoostFlutterActivity(通常)打开Flutter页面,在onCreate中装载FlutterView, 在onResume中通知Dart层渲染、将FlutterView与Engine绑定并开始渲染,getContainerUrl方法告知Dart层页面的路由名称,Dart层通过Overlay的管理方式将需要展示的Widget“浮”在所有页面之上。
- Boost还为我们躺了哪些不为人知的坑
键盘、无障碍、状态栏、白屏