美文网首页
FlutterBoost3.0发布preview版本

FlutterBoost3.0发布preview版本

作者: 闲鱼技术 | 来源:发表于2021-06-22 12:06 被阅读0次

    作者:闲鱼技术——皓黯

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

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

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

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

    5. 支持页面透明能力

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

    7. 增加前置拦截器

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

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

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

    相关文章

      网友评论

          本文标题:FlutterBoost3.0发布preview版本

          本文链接:https://www.haomeiwen.com/subject/csgpyltx.html