当前位置:主页 > 查看内容

FlutterBoost3.0发布preview版本

发布时间:2021-06-22 00:00| 位朋友查看

简介:作者:闲鱼技术——皓黯 ? 在经历了近两个月的开发以及内部测试与线上灰度,FlutterBoost3.0的preview版本终于与大家见面了,与beta版本相比,这个版本在不大动主体结构的基础上,增加了以下能力: 重构生命周期,确保生命周期语义准确双端一致性近一步对齐……

作者:闲鱼技术——皓黯

? 在经历了近两个月的开发以及内部测试与线上灰度,FlutterBoost3.0的preview版本终于与大家见面了,与beta版本相比,这个版本在不大动主体结构的基础上,增加了以下能力:

重构生命周期,确保生命周期语义准确双端一致性近一步对齐增加自定义的启动参数实现页面返回传参方案支持页面透明能力增加自定义事件发送机制增加前置拦截器提供更完善的文档与例子

? 由于篇幅有限,就不对以上能力一一展开了。如果对具体实现感兴趣的话,可以通过源码和文档来了解相应的功能,我们今天先来聊一聊生命周期部分的设计与实现、文档与用例和社区建设

1. 页面生命周期设计

? FlutterBoost3.0有两个和页面相关的概念,一个是BoostContainer,另一个是BoostPage。每个BoostContainer在Native层都会有一个与之对应的容器,比如在Android端,这个容器可能是FlutterBoostActivity或者FlutterBoostFragment,而在iOS端,这个容器则指的是FBFlutterViewContainer。每个BoostContainer都会有一个与之对应的Navigator,因而一个BoostContainer可以包含多个BoostPage,这个设计也被我们称之为双重栈。细心的同学可能已经发现了,当我们需要打开一个Flutter页面时,有一个额外的参数withContainer,这个参数设置为false时,表示打开页面时不需要打开一个新容器,而这个参数如果被设置为true,则会在打开页面的同时,去打开一个新容器。

image.png

? 在开发业务的过程中,我们常常需要知道一个Flutter页面的可见性,比如我们写了一个Flutter页面,里面有一个VideoWidget,我们希望VideoWidget在页面可见的时候播放,在页面不可见的时候暂停。对页面可见性变化的监听是FlutterBoost需要提供的核心能力之一,因此我们提供了一个名为PageVisibilityObserver的API,用于专门监听页面可见性变化。

? 在一开始的设计当中,我们是通过上层Dart代码来掌控页面生命周期的。我们在FlutterBoostAppState里,维护了一个List\ BoostContaner\ ,而在每个BoostContainer中,则维护了一个List\ BoostPage\ ,所以显示的页面实际上就是顶部BoostContainer中的顶部BoostPage,所以每次顶部的BoostContainer发生变化,或者顶部BoostContainer中的顶部BoostPage发生变化,我们就认为发生了页面可见性变化,并将相应事件分发下去。

? 然而这个方案在实践的过程中,发现了一些问题,由于Dart侧只对Flutter的双层栈有感知,而对Native侧的页面栈则是毫无感知的,所以哪怕一个页面是顶部BoostContainer中的顶部BoostPage,也不见得这个页面就处于显示状态。举个例子,比如Flutter页面A去打开一个Native页面B,那么在打开Native页面B之后,Flutter页面A还是在双重栈顶部,因此如果不做任何处理,那么FlutterBoost还是认为Flutter页面A是可见的。我们也尝试了一些手段去解觉这些Bad Case,比如在Native层也维护一个Flutter页面栈用来感知页面显示隐藏等。但是在后续的验证过程中,我们发现这个方案可维护性不高,最终放弃了。

? 之后我们决定还是采用更稳妥的方案,BoostContainer的显示和隐藏,让Native容器自己来控制,当Native容器展示的时候发出onContainerShow事件通知对应的BoostContainer展示,Native容器隐藏时再发出onContainerHide事件通知对应的的BoostContainer隐藏,这样生命周期难以维护的问题也就解决了,这个方案的可维护性相比上一个方案要稳定,但是这个方案也有一个不得不解决的问题,第一次onContainerShow可能会收不到。我们以Android为例,FlutterBoostActivity创建后的第一次onResume发出了onContainerShow事件,然而该事件并不一定会被收到,因为此时可能页面对应的Widget还没有完成创建。稳定的生命周期事件是一个强诉求,所以这个问题我们需要在FlutterBoost3.0彻底解决。那么这个问题该如何解决呢?为了解决这个问题,我们将第一次收到onContainerShow事件单独处理,具体逻辑如下

