《Flutter技术解析与实战》读书笔记

本文详细介绍了Flutter在混合工程中的应用,包括Flutter研发结构、构建优化、混合工程改造和混合技术方案,如FlutterBoost。同时,文章还探讨了Flutter在原生能力扩展、多媒体能力和业务架构设计方面的增强,如基于外接纹理的同层渲染和富文本能力。此外,作者还分享了数据统计与性能监控方案,以及企业级应用实战中的架构演进和Flutter与FaaS云端一体化架构的实践。

第一章 混合工程

1. 混合工程下的Flutter研发结构

在这里插入图片描述

2. 构建优化

问题:Android在FLutter启动是构建缓慢
解决:是工程应用Module对应的build.gradle位于android/app下

Native启动下的Flutter调试

iOS:使用Observatory
Android和iOS:使用IDE链接调试配置Dart Remote Debug
在这里插入图片描述

Native启动下的Flutter热重载

启动App,进入Flutter页面后
iOS:查找Observatory端口x和认证码y,在flutter目录下,执行flutter attach --debug-uri=http://127.0.0.1:x/y/
Android:同上,也可以通过IDE Logcat或者ADB Logcat | grep Observatory获取端口,端口转发使用ADB forwart。

Native与Flutter 联合调试

Android:Android Studio 的Attach Debugger to Android Process 调试;
iOS:结合Xcode Attach 的Attach to Process;

3. 混合工程改造实践

混合开发模式

在这里插入图片描述

依赖引入策略

本地依赖:同步方便,但耦合
远程依赖:减少耦合,同步繁琐

混合工程持续开发流程

在这里插入图片描述

4. 混合技术方案

flutter-boot(混合开发的脚手架)

集成问题:

  1. 版本兼容问题
  2. 代码封装问题
  3. 原生接入繁琐

解决方案:

  1. Flutter引擎的托管
  2. 页面路由的配置
  3. 原生测试的跳转入口
FlutterBoost(混合栈框架升级)
混合方案基本原理:

Flutter技术链由C++实现的Flutter Engine和Dart实现Framework组成。Flutter Engine负责线程管理,Dart VM负责状态管理和Dart代码加载等工作。
一个进程里面最多只有一个Dart VM,但是一个进程可以由多个Flutter Engine,多个Engine实例共享一个Dart VM。

现有混合方案问题

单引擎:深度耦合,无法支持多个平级逻辑页面
在这里插入图片描述
性能总结:Flutter View只有一个,每一个页面都是一个截图,如果Flutter页面多的情况下,则截图太多会占据大量内存,这里采用文件内存二级缓存策略,内存中只保存少量截图,按需加载,这样能在保证用户体验的同时内存维持在较为稳定的水平。
多引擎:

  • 冗余资源占据内存
  • 插件注册混乱
  • 增加通信复杂度
方案升级:FLutterBoost

在这里插入图片描述

  • Container:容器,容纳Widget,是Navigator的派生类
  • Container Manager:Container管理者,提供show/remove等API
  • Coordinator:协调器,接受Messaging消息,负责调用Container Manager的状态管理。
  • Messaging:基于Channel的消息通信。
    原理解析:使用单引擎多Navigator对象管理模式,使用Key-Value映射扁平化的形式维护所有页面,不只有一个Navigator,使用多个Navigator对象维持多栈管理,实现多平行页面不丢失。

第二章 能力增强

2.1 基于原生能力的插件扩展

Flutter App调用Native APIs(Platform Channel)
在这里插入图片描述
Platform Channel架构图
在这里插入图片描述

2.2 基于外接纹理的同层渲染

在这里插入图片描述
Layer Tree:这个是dart runtime输出的一个树状数据结构,树上的每一个叶子节点,代表了一个界面元素(Button,Image等等)。
Skia:这个是谷歌的一个跨平台渲染框架,从目前IOS和anrdroid来看,SKIA底层最终都是调用OpenGL绘制。Vulkan支持还不太好,Metal还不支持。
Shell:这里的Shell特指平台特性(Platform)的那一部分,包含IOS和Android平台相关的实现,包括EAGLContext管理、上屏的操作以及后面将会重点介绍的外接纹理实现等等。
从图中可以看出,当Runtime完成Layout输出一个Layertree以后,在管线中会遍历Layertree的每一个叶子节点,每一个叶子节点最终会调用Skia引擎完成界面元素的绘制,在遍历完成后,在调用glPresentRenderBuffer(IOS)或者glSwapBuffer(Android)按完成上屏操作。
问题:Flutter在Native和Flutter Engine上实现了UI的隔离,书写UI代码时不用再关心平台实现从而实现了跨平台。但是Flutter想要获取一些Native侧的高内存占用图像(摄像头帧、视频帧、相册图片等等)会变得困难重重,前文说到的Channel用于消息传送,传输文件或图像会消耗巨大内存与CPU。

