Beike_AspectD
这是 AspectD 的一个分支。
Beike_AspectD 是一个用于 Dart 的 AOP 框架。AspectD 提供了 call/execute/inject 语法供开发者操作 Dart 代码。除此之外,Beike_AspectD 还提供了:
- ✅ 支持添加语法为类添加方法。
- ✅ 支持字段获取语法来拦截字段的读取操作。
- ✅ 支持 Flutter Web。
我们可以使用 Beike_AspectD 做什么?
Beike 在许多包中都使用了 Beike_AspectD。
- 事件跟踪。
- JSON 转 Model。
- 性能监控。
- Flutter 框架 Bug 修复。
安装
1. 应用 flutter_tools.patch。
cd path-for-flutter-tools-git-repo
git apply --3way path-for-beike_aspectd-package/inner/0001-aspectd.patch
rm ../../bin/cache/flutter_tools.stamp
下次构建项目时,flutter tools 会自动构建。
2. 将 Beike_AspectD 添加到你的 yaml 文件。
dependencies:
beike_aspectd:
path: ../
3. 将 aop_config.yaml 添加到你的 Flutter 项目。
在 Flutter 项目的根目录(与 pubspec.yaml 同级)下添加一个名为 aop_config.yaml 的文件。
你可以从 Beike_AspectD 的示例中复制该文件。
文件的内容如下:
flutter_tools_hook:
- project_name: 'beike_aspectd'
exec_path: 'bin/starter.snapshot'
Flutter_tools 会检查该文件以确定 Beike_AspectD 是否已启用。然后它会获取 starter.snapshot 来处理 dill 文件。
4. 编写你的 hook 文件并导入该文件。
hook_example.dart (AOP 实现)
import 'package:beike_aspectd/aspectd.dart';
@Aspect()
@pragma("vm:entry-point")
class CallDemo {
@pragma("vm:entry-point")
CallDemo();
//实例方法
@Call("package:example/main.dart", "_MyHomePageState",
"-_incrementCounter")
@pragma("vm:entry-point")
void _incrementCounter4(PointCut pointcut) {
print('call instance method2!');
pointcut.proceed();
}
}
由于 hook_example.dart 没有在你的项目中被使用,我们应该在项目中导入它,否则它会在编译时被 tree shaking 掉。
例如,我们可以在 main.dart 中导入该文件。
// ignore: unused_import
import 'package:example/hook_example.dart';
教程
除了 AspectD 提供的 3 种 AOP 编程方式(call/execute/inject)外,Beike_AspectD 还提供了 add/field get 操作。
add
向类添加方法,支持类名正则匹配,支持父类过滤。
@Add("package:.+\\.dart", ".*", isRegex: true)
@pragma("vm:entry-point")
dynamic getBasicInfo(PointCut pointCut) {
return pointCut?.sourceInfos ?? {};
}
上面的代码将 getBasicInfo() 方法添加到所有类中,你可以使用自己的正则表达式和 superCls 参数来过滤类。
我们可以使用以下代码调用该函数。
dynamic self = someinstance;
Map info = self.getBasicInfo(PointCut.pointCut());
field get
字段的每一个调用点都会被操作。
@pragma("vm:entry-point")
@FieldGet('package:example/main.dart', 'MyApp', 'field', false)
static String exchange2(PointCut pointCut) {
return 'Beike_Aspectd';
}
假设 MyApp 类有一个名为 field 的属性,通过使用上面的代码,当调用属性 field 时,它总是返回字符串 ‘Beike_Aspectd’。
兼容性
目前 Beike_Aspectd 支持 flutter 1.22.4 和 2.2.2。
问答
- 如何知道我的代码是否被成功 hook 了?
- 首先,你需要下载 dart-sdk 并检出到 flutter 的相应 revision。dart 的 revision 可以在 path_to_flutter/bin/cache/dart-sdk/revision 找到。
- 运行以下命令。
path_to_flutter/bin/cache/dart-sdk/bin/dart path_to_dart/pkg/vm/bin/dump_kernel.dart path_to_your_project/.dart_tool/flutter_build/***/app.dill output_path/out.dill.txt
- 打开 output_path/out.dill.txt 文件,检查你的代码是否被 hook 了。
联系方式
如果您有任何问题,请随时提交 issue。