写点什么

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:003058

评论 1 条评论

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

Android 8 通知渠道(Notification Channels),美团移动端开发工程师

android 程序员 移动开发

软件测试常用工具总结(测试管理、单元测试、接口测试、自动化测试、性能测试、负载测试...)

六十七点五

程序员 软件测试 自动化测试 接口测试 测试工程师

Android Framework学习笔记(七)AMS全家桶,剖析Android开发未来的出路在哪里

android 程序员 移动开发

Android - 在线浏览源码,电话短信相关,文本变化监听器

android 程序员 移动开发

android Jetpack Navigation组件——堆栈操作和动画效果

android 程序员 移动开发

Android Material Design尝鲜,阿里P8面试官都说太详细了

android 程序员 移动开发

Android MTK 设置默认启动 Launcher,android实战pdf

android 程序员 移动开发

Android Activity 启动出现白屏带标题或闪屏问题解决,移动开发者社区

android 程序员 移动开发

android hxgsecurity 常用的集中加密方式封装,android项目开发案例

android 程序员 移动开发

Android - 定位方式,火星坐标系统,一键锁屏,字节Android高工面试

android 程序员 移动开发

Android 3年外包工面试笔记,有机会还是要去大厂学习提升

android 程序员 移动开发

墨刀发布企业版v3.5 ! 再度赋能“团队协同”新模式

Android App Bundle探索,android系统软件开发

android 程序员 移动开发

Android Dialog 的一些使用和优化心得(DialogFragment的使用和优化)

android 程序员 移动开发

读完这些“Java技术栈”,拿下阿里Offer没问题

Java MySQL spring 程序员 JVM

华为云GaussDB持续深耕创新与开放,打造企业核心数据上云信赖之选

华为云数据库小助手

GaussDB GaussDB(for openGauss) 华为云数据库 GaussDB(for MySQL) UGO

android activity Intent 传值 传对象(1),头条三面技术四面HR

android 程序员 移动开发

android activity Intent 传值 传对象,android开发框架开源登录界面

android 程序员 移动开发

Android Jsoup:实现HTML解析和Epub解析,论程序员成长的正确姿势

android 程序员 移动开发

怎么用EasyRecovery恢复sd卡中的数据

淋雨

EasyRecovery

Android APK反编译就这么简单 详解(附图),字节跳动大神讲座

android 程序员 移动开发

Android App关于应用程序升级的一点内容,app软件开发课程

android 程序员 移动开发

Android Binder 的主要内容概述以及特性和原理,Android开发前景怎么样

android 程序员 移动开发

云原生:详解|K8s技术栈解析, 一文读懂K8s工作原理

息之

架构 容器 云原生 k8s 集群

Android 6,android网络开发技术实战详解

android 程序员 移动开发

android LifeCycle-简单使用和详细原理解析,2021大厂Android面试经历

android 程序员 移动开发

Android NDK 开发之 CMake 必知必会,后台开发Android岗

android 程序员 移动开发

Android 11 Beta 版正式发布!以及众多面向开发者的重磅更新

android 程序员 移动开发

Android 12体验!新的黑夜模式、影音格式,详解系列文章

android 程序员 移动开发

Android Glide 3,flutter小程序

android 程序员 移动开发

Android Launcher——ui框架,嵌入式音视频方向

android 程序员 移动开发

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