京东技术中台的Flutter实践之路

Posted 前端之巅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了京东技术中台的Flutter实践之路相关的知识,希望对你有一定的参考价值。


作者 | 京东 ARES 跨端团队
编辑 | Yonie
在 2019 年,Flutter 推出了多个正式版本,支持的终端越来越多,使用的项目也越来越多。Flutter 正在经历从小范围尝鲜到大面积应用的过程,越来越多的研发团队加入到 Flutter 的学习热潮中,京东作为互联网大厂之一也积极参与了 Flutter 的跨端方案研究。本文将介绍京东在 Flutter 上的应用方案和相关优化成果。
为什么考虑 Flutter 技术方案

其实京东很早就开始研究并实践跨端的开发解决方案,最早使用的是 Hybrid App 的技术方案,从 2015 年底开始逐步转向 RN 技术栈,目前应该是业内 RN 技术平台应用最广泛、配套设施比较完善的公司之一。从 2018 年中开始,我们也关注到了 Flutter 技术,最吸引我们的特性是高性能和兼容性。这两点也是目前 RN 技术相对不足的地方。高性能指的是复杂场景和交互下的渲染性能,兼容性指的是不同终端平台上的布局和体验的一致性,这点在碎片化严重的 android 平台上尤其重要。

京东在 Flutter 的实践
随着 2018 年底 Google 正式发布了 Flutter 预览版本,京东内部也越来越多的研发团队有用 Flutter 进行开发业务的诉求。我们正式启动研发并内部发布了 JDFlutter 引擎。在官方 Flutter 引擎之上,我们做了额外的优化和功能扩展:
  • Flutter 工程改造: 对 Flutter 开发环境和 dart 代码管理进行优化,可以无缝集成到现有 APP 中并支持自动化 dart 编译打包,便于开发和调试。
  • 路由及多页面管理: 对原生页面和 flutter 页面实现了集中路由管理,可以双向传参、跳转并且进行了共享内存优化。
  • 扩展 UI 组件库: 官方支持的 Material 和 Cupertino 样式不能满足需求,我们内部实现了自定义样式的组件库。
  • 原生能力扩展: 对官方原生能力进行了扩展,封装了包括网络、登陆、埋点等等基础能力的打通并提供了 50+ 原生扩展 API。
  • Android 端动态化支持: 在 Android 端实现了动态化支持,可以线上热更新业务。ios 端暂不支持动态化。

目前京东商城、京东视频、京东到家、京东物流、7Fresh 等 APP 都有业务采用 JDFlutter 进行开发。

JDFlutter 框架设计

JDFlutter 整体的框架结构,主要包含:基础框架、组件、工具三部分,如图所示:

京东技术中台的Flutter实践之路

基础框架
JDFlutter 基础框架分为三层架构,包含 JDFlutter 基础层,通用业务层,业务层。
  • 基础层: 提供了 Flutter 的基础组件支持,包括组件管理,状态管理等;基础层完全独立,对业务没有依赖。
  • 通用业务层: 提供了通用型业务组件支持,例如登录组件,支付组件等;通用业务层依赖于基础层。
  • 业务层: 即具体业务逻辑实现层,根据业务需要进行不同组件的组合,实现业务页面的快速开发。

京东技术中台的Flutter实践之路

核心组件
  • 组件管理: 组件之间通过标准的协议接口进行通信,降低组件耦合,便于维护及组件升级;

  • 状态管理: 实现数据和界面分离,统一状态管理,以数据的变化来驱动界面的改变,更有利于数据的持久化和保存,同时也有利于 UI 组件的复用;
  • Hybrid Router: 主要解决 Flutter 和 Native 之间交叉跳转的问题,减少内存开销,共享同一个 Flutter Engine。

工具介绍
  • 编译发布: 优化 Flutter 原有的编译逻辑,管理依赖 Flutter 原生依赖关联,打包 Flutter 和原生代码,实现自动化构建发布。

  • 资源管理: 管理图片资源,将资源转换成 Flutter 类,便于资源的读取操作,类似 Andorid 的 R 类;
  • 模版代码生成: 减少 Flutter 的代码编写,自动生成 Flutter 组件的框架模板代码,提升代码编写效率;
  • JSON 转换: 将 JSON 数据转换成 Flutter code,并提供 json 转 Flutter 对象的 API,减少动手编写 Flutter code 及解析。

JDFlutter 业务开发实践

JDFlutter 为业务研发团队提供了全流程的开发解决方案:

京东技术中台的Flutter实践之路

配置混合工程

Flutter 和原生混合开发有两种情况,其一,开发 Flutter 业务的同学,需要和原生做交互,因此需要有 Flutter 和原生的混合编译环境;其二,使用原生 SDK 开发业务的同学,需要和 Flutter 业务一起集成打包,此时需对 Flutter 透明,以减少对 Flutter 编译环境的依赖,并且,只依赖原生编译环境即可,此时我们将 Flutter 编译成 aar 依赖,放入原生项目中即可。接下来,我们将重点介绍 Android 和 iOS 的混合编译环境配置。

Android 平台配置

创建一个 flutter module

 flutter create -t module --org com.example my_flutter

在原生根项目的 settings.gradle 加入如下配置信息