解决方案:外接纹理Texture

  1. FLutter渲染流程
    Native端的数据源(摄像头播放器等)将数据写入PixelBuffer,Flutter拿到之后转为OpenGLES Texture,交由Skia绘制。在这里插入图片描述
  2. Flutter线程结构
    在这里插入图片描述
    GPU Runner:负责GPU的渲染相关操作。
    IO Runner:负责资源的加载操作。
    Platform Runner:运行在main thread上,负责所有Native与Flutter Engine的交互。

在这里插入图片描述
iOS通过两个线程各自使用自己的EAGLContext,彼此通过ShareGroup(android为shareContext)来共享纹理数据。

2.3 多媒体能力扩展实践

闲鱼相册组件API:
在这里插入图片描述
Flutter层使用MVC架构;Native层由OpenGL负责BitMap转纹理。

2.4 富文本能力应用实践

Text:只能显示简单样式文本。
TextSpan:只能显示多重文本样式。

RichText

在这里插入图片描述
通过TextPaint的Layout,在过程中通过TextSpan结构树,一次通过AddText添加各个阶段的文本,,最后通过Paragraph的Layout计算文本高度。
在这里插入图片描述
再利用SpaceSpan记录宽高属性,和RichText结合可实现文案 图片 自定义控件融合起来,实现复杂效果。

第三章 业务架构设计

3.1 应用框架实践

Fish Redux

开发目的:1. 页面的集中状态管理,页面的不同组件共享一个数据涞源,当数据涞源发生变化,则通知页面的所有组件。
2. UI组件的复用,进行组件化切分。
功能介绍

  1. Redux可以做预测 集中式 易调试 灵活性的数据管理框架,所有对数据的“增删查改”等操作都由Redux集中负责。
  2. Redux 的概念是状态管理,那在已有 state 的基础上,为什么还需要 Redux ?因为使用 Redux 的好处是:共享状态和单一数据。
  3. Redux使用Middleware(AOP)模式和Subscribe机制,给框架带来灵活性和扩展性。
  4. Fish Redux通过Redux做集中化的可观察的数据管理,另外,在面向端侧FLutter页面纬度开发的场景中,通过一个组件需要定义一个数据(Sturct)和一个Reducer,通过组件之间存在者父依赖子的关系,解决“集中”和“分治”之间的矛盾,通过对Reducer的手动层层组装成改变为由框架自动完成,大大降低了使用Redux的工作。

3.2 轻量级动态化渲染引擎的设计

1. 现有动态方案
  • CodePush是谷歌提供的动态化方案,在执行Dart VM的时候,通过加载isolate_snapshot_data和isolate_snapshot_instr两个文件,就能达到动态更新(已被谷歌放弃)。
  • 动态模板是通过定义一套DSL,在端侧便携配套的解析引擎,从而实现动态化,例如LuaViewSDK/Tangram-IOS和Tangram-Android。这些方案都创建的是Native的View,如果想在Flutter里面实现,需要创建Texture来桥接。在Native端渲染完成之后,再将纹理贴在Flutter的容器中(实现成本高,性能不佳)。
2. 模版编译

直接将Dart文件作为模版,将其转化为JSON格式的协议数据,端侧拿到协议数据再进行解析。

  1. 规范模版,代码编写时按照模版规定的规则。
  2. 编译流程,用Dart的Analyzer库编译写好的模版,通过parseCompilationUnit函数,直接将Dart源码解析在以CompilationUnit为Root节点的AST树,递归遍历整棵树,最后得到ConstructorNode树。端侧拿到节点树之后,就可以根据Widget的名称和参数生成Widget树。
  3. 渲染引擎端侧获得JSON格式的模板信息,渲染引擎的工作就是解析模板信息并创建Widget生成Widget树 的过程。
    在这里插入图片描述
    在这里插入图片描述

