Flutter_Boost

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还为我们躺了哪些不为人知的坑

键盘、无障碍、状态栏、白屏