最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

FlutterBoost3.0 发布 preview 版本

  • 2021-07-05
  • 本文字数:4086 字

    阅读完需:约 13 分钟

FlutterBoost3.0发布preview版本

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


1.重构生命周期,确保生命周期语义准确

2.双端一致性近一步对齐

3.增加自定义的启动参数

4.实现页面返回传参方案

5.支持页面透明能力

6.增加自定义事件发送机制

7.增加前置拦截器

8.提供更完善的文档与例子


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

页面生命周期设计

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


null

在开发业务的过程中,我们常常需要知道一个 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 事件单独处理,具体逻辑如下:


    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 eventvoid dispatchPageShowEventOnPageShowFirstTime(Route<dynamic> route) {    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {        dispatchPageShowEvent(route);    });}
复制代码


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

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。

文档与用例完善

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

• 集成详细步骤

• 基本的路由 API

• 页面生命周期监测相关 API

• 自定义发送跨端事件 API


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

社区建设

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


null


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

未来展望

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


本文转载自:闲鱼技术(ID:XYtech_Alibaba)

原文链接:FlutterBoost3.0发布preview版本

2021-07-05 08:002931

评论 1 条评论

发布
用户头像
有兴趣卖解决方案吗,关于移动端的,我们是华东院的
2021-09-17 13:51
回复
没有更多了
发现更多内容

性能压测

【架构师训练营第 1 期 07 周】 学习总结

Bear

极客大学架构师训练营

springboot 热部署

hepingfly

Java springboot SpringCloud 热部署

7.1性能测试:系统性能的主要技术指标

张荣召

7.2全链路压测的挑战

张荣召

架构师训练营week07作业

IT老兵重开始

第 7 周 作业

Pyr0man1ac

架构师训练营 1 期 - 第七周作业(vaik)

行之

极客大学架构师训练营

#链表# #快慢指针#

玉皇大亮

链表 快慢指针

7.4操作系统:计算机如何处理成百上千的并发请求?

张荣召

架构师训练营第 1 期 -Week7 - 性能优化一学习总结

鲁大江

极客大学架构师训练营

【架构师训练营第 1 期 07 周】 作业

Bear

极客大学架构师训练营

第七周 性能优化 作业一

应鹏

极客大学架构师训练营

7.3性能优化:系统性能优化的分层思想

张荣召

Week 7 作業

Judyyy

第 7 周 听说你有好几个线程

Pyr0man1ac

第七周 性能优化 作业二

应鹏

极客大学架构师训练营

与前端训练营的日子--Week02

SamGo

学习

第七周总结

Geek_ac4080

架构师训练营第 1 期 -Week7 - 课后练习

鲁大江

极客大学架构师训练营

Week 7 學習總結

Judyyy

架构师训练营1期 - week07- 作业

lucian

极客大学架构师训练营

目标检测之ASFF

Dreamer

Week3 代码重构

贺志鹏

极客大学架构师训练营

架构师训练营第七周学习笔记

一马行千里

学习 极客大学架构师训练营

架构师训练营 1 期 - 第七周总结(vaik)

行之

极客大学架构师训练营

第3周作业

伊灵

第七周作业

Geek_ac4080

week3-作业二:根据当周学习情况,完成一篇学习总结

未来已来

第三周-课后练习

jizhi7

架构师训练营第七周学习总结

文智

极客大学架构师训练营

FlutterBoost3.0发布preview版本_大前端_闲鱼技术_InfoQ精选文章