GDD谷歌开发者大会上的腾讯企鹅辅导
导语:很荣幸,腾讯企鹅辅导的Flutter实践收到谷歌开发者大会的邀请
腾讯企鹅辅导终端团队自年接入Flutter,上线核心页面,整体性能稳定,效果拔群。目前积累的经验包括:架构设计、页面栈管理、接入层SDK、性能优化、动态更新的能力等等。
这次很荣幸收到谷歌开发者大会的邀请,分享Flutter在腾讯企鹅辅导实践上的经验。Flutter分会场座无虚席,宣传视频中多次介绍腾讯企鹅辅导。我们在现场也和同行们进行了技术交流,共同进步。首先来分享一些现场的图片:
一.接入与实践(1)手机端腾讯企鹅辅导手机端iOS,Android设备Flutter上线包括上课tab下的上课任务页、作业/考试页、笔记页、学报告页等。
二级页面:
三级页面:
因为是Native+Flutter混合项目开发,如果Native整体迁移,改造工程量会非常大。因此我们对Flutter项目进行改造,将Flutter公共模块抽取出来,以SDK的方式分别供iOS和Android两端使用。
(2)Pad端腾讯企鹅辅导Pad端主体工程使用Flutter搭建,潜心学习,打磨精品,实现包括所有一级页面在内的70%的页面,目前已完成开发,预计9月底会上架应用市场。
不同于手机端,PadHD是一个新起的项目,整体以Flutter工程为外壳进行开发,效率会大大提升。
二.开源共享Flutter开发腾讯企鹅辅导手机端、Pad端,我们努力的打磨着精品。完成复杂页面的同时,我们搭建起混合工程接入层MJFlutter,页面栈、常用的基础组件Widgets,高级动画等。
(1)MJFlutterMJFlutter的目标是让业务更方便的接入Flutter,所以我们在设计上接口会尽量简单、易用,减少与底层的耦合性。同时,扩展能力上也会非常强大。主要包括三层:
上层通用UI,提高开发效率,包括refresh_listview,toast,dialog,slidingwindow等
数据通道层,主要对FlutterChannel进行封装,实现专用和通道通道,旨在实现一些核心能力,包括页面栈管理、网络请求、存储等
底层Native接入层,主要是复用Native能力,减少开发成本,包括目前实现的EduStorage、EduPush、Log等
(2)基础组件WidgetsFlutter作为开源项目,社区的活跃度非常高。我们在使用了一些Flutter的开源组件后,结合实际项目的应用,也希望对开源的社区做出一点贡献。
alert_util:弹框组件,提供showAleart()方法展示
loading_widgets:加载组件,提供show()方法展示
popup_window:弹框组件,提供上下左右四个方向的弹框动画,可以实现任意大小的组件PopUp,甚至是滑动窗口
refresh_listvew:刷新Listview,支持下拉刷新,下拉加载更多,以及自定义加载动画等
toast_util:toast组件,提供show()方法展示
sweper:轮播组件,支持多种风格的轮播展示
...
以上我们提到的接入层,基础组件等,我们将会在9月底陆续开源,欢迎大家多提出宝贵意见,一起共建共享。
三.开发经验GDD大会的视频分享中,我们有提到其他的跨平台框架内存的占用会比较高,而且Flutter页面非常稳定,很少会出现crash,那我们团队是如何处理?
(1)DebugOnException接入Flutter,我们发现页面出现异常时,App并不会crash,但可以正常操作。这里Flutter框架帮我们捕获了,实际上我们可以拿到这些信息,方便我们定位问题。
页面异常可能会出现红屏或者错误提示,但逻辑上的异常并不会提示错误信息。这些问题都是我们需要解决的,我们需要做的就是拿到这些信息,然后定义异常处理方法。
staticboolinProduction=bool.fromEnvironment("dart.vm.product")
FlutterError.onError()=(){_reportError}
void_reportError(){
invokeNative();
}
对于FlutterDebug包,我们进行弹窗提示,打印到日志中
对于FlutterRelease包,我们主动上报管理平台,方便定位用户问题
(2)内存优化内存优化可以分为内存泄漏和内存的增量优化。
泄漏问题一直是困扰我们的大问题,因为iOS混合项目中,Flutter页面退出,但占用的内存并不会被释放掉。
阅读源码,我们发现Flutter从1.0引入Engine后,内存引用就是一个大循环。
内存泄漏的主要原因在于FlutterEngine中定义的一些methodChannel、basicMethodChannel、plugin,这些channel是一种retain的关系。我们看下面的源码FlutterEngine持有methodChannel,methodChannel中又持有FlutterEngine。关键点在于methodChannel中真正对FlutterEngine释放放到了dealloc,但实际上methodChannel因为一直持有FlutterEngine,所以一直无法走到dealloc中,因此造成了循环引用。
//FlutterEngine
_lifecycleChannel.reset([[FlutterBasicMessageChannelalloc]
initWithName:
"flutter/lifecycle"binaryMessenger:self
codec:[FlutterStringCodecsharedInstance]]);
//FlutterMethodChannel
-(instancetype)initWithName:(NSString*)name
binaryMessenger:(NSObjectFlutterBinaryMessenger*)messenger
codec:(NSObjectFlutterMethodCodec*)codec{
self=[superinit];
NSAssert(self,
"Superinitcannotbenil");_name=[nameretain];
_messenger=[messengerretain];//主要的修改点_message=messager,不增加引用计数
_codec=[codecretain];
returnself;
}
-(void)dealloc{
[_namerelease];
[_messengerrelease];
[_codecrelease];
[superdealloc];
}
找到了FlutterEngine内存泄漏的主要原因,进行相应的修改,我们需要一个入口,释放FlutterEngine中持有的channel们,这里建议放到FlutterViewControllerdealloc中调用,释放Flutter占有的内存。
内存增量的问题也会是引起内存暴增的主要原因。我们发现页面中图片资源越多,内存往往越高;页面压栈,内存反而并不会降低。
针对这样的问题,我们的处理是:
低内存是主动调用GC
定制化图片cache,更新Flutter图片缓存策略
四.总结腾讯企鹅辅导终端团队从0到1,踩了很多坑,也积累了不少经验。除了以上提到的接入层,性能优化等,我们将会在下半年陆续分享在FlutterForWeb,动态更新的一些经验,欢迎大家交流分享。
最后,再次感谢GDD大会的邀请,感谢晓雨同学的帮助,感谢江哥的磨皮,感谢程哥的支持。
预览时标签不可点收录于话题#个上一篇下一篇转载请注明:http://www.mengdejiexix.com/lxgs/6927.html