3.3 面向切面编程的设计实践

Dart语言特性: 1. Dart的反射支持很弱,只支持检查(Introspection),不支持修改(Modification);2. Flutter为了控制包大小,保证健壮性等原因,禁止了反射。
因此,Dart的AOP方案得基于编译期修改。

闲鱼AOP库:AspectD
  1. 无Before Around After三种语法,只有统一的抽象,Around。
  2. Call是调用点,Execute是执行点,Inject 的输入参数相对于 Call/Execute 而言,多了一个 lineNum 的命名参数,可用于指定插入逻辑的具体行号。

3.4 高性能的动态模版渲染实践

目的:通过设计模板DSL用于配置生成Flutter的Widget树界面;
难点:Widget是immutable的,只是包含了视图的配置信息,是非常轻量级的。在Flutter中,Widget会被不断的创建销毁,这会导致布局计算非常的频繁;因此无法通过单纯使用DSL定义widget树的方式生成渲染界面;
解决要点:需要在Element以及Render-Object上做处理,需自定义Widget。

Flutter在Layout过程中的优化

Flutter采用一次布局的方式,O(N)的线性时间来做布局和绘制。
在这里插入图片描述
在一次遍历中,父节点调用每个子节点的布局方法,将约束向下传递,子节点根据约束,计算自己的布局,并将结果传回给父节点;
RelayoutBoundary优化
RenderObject树是真正负责渲染的,根据其layout方法,可知标记为RelayoutBoundary,子节点的大小变化不会影响到父节点的布局;
Element更新优化
为什么Widget频繁创建销毁不会影响渲染性能呢?
Element定义了updateChild的方法,最早在Element被创建,Framework调用mount的时候,以及RenderObject被标记为needsLayout执行RenderObject.performLayout等场景,会调用Element的updateChild方法;
通过runtimeType和key比较来判断;如果可以更新,更新Element子节点;否则deactivate子节点的Element,根据newWidget创建新的Element。

在这里插入图片描述
实现要点:

  • 自定义Widget、Element以及RenderObject
  • 处理match_content,先计算子节点的大小,然后再计算当前节点的大小
  • 处理match_parent,重载performLayout方法,获取父节点大小

目前存在的问题:每次Widget的更新,都会导致2N次的Layout计算。帧率达不到Flutter页面

第四章 数据统计与性能

4.1 数据统计框架的设计

在Flutter上的埋点实现方案

Flutter原生方案主要通过注册监听Flutter的NavigatorObserver来获取Flutter页面的进栈(push)和出栈(pop)实事件。
问题:

  • 假设A、B两个页面先后进栈(A enter -> A leave -> B enter)。然后B页面返回退出(B leave),此时A页面重新可见,但是此时是收不到A页面push(A enter)的事件。
  • 假设在A页面弹出一个Dialog或者BottomSheet,而这两类也会走push操作,但实际上A页面并未离开。
    闲鱼自研方案

在这里插入图片描述
在这里插入图片描述

4.2 性能稳定性监控方案的设计

Flutter性能稳定性目标

  • 页面滑动流畅度
  • 页面加载耗时
  • 异常率
页面滑动流畅度
  1. 官方检测工具:Performance Overlay;只能在debug和profile模式下开启,无法用于线上版本统计。
  2. 改进方式:注册WidgetsFlutterBinding监听页面,刷新回调handleBeginFrame()和handleDrawFrame()。
    在这里插入图片描述
页面加载耗时

在这里插入图片描述
在这里插入图片描述

异常率

Flutter内部assert、try-catch和一些异常逻辑的地方都会调用FlutterError.onError,通过重定向FlutterError.onError可以检测到异常发生次数。

4.3 高可用框架的设计与实践

性能监控
  1. 性能指标
    页面滑动流畅度、页面加载耗时、页面异常
  2. sdk特性
    准确性、线上监控、易于扩展

4.4 跨端方案性能对比实践

Flutter对比React Native,Flutter win。

第五章 企业级应用实战

架构演进方案

  1. 已有App+Flutter容器(flutter_boost)
  2. Flutter页面+Native UI(Channel+纹理)

Flutter与FaaS云端一体化架构

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值