在 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

干货 | 京东技术中台的Flutter实践之路的更多相关文章

  1. 干货 | 京东云原生容器—SpringCloud实践(一)

    "云原生"成为近年热词并不是一种偶然,它不是一个软件,也不是一种框架,而是一堆理念集合,以及围绕这些理念所产生的一些最佳实践的工具.云原生天然就是作用于服务架构的,可以视作一个服务 ...

  2. 小鹏汽车技术中台实践 :微服务篇 InfoQ 今天 以下文章来源于InfoQ Pro

    小鹏汽车技术中台实践 :微服务篇 InfoQ  今天 以下文章来源于InfoQ Pro

  3. 知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

    本文来自知乎官方技术团队的“知乎技术专栏”,感谢原作者陈鹏的无私分享. 1.引言 知乎存储平台团队基于开源Redis 组件打造的知乎 Redis 平台,经过不断的研发迭代,目前已经形成了一整套完整自动 ...

  4. 基于Kubernetes 构建.NET Core技术中台

    今天下午在腾讯云+社区社区分享了<基于Kubernetes 构建.NET Core技术中台>,下面是演讲内容的文字实录. 我们为什么需要中台 我们现在处于企业信息化的新时代.为什么这样说呢 ...

  5. 直击JDD | 京东技术全景图首次展示 四大重磅智能技术驱动产业未来!

    11月19日,主题为"突破与裂变"的2019京东全球科技探索者大会(JDDiscovery)在京盛大开幕,京东集团展示了完整的技术布局与先进而丰富的对外技术服务,对外明确诠释了&q ...

  6. 学习PHP爬虫--《Webbots、Spiders和Screen Scrapers:技术解析与应用实践(原书第2版)》

    <Webbots.Spiders和Screen Scrapers:技术解析与应用实践(原书第2版)> 译者序 前言 第一部分 基础概念和技术 第1章 本书主要内容3 1.1 发现互联网的真 ...

  7. 【行业干货】ASOS:外来快时尚品牌的入华战 - 行业干货 - 京东内部论坛 - Powered by Discuz!

    [行业干货]ASOS:外来快时尚品牌的入华战 - 行业干货 - 京东内部论坛 - Powered by Discuz! [行业干货]ASOS:外来快时尚品牌的入华战

  8. 20145226夏艺华 网络对抗技术EXP8 WEB基础实践

    20145226夏艺华 网络对抗技术EXP8 WEB基础实践 实验问题回答 1.什么是表单? 表单在网页中主要负责数据采集功能.一个表单有三个基本组成部分: 表单标签:这里面包含了处理表单数据所用CG ...

  9. 基于Kebernetes 构建.NET Core技术中台

    原文:基于Kebernetes 构建.NET Core技术中台 我们为什么需要中台 我们现在处于企业信息化的新时代.为什么这样说呢? 过去企业信息化的主流重心是企业内部信息化.但现在以及未来的企业信息 ...

随机推荐

  1. POJO,JavaBean,entity的理解

    POJO本质是就是JavaBean JavaBean JavaBean实际上是指一种特殊的Java类,它通常用来实现一些比较常用的简单功能,并可以很容易的被重用或者是插入其他应用程序中去.所有遵循“一 ...

  2. .NET via C#笔记12——泛型

    12 泛型 使用值类型作为参数的泛型容器,传入值类型的参数时,不需要进行装箱 12.1 FCL中的泛型 System.Array中提供了很多泛型方法 AsReadOnly BinarySearch C ...

  3. CAN编写完分帧发送, 分帧接收,J1939位域型结构体心得

    关于由多个不同的C文件构成的工程,我采用以下方法 以为400Hz数字电源程序为例 假设工程由以下文件组成 DC_Comm.c 主要完成串口通讯部分 DC_Config.c 主要完成时钟,外设 中断初始 ...

  4. P1045 快速排序

    P1045 快速排序 转跳点:

  5. 使用 Dashboard【转】

    上一节我们完成了 Kubernetes Dashboard 的安装,本节就来实践一下. Dashboard 界面结构 Dashboard 的界面很简洁,分为三个大的区域. 顶部操作区在这里用户可以搜索 ...

  6. a标签的超链接提交form表单

    <form action="/home/search" method="get" id="search_form"><di ...

  7. 《新标准C++程序设计》3.1.4-3.2(C++学习笔记6)

    1.类型转换构造函数 (1)定义 只有一个参数,而且不是复制构造函数的构造函数,一般就可以看作是转换构造函数. 当需要的时候,编译系统会自动调用转换构造函数,建立一个无名的临时对象(或临时变量). ( ...

  8. jQuery中:first,:first-child,first()的使用区别

    ul li:first  先获取页面中所有li节点对象数组,然后返回数组中的第一个li节点对象 . :first-child  选择器选取属于其父元素的第一个子元素的所有元素. first() 返回被 ...

  9. Promise 与 await 组合使用

    看例子就行了,废话不多说!   async function checkStatus(name){   return new Promise((resolve,reject) => {      ...

  10. Dynamic Route Matching Vue路由(1)

    Dynamic Route Matching 动态的 路由 匹配 Very often we will need to map routes with the given pattern to the ...