应用场景
AspectD是一款闲鱼推出的开源的代码插桩工具。使用它需要hook flutter的sdk。因为它需要修改flutter的构建流程。flutter产物有一个从dart代码到app.dill再到kernel.bin的过程。
分析项目如何集成
我们先以官方的example为例来分析一下。
对于普通的flutter工程,你可能以为example是项目的入口,其实不是。aspectd因为要去做一些hook操作。修改了项目的入口,每次都会去找项目中是否有aspectd_impl目录,如果有的才会当做需要做代码插桩操作的aspectd项目,否则,人为是普通的项目。
我们看一下aspectd_impl的项目依赖关系。
name: aspectd_impl
description: A new Flutter package project.
version: 0.0.1
author:
homepage:
environment:
sdk: ">=2.3.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
aspectd:
path: ../
example:
path: ../example
看pubspec.yaml文件,可以发现这个入口项目依赖了aspectd自身的library,还有我们原始的example库。
aspectd和aspectd_impl有什么区别呢?
可以看到library中的transformer,里面涉及到对ast抽象语法树的一些操作。后续再做介绍。
aspectd_impl中只有两个类问文件。
aspectd_impl.dart:
import 'package:example/main.dart' as app;
// ignore: unused_import
import 'aop_impl.dart';
void main() => app.main();
一个入口类,指向了example工程中的main.dart中的main()入口方法。
另一个aop_impl.dart
import 'package:aspectd/aspectd.dart';
@Aspect()
@pragma("vm:entry-point")
class RegularCallDemo {
@pragma("vm:entry-point")
RegularCallDemo();
@Call("package:example/main.dart", "D", "+D")
@pragma("vm:entry-point")
static dynamic hookMethod(PointCut pointcut) {
print('[KWLM1]: Before D! named widget');
dynamic object = pointcut.proceed();
print('[KWLM1]: After D! named');
return object;
}
}
主要是注解,是我们需要注解处理的类。
这里添加的是Call操作,也就是方法调用。hook main.dart中的D类的构造函数。在其中调用前后插入print日志。当然这里还可以做一些其他的操作,例如记录类的调用,最后总体上统计每个类的调用次数。帮助逐渐下掉代码中使用少的模块和代码。