void containerDidShow(BoostContainer container) {
 final id = container.pageInfo.uniqueId;
 assert(id != null);
 if (!hasShownPageIds.contains(id)) {
 hasShownPageIds.add(id);
 // This case indicates it is the first time that this container show
 // So we should dispatch event using
 // PageVisibilityBinding.dispatchPageShowEventOnPageShowFirstTime
 // to ensure the page will receive callback
 PageVisibilityBinding.instance
 .dispatchPageShowEventOnPageShowFirstTime(container.topPage.route);
 } else {
 PageVisibilityBinding.instance
 .dispatchPageShowEvent(container.topPage.route);

? 而在PageVisibilityBinding.dispatchPageShowEventOnPageShowFirstTime中,我们将事件分发延迟到这一帧渲染结束

///When page show first time,we should dispatch event in [FrameCallback]
///to avoid the page can't receive the show event
void dispatchPageShowEventOnPageShowFirstTime(Route dynamic route) {
 WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
 dispatchPageShowEvent(route);
}

? 这样我们就能确保第一次onContainerShow事件能够被接收到。从最后的代码来看,这是一个微不足道的改动,但是从设计上看,这个改动明确定义了页面生命周期事件,确保了生命周期事件一定被调用到。

2. Flutter应用生命周期设计

? 对于纯Flutter应用来说,一个Flutter应用实际上是跑在一个Activity或者ViewController上的,所以Flutter应用的生命周期实际上也和Activity或ViewController的生命周期绑定了,这也是Flutter目前的实现。但是对于单引擎多页面的混合栈场景来说,这无疑是不适用的。如果我们不对Flutter应用生命周期进行任何处理,那么就有可能出现Flutter应用生命周期混乱,最终导致界面无法刷帧。之前我们解决这个问题的思路,都是从Native层出发,通过控制生命周期事件的发送,来校正Flutter应用的生命周期。比如Android端,就是在每次Flutter应用被pause的时候,补发一个resume事件,而iOS端则是绕过FlutterViewController生命周期方法来自行管理生命周期事件。这样做虽然校正了Flutter应用的生命周期,但最终也导致了上层应用的生命周期非常混乱,可能会出现pause和resume连续多次被调用的情况。

? 为了上层使用者能有一个稳定的Flutter应用生命周期,我们决定将这部分能力接管。我们提供了一个BoostFlutterBinding,用于接管生命周期,相关代码如下

mixin BoostFlutterBinding on WidgetsFlutterBinding {
 bool _appLifecycleStateLocked = true;
 @override
 void initInstances() {
 super.initInstances();
 _instance = this;
 changeAppLifecycleState(AppLifecycleState.resumed);
 static BoostFlutterBinding get instance = _instance;
 static BoostFlutterBinding _instance;
 @override
 void handleAppLifecycleStateChanged(AppLifecycleState state) {
 if (_appLifecycleStateLocked) {
 return;
 Logger.log('boost_flutter_binding: handleAppLifecycleStateChanged ${state.toString()}');
 super.handleAppLifecycleStateChanged(state);
 void changeAppLifecycleState(AppLifecycleState state) {
 if (SchedulerBinding.instance.lifecycleState == state) {
 return;
 _appLifecycleStateLocked = false;
 handleAppLifecycleStateChanged(state);
 _appLifecycleStateLocked = true;
} 

? 代码非常简单,就是将handleAppLifecycleStateChanged方法给hook掉,这样无论Native层如何调用Flutter设定的生命周期事件,都不会影响到上层Flutter应用的生命周期。另外我们提供了一个changeAppLifecycleState方法,这个方法可以真正来改变上层Flutter应用的生命周期,目前这个方法的调用时机与Flutter容器个数相关,当容器大于等于1,Flutter应用的生命周期状态为resumed,而容器个数为0时,Flutter应用的生命周期状态则为paused。

3. 文档与用例完善

? FlutterBoost在之前只有一份接入文档,这对使用者来说并不算友好。因此我们决定提供更完善的文档。我们梳理了大家最关心的几个主题:

集成详细步骤基本的路由API页面生命周期监测相关API自定义发送跨端事件API

? 对于这些主题,我们这次都提供了相对应的文档,让使用者接入FlutterBoost可以更轻松,在遇到问题的时候也能更容易排查。另外我们也正在编写全新的example3.0,配合文档使用,在这个新的example3.0中,我们会把所有文档中提到的部分都以用例的方式呈现出来,希望这能帮助到大家。

4. 社区建设

? 之后Boost所有的开发计划工作,都会在project看板上体现出来,对应的地址为( https://github.com/alibaba/flutter_boost/projects)。对我们工作感兴趣的同学,可以在看板上看到我们的工作规划,欢迎一起交流探讨。另外如果有哪些想要我们支持的feature,也可以提issue给我们,如果我们评估合理,也会加入到看板上。

image.png

? 于此同时,我们增加了一个AUTHORS文件(https://github.com/alibaba/flutter_boost/blob/master/AUTHORS),记录所有FlutterBoost的贡献者(Contributors)。之后给我们提PR的同学,在提供PR的同时,也可以在这个文件上,加上你的名字,感谢大家为Boost做出的贡献。

5. 未来展望

? FlutterBoost3.0作为AliFlutter的核心基础设施,目前主要由闲鱼团队和UC Hummer团队进行开发维护,主要开发者包括noborder、0xZOne、christyuj、ColdPaleLight、luckysmg,另外也要感谢seedotlee、CheungSKei、bktoky、jk等同学为FlutterBoost3.0做出的贡献,目前集团内已有多个App接入了FlutterBoost3.0,包括夸克、淘宝联盟、吃货笔记等。

? 之后FlutterBoost3.0的preview版本原则上不会再做Breaking Change,目前已经使用了beta版的同学,也可以陆续切到preview版本上了,下个阶段我们会将工作重心放在issue收敛与文档用例补齐上。

? FlutterBoost作为一个开源项目,还有很长的路要走,感谢大家一路支持和包容,我们也希望有更多同学能参与到这个项目中来。

?


本文转自网络,原文链接:https://developer.aliyun.com/article/784832
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文

  • 周排行
  • 月排行
  • 总排行

随机推荐