在 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整体的框架结构,主要包含:基础框架、组件、工具三部分,如图所示:

基础框架

JDFlutter基础框架分为三层架构,包含JDFlutter基础层,通用业务层,业务层。

  • 基础层:提供了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和原生的混合编译环境;其二,使用原生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')
}

这样就可以原生项目一起编译了。具体可以参照官方文档:http://github.com/flutter/flu…这样的方式虽可以满足混编需求,但还不是特别方便,开发完项目后,还需要去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

搭建PUB私服仓库

Flutter开发中使用的组件,一般公司内部会采用共享的方式,以避免重复开发,而Flutter组件共享,即需要使用pub仓库。由于公司内部的业务组件不适合上传到pub官方仓库,因此,需要搭建私服仓库,以解决各个业务研发团队,对Flutter组件共享需要。感兴趣的同学可以研究下官方pub仓库的源码 http://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

最新文章

  1. 解决NGUI自动被设置LYAER
  2. MySQL—FOREIGN KEY
  3. windows编程注意点(持续更新)
  4. PHP应用程序的安全性
  5. ASP.NET MVC 中的 T4
  6. 如何创建C++程序
  7. 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义。
  8. shell 获取指定目录下文件名
  9. 某马-某淘商城的day01---&gt;分析,工程搭建,tomcat插件启动工程,svn,反思
  10. Error:Execution failed for task &#39;:app:processDebugManifest&#39;.
  11. Google的java工具类Guava
  12. distribution 分发数据库 灾难恢复 备份恢复
  13. Manual Validation with Data Annotations C#对实体类进行手动验证
  14. Windows 用bat脚本带配置启动redis,并用vb脚本使其在后台运行。
  15. WebAPi使用Autofac实现依赖注入
  16. create-react-app之Invalid Host Header
  17. 单线程实现同时监听多个端口(windows平台c++代码)
  18. 基于Linux的智能家居的设计(3)
  19. 平台升级至spring 4.3.0 运行稳定
  20. UVa 225 黄金图形(回溯+剪枝)

热门文章

  1. PHP时间格式
  2. Font Awesome可缩放的矢量图标
  3. 传入sql语句,执行完提取内容赋值到控件上
  4. python中numpy矩阵运算操作大全(非常全)!
  5. 循环指令 LOOP
  6. ROS常见问题(三) 报错are you sure it is properly registered and that the containing library is built?
  7. spring boot 使用swagger
  8. 3分钟学会Python 针对Excel操作
  9. 五十五、SAP中调用系统自带的函数
  10. SpringMVC:提交日期类型报400错误解决方法