// MyApp/settings.gradle
include ':app' // assumed existing content
setBinding(new Binding([gradle: this])) // new
evaluate(new File( // new
settingsDir.parentFile, // new
'my_flutter/.android/include_flutter.groovy' // new
))

在原生 App 模块中加入 flutter 依赖

dependencies {
implementation project(':flutter')
}

这样就可以原生项目一起编译了。

具体可以参照官方文档: https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps

这样的方式虽可以满足混编需求,但还不是特别方便,开发完项目后,还需要去 Android Studio 项目中进行编译,比较麻烦,所以我们也可以把 Flutter 项目 settings.gradle 改造,在 Flutter 开发环境下直接运行包含原生代码的混合项目,改造方式如下:

// MyApp/settings.gradle
//projectName 原生模块名称
//projectPath 原生项目路径
include ":$projectName"
project(":$projectName").projectDir = new File("$projectPath")

这样改造之后即可在 Flutter IDE 中直接编译 Flutter 混合工程,并进行调试,也可以运行 futter run 来启动 Flutter 混合工程,不过在配置的时候,需要注意 Flutter 中 gradle 编译环境和原生编译环境的一致性,如果不一致可能会导致编译错误。

iOS 平台配置

创建 flutter module

flutter create -t module my_flutter

进入 iOS 工程目录,初始化 pod 环境(如果项目工程已经使用 Cocoapods,跳过此步骤)

pod init

编辑 Podfile 文件

## 在 Podfile 文件添加的新代码
flutter_application_path = '/{flutter module 目录}/my_flutter'
eval(File.read(File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)

安装 pod

pod install

打开工程 (***.xcworkspace) 配置 build phase,为编译 Dart 代码添加编译选项

打开 iOS 项目,选中项目的 Build Phases 选项,点击左上角 + 号按钮,选择 New Run Script Phase,将下面的 shell 脚本添加到输入框中:

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

京东技术中台的Flutter实践之路

搭建 PUB 私服仓库

Flutter 开发中使用的组件,一般公司内部会采用共享的方式,以避免重复开发,而 Flutter 组件共享,即需要使用 pub 仓库。由于公司内部的业务组件不适合上传到 pub 官方仓库,因此,需要搭建私服仓库,以解决各个业务研发团队,对 Flutter 组件共享需要。

感兴趣的同学可以研究下官方 pub 仓库的源码: https://pub.dartlang.org/,其对 Google Cloud 环境有很大的依赖 , 也可以基于 https://github.com/kahnsen/pub_server 来搭建一个简易版本的私服仓库,以满足上传和下载功能,pub 协议相对比较简单,我们可以在源码增加协议接口来实现更多功能。

运行 pub_server

~ $ git clone https://github.com/dart-lang/pub_server.git
~ $ cd pub_server
~/pub_server $ pub get
...

~/pub_server $ dart example/example.dart -d /tmp/package-db
Listening on http://localhost:8080

To make the pub client use this repository configure your shell via:

$ export PUB_HOSTED_URL=http://localhost:8080

发布一个 Flutter 组件需要修改 pubspec.yaml,增加以下内容:

name: hello_plugin //plugin 名称
description: A new Flutter plugin. // 介绍
version: 0.0.1// 版本号
author: xxx <xxx@xxx.com>// 作者和邮箱
homepage: https://localhost:8080 // 组件的介绍页面
publish_to: http://localhost:8080// 仓库上传地址

上传时可以使用如下命令检查代码错误,并显示出上传的目录结构

pub publish --dry-run

如果有不想上传的文件,可以在根目录增加一个.gitignore 文件来忽略如下:

/build

Flutter 组件的依赖配置,在项目的 pubspec.yaml 中 dependencies: 下增加如下信息

dependencies:
hello_plugin:
hosted:
name: hello_plugin
url: http://localhost:8080
version: 0.0.2

这样可以在公司内部实现 Flutter 组件共享,如果不想搭建自己的 pub 仓库,也可以采用 git 依赖,配置如下

dependencies:
hello_plugin:
git:
url: git://github.com/hello_plugin.git //git 地址
ref: dev-branch // 分支
Flutter 业务的开发与调试

在 Flutter IDE 中编译代码调试会很方便,直接点击 debug 按钮即可进行代码调试,如果是混合工程在 Android studio 或者 xcode 中运行的工程,则没办法这么做,但也可以实现调试:

将要调试的 App 安装到手机中(安装 debug 版本),连接电脑,执行如下命令,同步 Flutter 代码到设备的宿主 App 中

$ cd flutterProjectPath/
$ flutter attach

执行完命令后会进行等待设备连接状态,然后打开宿主 App,进入 Flutter 页面,看到如下信息提示则表示同步成功。

zbdeMacBook-Pro:example zb$ flutter attach
Waiting for a connection from Flutter on MI 5X...
Done.
Syncing files to device MI 5X... 1.2s

以上是关于京东技术中台的Flutter实践之路的主要内容,如果未能解决你的问题,请参考以下文章

第2345期哈啰中台业务 Flutter 实践

JDFlutter | 京东技术中台新一代跨平台开发框架

3 年PB级企业三高大数据全域中台架构设计与实践之路

京东:将Flutter扩展到微信小程序端的探索

转型路上的实践,平安银行自动化运维及中台建设之路

京东千万并发 API 网关实践之路!