阅读 4110

Flutter dill操作,“为所欲为”?

自上次《Flutter全埋点实现与思考》发布后,收获了不少的阅读与点赞,非常感谢大家的支持,有些评论没及时回复非常抱歉,实在是年底了事情特别的多,而且进入了996的工作模式...

其中与一些同学交流过后比较不好理解的就是在对dill文件的操作这里,其实这里从思路上是非常好理解的,无非就是在编译期间,按照类似一种链式的流程,添加一个或多个transform,通过对dill文件的递归式AST遍历,实现对dill的变换来达到我们的目的。

我们横向对比其他语言实现,熟悉Java的同学知道,Java中的存在多个字节码的操作框架,操作的粒度各不相同,其中典型的就是ASM,从设计上来看,Dart中对AST的遍历与其基本类似,是典型的visit(访问者)模式,这个设计模式大家在实际生产项目中使用的可能非常少,但是对于dill与字节码操作来说非常的合适,它的最大的特点就是在不修改现有体系的情况下对系统的功能做拓展,将数据操作与数据表示隔离开。当然,了解思想与实际运用还是有一段路要走的,不过我猜测,这方面应该马上就要有更多资料补充了(狗头)。

而在Flutter中在编译期对dill进行操作,其中涉及到的关键在ast.dartbinary/ast_to_binary.dartbinary/ast_from_binary.darttext/ast_to_text.dart这几个文件,而其中我觉得ast.dart尤为重要,而这个文件内容有一万多行,语法节点多而复杂,且没有一个规范的官网文档或者资料对这方面的介绍,有种说法是"源码是最好的老师",不过我认为如果直接去通读源码效益其实并不高,况且绝大多数人都是普普通通的"打工人",每天为了写业务代码赶项目已经很不容易了,如果自己再去单独研究整理的话,估计得耗费不少的时间精力,我觉得如果有兴趣,可以带着实际中遇到问题带着目的去看对应的点就行,当然如果时间有多另当别论。另外一方面,从目前各种已经发布的在Flutter的动态化这方面的内容来看,基本也都包含着对AST的运用与处理,也侧面反映了这一块的内容还是非常的重要的。

根据dill转化操作的特点,大体可以分为:代码生成代码修改两大类,而其中代码修改又可以根据不同的应用,实现代码监控、代码分析等功能,简言之,"一千个人眼中就有一千个哈姆雷特",相信每个人总会发现不一样、有趣的用法。

在与部分同学沟通过后,现将项目中已经用到的关于dill操作的地方,参考Aspectdflutter tools的hook patch,挑选了几个在开发中非常经典实用的功能实现,对dill的操作中既有细粒度的实现对每个变量、表达式的操作,也有粗粒度的在代码某个地方插入其他方法的调用。先将代码开源出来,与大家交流使用:

Flutter Transform Dill

github地址:传送地址 (尴尬,竟然忘记贴上项目地址了...)

提供多个简单实用的注解供Flutter开发、调试,提高开发效率,也是学习dill操作的经典案例。

目前支持Flutter版本:v1.22.3/v1.22.4

使用方法:

  1. 直接将该项目作为本地库依赖

  2. flutter tools进行patch,在Flutter仓库目录下执行:git apply --3way [ft-dill-transform-patch.patch]路径

    • for Windows :

    • for Mac:

  3. 删除flutter/bin/cache/flutter_tools.stamp,执行flutter doctor -v

之所以是需要以上的步骤是因为Flutter本身没有提供对Flutter tools构建的hook接口,也没有开放其内部transform的流程,不过在flutter的官网issue中有提到这部分的讨论,我相信官方不久的将来也会支持这个功能,那个时候肯定也能以很低的成本将目前的dill转换功能迁移适配。

另外,接入的过程主要耗时估计在对Flutter版本的升级,以及对Dart sdk完整源码的依赖上,第一次最好在网络好的情况下进行。

目前实现的功能:

1.ClickShake注解,作用于方法:

实现Flutter防多次点击、防抖动功能。可自己设置有效间隔时间,默认间隔时间是200ms。

如果依赖了该库且执行了以上1-3步,那么默认情况下是支持所有通过GestureRecognizer实现的可点击的组件的,并且只会对其中的onTaponTapDownonDown这三个行为单击行为做防多次点击处理,不会影响其他点击行为。

GestureDetector(
  onTapDown:(_){
      print('onTapDown');//快速点击只会调用一次
  }
)
    
复制代码

另外,为了补充上述情况的其他行为操作(例如Listener、自定义的行为),提供ClickShake注解,能对特定的方法进行处理。

@ClickShake(intervalTime = 300)
testClick()async{
  print('testCost1');
}
复制代码

2.FunctionLog注解,作用于方法:

提供更简单的方式打印方法耗时,参数、返回值等。

@FunctionLog()
void _incrementCounter(String p1,int p2){
  //to do something...
}
//输出
//--> _incrementCounter(String p1 = xx int p2 = xx)
//<-- _incrementCounter cost time(耗时) = xx[ms]
复制代码

3.更多实现中(模块化的方法统计打印?代码生成支持支持获取修改私有属性?)...

因个人精力有限,如果你有好的想法或者期待实现的功能,又或者你能花费自己宝贵的时间提供更优秀的代码,请提交PR或者联系我,我看到会尽快处理,希望大家能一起发挥想象力,利用Dill Transform实现更多的功能!

如何调试验证:

如果你需要调试本项目的代码,又或者是想自己调试验证开发自己的transform是否正确,可通过以下两步骤:

  • start.dart中Debug start.dart,此处需要自行补充args参数
  • 生成的dill文件验证与否符合预期,在完整的Dart SDK目录下,进入pkg/vm/bin,通过命令dart dump_kernel.dart [已经生成的dill文件路径] [转化后的.txt文件]

在调试验证过程中,也可能会遇到一些莫名的问题,如果你仔细思考与实践后还无法解决,可在issue区讨论或者联系我:coderwangzi@163.com

注:暂时与Aspectd不能两者完全兼容,需要自己下载源码修改兼容。

Thanks Aspectd:github.com/alibaba-flu…

2020年马上就要结束了,后段时间应该会越发紧张,这篇文章算是给自己在掘金的2020画上一个句话了。希望读到这里的同学,不为已经过去的时间而懊悔,"与其感慨路难行,不如马上出发",在2021年,不管是事业上还是个人能力上,祝愿大家都能有质的飞跃!

文章分类
Android
文章标签