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)MJFlutter

MJFlutter的目标是让业务更方便的接入Flutter,所以我们在设计上接口会尽量简单、易用,减少与底层的耦合性。同时,扩展能力上也会非常强大。主要包括三层:

上层通用UI,提高开发效率,包括refresh_listview,toast,dialog,slidingwindow等

数据通道层,主要对FlutterChannel进行封装,实现专用和通道通道,旨在实现一些核心能力,包括页面栈管理、网络请求、存储等

底层Native接入层,主要是复用Native能力,减少开发成本,包括目前实现的EduStorage、EduPush、Log等

(2)基础组件Widgets

Flutter作为开源项目,社区的活跃度非常高。我们在使用了一些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

  • 上一篇文章:
  • 下一篇文章:
  • 网站简介| 发布优势| 服务条款| 隐私保护| 广告合作| 网站地图| 版权申明

    当前时间: