Flutter混编实践

一、跨平台技术的出现背景

1. 原生开发

Android基于Java或者Kotlin, iOS基于Objective-C或Swift,直接调用各自平台的SDK开发的应用程序;

  • 优点:能快速访问各种硬件功能(GPS、摄像头)速度快、性能高、可以实现复杂动画及绘制,整体用户体验好
  • 缺点: 开发成本高,一个应用要维护两套代码,一致性差

为了加快产品的开发周期,提高开发效率,保持多端的一致性,逐渐出现了多种跨平台技术,下面选取一些常用技术作为对比:

2. H5+原生混合开发

H5技术在各类app中使用的频率非常高,通过原生的网页加载控件WebView (Android)或WKWebView(iOS)来加载H5页面,而WebView实质上就是一个浏览器内核,其JavaScript依然运行在一个权限受限的沙箱中,所以对于大多数系统能力都没有访问权限,如无法访问文件系统、不能使用蓝牙等。所以我们通常要使用JsBridge来进行两端的通信,虽然web技术栈社区及资源丰富,但是性能不够好,对于复杂用户界面或动画,容易出现卡顿和掉帧。

3. React Native

React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,目前支持iOS和Android两个平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用。

4. Weex

Weex是阿里巴巴于2016年发布的跨平台移动端开发框架,思想及原理和React Native类似,最大的不同是语法层面,Weex支持Vue语法和Rax语法,Rax 的 DSL(Domain Specific Language) 语法是基于 React JSX 语法而创造。与 React 不同,在 Rax 中 JSX 是必选的,它不支持通过其它方式创建组件,所以学习 JSX 是使用 Rax 的必要基础。而React Native只支持JSX语法。

二 、Flutter的优势

Flutter和以上几种跨平台技术最大的不同是其自行实现一套渲染框架,可通过调用skia等方式完成自渲染,而不依赖于原生控件,也不用依赖于webview,使用的语言也从JavaScript变成了Dart。

1. 自绘引擎Skia

Flutter使用Skia作为其2D渲染引擎,Skia是Google的一个2D图形处理函数库,包含字型、坐标转换,以及点阵图都有高效能且简洁的表现,Skia是跨平台的,并提供了非常友好的API,目前Google Chrome浏览器和Android均采用Skia作为其绘图引擎。

2. Dart语言

Flutter使用Dart而不是JavaScript作为开发语言,主要有如下考虑:

  • 基于JIT的快速开发周期:Flutter在开发阶段采用,采用JIT模式,这样就避免了每次改动都要进行编译,极大的节省了开发时间;
  • 基于AOT的发布包: Flutter在发布时可以通过AOT生成高效的ARM代码以保证应用性能。而JavaScript则不具有这个能力。
3. 总结:
技术类型 UI渲染方式 性能 开发效率 动态化 框架代表
H5 WebView 渲染 一般 支持 Cordova、Ionic
JavaScript+原生渲染 支持 RN、Weex
Flutter 不支持 Flutter

三、Flutter框架结构

Flutter架构

Flutter 架构采用分层设计,从下到上分为三层,依次为:Embedder、Engine、Framework。

1. Embedder

操作系统适配层,实现了渲染 Surface 设置,线程设置,以及平台插件等平台相关特性的适配。从这里我们可以看到,Flutter 平台相关特性并不多,这就使得从框架层面保持跨端一致性的成本相对较低。

2. Engine

主要包含 Skia、Dart 和 Text,实现了 Flutter 的渲染引擎、文字排版、事件处理和 Dart 运行时等功能。Skia 和 Text 为上层接口提供了调用底层渲染和排版的能力,Dart 则为 Flutter 提供了运行时调用 Dart 和渲染引擎的能力。而 Engine 层的作用,则是将它们组合起来,从它们生成的数据中实现视图渲染。

3. Framework

层则是一个用 Dart 实现的 UI SDK,包含了动画、图形绘制和手势识别等功能。为了在绘制控件等固定样式的图形时提供更直观、更方便的接口,Flutter 还基于这些基础能力,根据 Material 和 Cupertino 两种视觉设计风格封装了一套 UI 组件库。我们在开发 Flutter 的时候,可以直接使用这些组件库。

