Flutter是google近年来新推出的跨平台移动UI框架,可以在ios和Android系统上快速构建出高质量,体验较高的原生界面,同时Flutter还将会作为google新一代操作系统Fuchsia的Toolchain,这对Flutter的未来发展前景是一个强有力的支撑。写这篇文章时,中国 GDG 2018 刚刚落幕,Flutter团队在大会上发布了release之前的最后一个preview版本。扇贝移动团队近期也对Flutter如何应用到扇贝产品上做了一番探索和实践。

Hello Flutter

Flutter项目可以用同一套代码同时在ios和Android操作系统上运行,在此之前,市面上已经存在了很多跨平台解决方案,扇贝的移动产品上在跨平台开发上一直采用Webview加React Native的解决方案。

Webview的优缺点都非常明显,优势是可以完全用Web开发的技术栈去实现,app只需要提供webview组件承载即可,同时可以随时更新页面,动态性很高,并且这些页面可以完全交由web开发人员开发迭代,移动端不需要太关心,但是Webview的缺点又很多,渲染的性能一直被开发者诟病,内置的Chrome内核在国内的机型上也会有不兼容的情况发生。

React Native在活动页面和商品页面得到了使用,RN相对于Webview来说,性能和渲染效率都得到了不小的提升,它是将编写好的web界面利用JSCore转换成原生控件,同时配合动态更新系统可以发布新版本的RN包来实现动态更新界面,但是RN和系统的关联性较强,很多功能需要依赖系统特性开发,debug成本也相对比较高,移动端的同学也需要对RN有一些了解来配合前端开发。

因此我们将目光投向了Flutter。

Flutter的特点

  • Dart可以运行前编译(AOT),在开发flutter应用的时候布局文件会直接通过源码编写node tree,从而避免了大量的解析转译时间,使得Dart的效率比JS更高。
  • Dart语言同样支持JIT编译,因此flutter可以hot reload,为开发周期提速。
  • Dart没有锁的概念,可以做到对象回收和GC,Dart中的线程叫做isolates,因为不共享内存的原因,同时和js一样是单线程操作,所以不会出现抢占调度和锁死的问题。开发者控制线程的时候需要显式创建线程,最常用的是async和await。
  • Flutter用Dart语言开发,因为Flutter主要用来开发用户界面,Dart语言的特性适合了用户构建用户界面时的操作逻辑,没有像Android的xml文件和前端的html文件这样的单独布局文件,使得开发更简洁,预览更方便。
  • Flutter不再受限于native,自己开发了一套渲染逻辑,因此在未来的性能优化和跨平台相比RN优势会更加明显。

关于Flutter的具体使用可以前往官网学习 flutter.io

Flutter的依赖是在Pub仓库中管理,项目的依赖在根目录下的pubspec.yaml中进行配置,例如如下配置:

dependencies:flutter:sdk: flutterjson_annotation: ^1.0.0intl: ^0.15.7
复制代码

关于依赖的package版本可以有两种写法

  • packagename: ^version 引入某个版本的package
  • packagename: ‘>=version’ 引入某个版本之后的package,用来约束最低或最高版本

在pubspec.yaml文件中声明依赖之后需要执行package get命令,国内开发者可能需要科学上网才能拉下来依赖包,Flutter为国内开发者提供了本地化的网站和镜像。只需要简单配置即可。 using Flutter In China

技术预研

在对Flutter方案做技术预研的时候,我们罗列出了一些需要探索和解决的问题。

  • 重写界面的成本
  • Flutter和原生互相通信问题
  • 图片资源增加包体积
  • Flutter如何构建到现有项目

重写界面成本

既然开始选用Flutter作为预备跨平台方案,而且是Android和ios团队负责开发维护,就需要了解一下Flutter的学习和开发成本。

Dart是Flutter前期在对十几种语言进行调研之后最后选择的语言,它天然支持响应式编程,Dart2的升级是进一步优化客户端的开发,编写出的代码结构清晰,有一定程序设计基础的开发人员不需要经过系统的学习就可以上手进行Flutter开发。

Flutter提供了大量基于Android material design风格和ios Cupertino风格的控件,可以通过组合嵌套的方式构建界面,需要注意的是在Flutter里面属性也是控件的概念,例如Padding、Center、Align等。具体查看Widgets Catalog。

Flutter和原生互相通信

以Android为例,Dart调用Java代码可以通过MethodChannel来实现,Java调用dart则用EventChannel来实现。

因为需要用Flutter重写的页面有涉及到网络请求的问题,之前的Android项目里实现了一套完整的网络请求框架,封装了项目需要的一些附带请求信息和处理逻辑等,我们目前还不需要为Flutter项目单独实现一个完整网络请求框架,所以将网络请求通过dart调用java的方式在java层进行网络请求然后callback到flutter页面上,有因为网络请求是异步的,dart的async/await关键字可以提供异步支持。

