内容简介:背景近年来,闲鱼旧业务在Flutter架构升级下,大量页面通过Flutter开发实现。业务不断迭代,包体积也随之增大,闲鱼Android、iOS安装包大小较去年有较大增加,其中,Flutter在闲鱼包体积中占比20%,闲鱼开发逐步需要考虑进行Flutter侧工程治理。Flutter官方也在为包大小不断努力,致力于降低打包产物的大小,但仍未有成熟方案。因此现阶段,我们可以考虑如何将无效代码下线。通过人工梳理的方式,依赖于开发人员的业务熟悉程度,难免疏漏。我们需要有准确的的线上代码覆盖率,作为数据依据,推动业务
背景
近年来,闲鱼旧业务在Flutter架构升级下,大量页面通过Flutter开发实现。业务不断迭代,包体积也随之增大,闲鱼Android、iOS安装包大小较去年有较大增加,其中,Flutter在闲鱼包体积中占比20%,闲鱼开发逐步需要考虑进行Flutter侧工程治理。Flutter官方也在为包大小不断努力,致力于降低打包产物的大小,但仍未有成熟方案。因此现阶段,我们可以考虑如何将无效代码下线。
通过人工梳理的方式,依赖于开发人员的业务熟悉程度,难免疏漏。我们需要有准确的的线上代码覆盖率,作为数据依据,推动业务进行行之有效的代码下线。
本文为您介绍,Flutter的线上代码覆盖率解决方案——FlutterCodeX。针对类级别编译时代码插粧,运行时后台数据聚合,进行数据采集上报,获得最终代码覆盖率数据,推动废弃业务下线,达到包体瘦身,对工程健康做长效监控与改善。
插桩方案 探索
在线上代码覆盖率的统计中,问题的难点主要在于,如何准确判断类,是否被调用过?一般人会马上可以想到,只需要在每个类初始化时,加入一段代码,标记该类已经被调用,最快的就是构建函数中添加,但成本极高,有没有自动化、无侵入的插桩方案呢?以下从iOS、Android、Flutter不同的插桩方案进行简单的对比。
iOS
iOS中,ObjC首次调用类初始化时,+initialize被执行,系统会自动标记已被调用,在 metaClass的 data的flags字段中的 1<<29 位的这个bit RW_INITIALIZED,就记录着类是否initialize。可以通过判断类是否被初始化,因此在运行时,找到合适的时机,遍历所有类,进行数据的聚合上传。
Android
Android中,Java语言可以不需要侵入原有代码,以添加静态代码块的形式添加插桩代码,buildscript增加编译插件,在编译时遍历所有类文件进行代码插入即可。
Flutter
Flutter与Android、IOS的方案均有一定差异,Dart没有 Java 的静态代码块,也没有类似ObjC的系统标记。在什么地方插桩,可以不侵入原有代码呢?
理论上,Dart Class初始化执行顺序为:
-
class variables initialize on declaration (no static)
-
initializer list
-
superclass’s constructor
-
main class’s constructor
改写构造函数会直接侵入原有代码,Dart构造函数的多样写法也增加了自动化插件的难度。因此改写构造器不是第一选择。根据初始化执行顺序,很快可以想到,是否可以增加新的类成员,初始化时调用插桩代码,以达到类初始化插桩的效果。例如
但在Dart中,针对拥有常量构建器的类,要求所有的成员均为final,成员初始化必须在第1第2阶段,或构造函数入参进行初始化,即使是extends、with也强制要求子类及Mixin所有的变量均为final。而Flutter中,Widget等常用组件,均使用常量构建函数,无法通过这种形式插桩。
注入代码的形式不可用!
还有其他办法吗?可不可以通过AOP的方式,hook住所有的类构建器呢?而闲鱼技术团队刚刚开源的AspectD,恰好可以解决这个问题。
AspectD是针对Dart的AOP编程框架,通过Transform实现dill变换以实现AOP,可以便捷地实现无侵入代码自由注入。
在Flutter v1.12.13下验证,针对常量构建器、无构建函数、命名为ClassName.identifier形式构建函数,均测试通过!AspectD代码如下:
AspectD原理不在此详细说明,有兴趣请移步https://github.com/alibaba-flutter/aspectd。
整体方案设计
FlutterCodeX线上代码覆盖率SDK,由编译时代码插桩插件、运行时数据采集模块组成。
-
代码插桩插件
编译时,通过build_runner,CodeXGenerator与CodeAstVisitor进行工程内所有类ast解析,遍历所有类构造函数,自动生成AspectD的PointCut Execute类文件,hook类构建函数,在构造函数执行完毕后,插桩标记类调用信息,同时还生成项目的完整类列表至构建产物。关键代码如下:
AspectD Execute如下图所示,类A拥有两个构造函数,生成两个AspectD AOP函数。
-
运行时数据采集模块
运行时,工程中每个类初始化后将会自动调用addCallTime方法,将类调用信息缓存,选择用户退出后台的时机,进行数据文件进行压缩上传,目前我们采用阿里云OSS文件上传。根据应用活跃用户数,设置采样率,命中至少5万用户UV。
-
数据汇总与产出
最后,线上运行一段时间后,我们将数据汇总,与打包构建产物中的完整类列表进行比对,即可获得线上代码覆盖率数据,推动业务进行行之有效的瘦身。
以简单Demo工程为例:
说在最后
目前,FlutterCodeX在闲鱼App即将上线,结合客户端Android、iOS代码覆盖率数据,有效地推动废弃业务下线,助力包体瘦身,对工程健康做长效监控与改善。
闲鱼技术团队不仅是阿里巴巴集团旗下闲置交易社区的创造者,更是移动与高并发大数据应用新技术的引导者与创新者。我们与 Google Flutter/Dart 小组密切合作,为社区贡献了多个高 star 的项目和大量 PR 。我们正在积极探索深度学习和视觉技术在互动、交易、社区场景的创新应用。闲鱼技术与集团中间件团队共同打造的 FaaS 平台每天支持数以千万级用户的高并发访问场景。
就是现在! 客户端/服务端java/架构/前端/质量 工程师 面向社会+校园招聘,base杭州阿里巴巴西溪园区,一起做有创想空间的社区产品、做深度顶级的开源项目,一起拓展技术边界成就极致!
*投喂简历给小闲鱼→ guicai.gxy@alibaba-inc.com
开源项目、峰会直击、关键洞察、深度解读
请认准 闲鱼技术
以上所述就是小编给大家介绍的《Flutter线上代码覆盖率解决方案——FlutterCodeX》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 如何利用 Xcode 实现线上代码覆盖率的检查
- 升级iPhone XS的理由多了一条:Face ID解锁速度比上代明显快
- iOS 覆盖率检测原理与增量代码测试覆盖率工具实现
- 聊聊前端代码覆盖率
- golang代码覆盖率
- 100%代码覆盖率的悲剧
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
圈圈教你玩USB
刘荣 / 2013-4 / 59.00元
通过U盘、USB鼠标、15SB键盘、USBMIDI键盘、USB转串口、自定义的USBHID设备和自定义的USB设备等几个具体的USB例子,一步步讲解USB设备及驱动程序和应用程序开发的详细过程和步骤。第9和10章介绍USBWDM驱动开发,并给出一个简单的USB驱动和USB上层过滤驱动的实例。第2版中新增4章内容,包括USB触摸屏设备、移植到AVR单片机和ARM微控制器上以及更多的USB设备的实现。......一起来看看 《圈圈教你玩USB》 这本书的介绍吧!