​通过上面的架构可以看出,底层使用Skia引擎来统一渲染,上层开发接口和功能体验也就随即统一了,开发者再也不用操心平台相关的渲染特性了。也就是说,Skia 保证了同一套代码调用在 Android 和 iOS 平台上的渲染效果是完全一致的。

四、Flutter是如何实现跨平台的?

1. 自绘UI

引擎基于 Skia 绘制,操作 OpenGL、GPU,不需要依赖原生的组件渲染框架。


Flutter绘制过程

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)按完成上屏操作。

在Android中的层级关系图如下:


关键类层级关系
  1. SurfaceView
  2. TextureView
2. PlatformChannel

在实际的开发过程中,我们时常要从flutter端访问native的数据或者硬件能力,这个时候需要使用到Platform Channel进行通信

channel示意图

五、混合框架的搭建

对于这种新型技术,为了降低引入的风险,一般都会逐步地迁移和体验,这样就涉及到混合项目的搭建,native和flutter两端的页面交互和数据同步等问题

1、混合栈管理

为了实现高效、便捷的栈管理和页面交互,我们引入了闲鱼开源的FlutterBoost,它主要为我们解决了以下一些痛点:

  • 统一了native和flutter之间跳转方式
  • 提供与native一致的生命周期管理
  • 优化FlutterEngine的使用,减少内存消耗
  • 其他(比如黑屏闪屏的坑)

FlutterBoost和其他常规方案对比如下:


路由方案对比
2、自定义插件封装

混合项目绕不开两端的数据交互,于是我们基于MethodChannel封装了一些常用的插件,主要用来打通native和flutter两端的数据同步和硬件访问能力

3. 整体架构

我们使用google官方的方式,将Flutter模块作为一个module,让native那边依赖,形成了下的架构


整体架构

六、仓库和依赖管理

为了方便Android和iOS两端能够同步地访问代码,我们将Flutter模块单独抽取到一个仓库,然后提供给native去依赖

1. 仓库地址
  • Flutter模块仓库地址:http://git.fcbox.com/WA/ANG/flutter/Honey-Flutter
  • iOS丰蜜项目仓库地址:http://git.fcbox.com/WA/iOS/Hiveoperation.git
  • Android丰蜜项目仓库地址:http://git.fcbox.com/WA/ANG/Honey
2. 依赖关系
仓库依赖.png

七、落地效果

丰蜜项目中已经实现了“个人中心”模块的Flutter重构工作,并且成功地接入到Android和iOS两端,目前看来效果很理想,release包的体验几乎和原生无异,主要改造的界面如下:

1. Android端效果图
Android端效果图
2. iOS端效果图
iOS端效果图
3. 动态效果
ezgif.com-video-to-gif (1).gif

八、总结

1. 收益

使用Flutter混编,大概有80%以上的代码能够公用,剩余一小部分需要两端单独处理,总的来说Flutter在两个平台上的UI一致性是非常好的,帧率也比较稳定,后面推广开来的话,会对APP端的开发效率有一个大幅提升

2. 展望
  • 将Flutter部分的基础和公共代码封装成框架,方便其他项目引入
  • Flutter官方目前也在适配Web端,时机成熟,甚至可以一套代码3端公用
  • 动态化方案研究
  • 包体大小优化( 目前丰蜜的relaese包在Android端增加8M左右,iOS端压增加15M左右)
3. 上手难度

移动端的开发思维其实是相通的,Dart语言对于Android和iOS端的同学来说还是很好上手的,语法有点Java和Kotlin、Swift的影子。Flutter的设计思想也是受React启发,一切都是Widget,没有像android ios 那些些activity fragment 杂七杂八的概念,所以Web端的同学学习起来也更容易理解

  • Flutter for Android开发者
  • Flutter for iOS开发者
  • Flutter for Web开发者

你可能感兴趣的:(Flutter混编实践)