MethodChannel

首先在dart代码中实例化MethodChannel对象,然后在需要调用java代码的时候调用invokeMethod方法。

static const methodChannel = const MethodChannel('com.shanbay.shared.data/method'); Future<ProfileModel> _getProfileJson() async {mProfileJson = await platform.invokeMethod("getProfileJson");if (mProfileJson != null) {setState(() {Map profileMap = json.decode(mProfileJson);mProfileData = new ProfileModel.fromJson(profileMap);});}}
复制代码

在java中注册MethodChannel,注意channel的名字需要相同。

private static final String METHOD_CHANNEL = "com.shanbay.shared.data/method";
private MethodChannel mMethodChannel;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GeneratedPluginRegistrant.registerWith(this);mMethodChannel = new MethodChannel(getFlutterView(), METHOD_CHANNEL);......
}
mMethodChannel.setMethodCallHandler(MethodChannel.MethodCallHandler() {@Overridepublic void onMethodCall(MethodCall call, final MethodChannel.Result result) {if(call.method.equals("getProfileJson"){//do somethingresult.success(json);}
}
复制代码

EventChannel

有时候在页面接收到了一个event事件要动态刷新或者修改页面,需要java调用dart。 在dart代码中实例化EventChannel对象

static const eventChannel = const EventChannel('com.shanbay.shared.data/event');
StreamSubscription _subscription = null;@overridevoid initState() {super.initState();//开启监听if (_subscription == null) {_subscription = eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);}}@overridevoid dispose() {super.dispose();//取消监听if (_subscription != null) {_subscription.cancel();}}void _onEvent(Object event) {setState(() {if (event.toString() == "refresh") {_getProfileJson();}});}void _onError(Object error) {setState(() {print(error);});}复制代码

在java代码中实例化相同一个EventChannel对象获得event实例用来调用dart。

private static final String EVENT_CHANNEL = "com.shanbay.shared.data/event";
private EventChannel mChannel;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GeneratedPluginRegistrant.registerWith(this);mChannel = new EventChannel(getFlutterView(), EVENT_CHANNEL);mChannel.setStreamHandler(new EventChannel.StreamHandler() {@Overridepublic void onListen(Object arguments, EventChannel.EventSink events) {mEvent = events;}@Overridepublic void onCancel(Object arguments) {}});
}onEvent(event) {mEvent.success("refresh");
}
复制代码

图片资源增加包体积

在我们现有的Android项目中往往只提供了xxhdpi分辨率的图片资源,这样做是为了减小apk包体积,让其他分辨率的手机通过设备自适应。Flutter对于图片资源需要提供1x、2x、3x三种分辨率格式,这样如果需要大量本地图片资源,会增加一定的包体积。

美团技术发表过一篇文章,他们针对flutter中需要复用的图片资源采取的方案是对移动app assets中的图片按屏幕密度缩放并且存放到本地,然后dart中调用本地图片。

这样的方案在启动Flutter页面之前就需要知道哪些图片需要被存储到本地,还要做一个图片缩放和存储的操作,我认为这样可能不能确保图片的准确性,同时需要Android和ios两端同时支持,写两份代码,并且还要针对不同的flutter页面记录一个资源文件到页面的映射表,成本有点过高,在我们团队内实现有些繁琐,而且我们要实践的页面只用到了少量的本地图片,占用体积也不是很大,针对这种情况,可以直接用官方的三种分辨率,保证了Android、ios的两端的同步。

Flutter如何构建到现有项目

这个版块我们计划是采用将flutter项目打包成aar到Android项目中集成的方式构建,其中踩到了一些坑,正在梳理,《Flutter在混合项目中的构建和集成》会详细说明。

在个人信息页的实践

这个是我们flutter项目结构,host是一个debug工程,可以直接编译运行,lib文件夹则是dart代码。

最后形成的个人信息页效果图如下:

总结

Flutter的控件目前只提供了md风格的基础组件,想要自定义控件相对于Android和ios来说还是有一些复杂度,但是Flutter团队通过原生渲染界面确实打破了原有的跨平台解决方案的思路,性能和效率的提升是显而易见的,相比RN来说具有很大的优势。

dart目前在Android Studio上还不能支持代码块折叠,同时格式化还要手动点击,没有快捷键,代码块折叠这一点对dart组合嵌套写界面来说实在是太有必要了,希望可以后续不断优化开发体验。

Flutter的引入无疑会增加包体积,preview2的发布,官方宣布release包体积将会再减小30%,一个空的release项目只需要4.7MB 的体积,对于现在流量吃到饱的情况,其实包体积压缩这个话题可以慢慢的弱化了,优化用户体验是最重要的。

Flutter在扇贝听力上的实践已经打出了release包等待发布,我们会逐渐完善Flutter项目,在更多跨平台场景上使用Flutter开发。

参考资料

1.Flutter 文档

2.Flutter Packages

3.Flutter原理与实践

Flutter探索与实践相关推荐

  1. 58同城 Flutter 混合开发探索与实践

    点击"开发者技术前线",选择"星标????" 在看|星标|留言,  真爱 导语 本文主要介绍将Flutter应用到已有Native项目中混合开发遇到的问题及解决 ...

  2. Flutter Web 在《一起漫部》的性能优化探索与实践

    一起漫部 是基于区块链技术创造的新型数字生活. 目录 前言 开发环境 渲染模式 首屏白屏 优化方案 启屏页优化 包体积优化 去除无用的icon 裁剪字体文件 deferred延迟加载 启用gzip压缩 ...

  3. FlutterWeb性能优化探索与实践

    点击"开发者技术前线",选择"星标" 让一部分开发者看到未来 来自:美团技术团队 美团外卖商家端基于 FlutterWeb 的技术探索已久,目前在多个业务中落地 ...

  4. 京东APP中Flutter探索及优化

    点击"开发者技术前线",选择"星标" 让一部分开发者先看到未来 前言 随着Flutter稳定版本逐步迭代更新,京东APP内部的Flutter业务也日益增多,Fl ...

  5. 得物App数据模拟平台的探索和实践

    导读 Mock是一个接口编辑模拟工具,可以快速手动或者基于YAPI创建Mock接口模拟数据调试,同时支持场景,场景组的快速切换,方便在开发期和测试阶段试验不同数据返回的UI功能逻辑. Mooncake ...

  6. mysql 集群实践_MySQL Cluster集群探索与实践

    MySQL集群是一种在无共享架构(SNA,Share Nothing Architecture)系统里应用内存数据库集群的技术.这种无共享的架构可以使得系统使用低廉的硬件获取高的可扩展性. MySQL ...

  7. 技术揭秘!百度搜索中台低代码的探索与实践

    导读:据Gartner调研,应用开发需求的市场增长至少超过IT交付能力的5倍,预计到2025年,70%的新应用开发将使用低代码技术.我们需要在需求迭代越来越高频.创新能力要求越来越高的背景下,探索如何 ...

  8. 深度学习在高德的探索与实践

    1.导读 驾车导航是数字地图的核心用户场景,用户在进行导航规划时,高德地图会提供给用户3条路线选择,由用户根据自身情况来决定按照哪条路线行驶. 同时各路线的ETA(estimated time of ...

  9. 京东网络开放之路——自研交换机探索与实践

    2019独角兽企业重金招聘Python工程师标准>>> 相比传统商业交换机,白盒交换机具有更好的开放性和灵活性,解决了运维管理方面的诸多痛点,随着SONiC的不断完善和白盒交换机市场 ...

最新文章

  1. java jackson json_使用Java和Jackson将Json序列化为通用结构而无...
  2. python路径文件api
  3. OpenCV SURF FLANN匹配单应性的实例(附完整代码)
  4. colab清理gpu缓存_安卓手机为什么会变卡?强制GPU渲染手机就能变流畅?你真的懂吗...
  5. command对象的获取 c#
  6. 【java】测试dubbo业务
  7. TCP/IP网络编程
  8. lstm预测单词_从零开始理解单词嵌入| LSTM模型|
  9. 如何快速生成100万不重复的8位随机编号?
  10. svm 10折交叉验证 matlab,怎么用10折交叉验证程序?
  11. MySQL数据库下.frm .MYD .MYI损坏恢复操作——筑梦之路
  12. mis系统的编写与设计
  13. cdr 表格自动填充文字_Cdr教程 用CorelDRAW绘制百事可乐标志Logo设计教程
  14. Hive文件存储格式(建表stored as 的五种类型)
  15. hdu多校第六场1005 (hdu6638) Snowy Smilel 线段树/区间最大和
  16. 学习必备的50条非常有趣且实用的Python一行代码,值得收藏
  17. App推广技巧之渠道免费资源
  18. CPU被挖矿,Redis竟是内鬼。
  19. 连续状态方程离散化与凸包表示形式
  20. swift版QQ音乐播放器(二)

热门文章

  1. Android 自定义属性时TypedArray的使用
  2. android Word 显示文档结构图
  3. Android 音频录制和播放问题
  4. 云际视界视频会议开创远程商务新模式
  5. pytorch实现L2和L1正则化regularization的方法
  6. JAVA 内存泄露详解(原因、例子及解决)
  7. python用random产生验证码,以及random的一些其他用法
  8. 【数据库】-基本特性
  9. JDBC获得数据库连接及使用
  10. 【2017-02-20】C#基础 - 运算符//表格,示例,代码巩固练习