设为首页 加入收藏

TOP

Flutter 实现原理及在马蜂窝的跨平台开发实践(二)
2019-08-26 06:59:03 】 浏览:99
Tags:Flutter 实现 原理 马蜂窝 跨平台 开发 实践
,因此也影响到了毫不相干的 6 号节点。

图 5: 绘制节点与图层的关系

 

为了避免这种情况,Flutter 的设计者这里基于 Relayout Boundary 的思想增加了 Repaint Boundary。在绘制页面时候如果遇见 Repaint Boundary 就会强制切换图层。

如下图所示,在从上到下遍历控件树遇到 Repaint Boundary 会重新绘制到新的图层(深蓝色),在从下到上返回的时候又遇到 Repaint Boundary,于是又增加一个新的图层(浅蓝色)。

图 6: Repaint Boundary 机制

 

这样,即使发生重绘也不会对其他子树产生影响。比如在 Scrollview 上,当滚动的时候发生内容重绘,如果在 Scrollview 以外的地方不需要重绘就可以使用 Repaint Boundary。Repaint Boundary 并不会像 Relayout Boundary 一样自动生成,而是需要我们自己来加入到控件树中。

6.【Widget】控件层。所有控件的基类都是 Widget,Widget 的数据都是只读的, 不能改变。所以每次需要更新页面时都需要重新创建一个新的控件树。每一个 Widget 会通过一个 RenderObjectElement 对应到一个渲染节点(RenderObject),可以简单理解为 Widget 中只存储了页面元素的信息,而真正负责布局、渲染的是 RenderObject。

在页面更新重新生成控件树时,RenderObjectElement 树会尽量保持重用。由于 RenderObjectElement 持有对应的 RenderObject,所有 RenderObject 树也会尽可能的被重用。如图所示就是三棵树之间的关系。在这张图里我们把形状当做渲染节点的类型,颜色是它的属性,即形状不同就是不同的渲染节点,而颜色不同只是同一对象的属性的不同。

图 7:  Widget、Element 和 Render 之间的关系

 

如果想把方形的颜色换成黄色,将圆形的颜色变成红色,由于控件是不能被修改的,需要重新生成两个新的控件 Rectangle yellow 和 Circle red。由于只是修改了颜色属性,所以 Element 和 RenderObject 都被重用,而之前的控件树会被释放回收。

图 8: 示例

 

那么如果把红色圆形变成三角形又会怎样呢?由于这里发生变化的是类型,所以对应的 Element 节点和 RenderObject 节点都需要重新创建。但是由于黄色方形没有发生改变,所以其对应的 Element 节点和 RenderObject 节点没有发生变化。

图 9: 示例

 

7. 最后是【Material】 & 【Cupertino】,这是在 Widget 层之上框架为开发者提供的基于两套设计语言实现的 UI 控件,可以帮助我们的 App 在不同平台上提供接近原生的用户体验。

 

Flutter 在马蜂窝商家端App 中的应用实践

图 10: 马蜂窝商家端使用 Flutter 开发的页面

 

开发方式:Flutter + Native

由于商家端已经是一款成熟的 App,不可能创建一个新的 Flutter 工程全部重新开发,因此我们选择 Native 与 Flutter 混编的方案来实现。
在了解 Native 与 Flutter 混编方案前,首先我们需要了解在 Flutter 工程中,通常有以下 4 种工程类型:

1. Flutter Application

标准的 Flutter App 工程,包含标准的 Dart 层与 Native 平台层。

2. Flutter Module

Flutter 组件工程,仅包含 Dart 层实现,Native 平台层子工程为通过 Flutter 自动生成的隐藏工程(.ios  / .android)。

3. Flutter Plugin

Flutter 平台插件工程,包含 Dart 层与 Native 平台层的实现。

4. Flutter Package

Flutter 纯 Dart 插件工程,仅包含 Dart 层的实现,往往定义一些公共 Widget。

了解了 Flutter 工程类型后,我们来看下官方提供的一种混编方案(https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps ),即在现有工程下创建 Flutter Module 工程,以本地依赖的方式集成到现有的 Native 工程中。

官方集成方案(以 iOS 为例)

a. 在工程目录创建 FlutterModule,创建后,工程目录大致如下:

b. 在 Podfile 文件中添加以下代码:

flutter_application_path = '../flutter_Moudule/'

该脚本主要负责:

  • pod 引入 Flutter.Framework 以及 FlutterPluginRegistrant 注册入口

  • pod 引入 Flutter 第三方 plugin

  • 在每一个 pod 库的配置文件中写入对 Generated.xcconfig 文件的导入

  • 修改 pod 库的 ENABLE_BITCODE = NO(因为 Flutter 现在不支持 bitcode)

c. 在 iOS 构建阶段 Build Phases 中注入构建时需要执行的 xcode_backend.sh (位于 FlutterSDK/packages/flutter_tools/bin) 脚本:

"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build

该脚本主要负责:

  • 构建 App.framework 以及 Flutter.framework 产物

  • 根据编译模式(debug/profile/release)导入对应的产物

  • 编译 flutter_asset 资源

  • 把以上产物 copy 到对应的构建产物中

d. 与 Native 通信

  • 方案一:改造 AppDelegate 继承自 FlutterAppDelegate

  • 方案二:AppDelegate 实现 FlutterAppLifeCycleProvider 协议,生命周期由 FlutterPluginAppLifeCycleDelegate 传递给 Flutter

以上就是官方提供的集成方案。我们最终没有选择此方案的原因,是它直接依赖于 FlutterModule 工程以及 Flutter 环境,使 Native 开发同学无法脱离 Flutter 环境开发,影响正常的开发流程,团队合作成本较大;而且会影响正常的打包流程。(目前 Flutter 团队正在重构嵌入 Native 工程的方式)

最终我们选择另一种方案来解决以上的问题:远端依赖产物。

图 11 :远端依赖产物

iOS 集成方案

通过对官方混编方案的研究,我们了解到 iOS 工程最终依赖的其实是 FlutterModule 工程构建出的产物(Framework,Asset,Plugin),只需将产物导出并 push 到远端仓库,iOS 工程通过远端依赖产物即可。

依赖产物目录结构如下:

 

 

 

 

 

 

 

 

 

 

 

  • Ap
首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇关于OC中的几种延迟执行方式 下一篇电商 APP 下单页(俗称车2) 业务..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目