Flutter代码插桩,竟如此简单!

1,771 阅读1分钟
Respect给到贝壳、闲鱼、AspectJ.
相关github链接在文章最后[参考资料]

开门见山

先来说说如何配置,再概括实现原理,后续再看情况出原理解析。

添加配置,这里添加的是贝壳开源的beike_aspectd,项目不需支持空安全则把null-safety去掉

beike_aspectd:
  git:
    url: https://github.com/LianjiaTech/Beike_AspectD.git
    ref: null-safety/2.5.3

在与pubspec.yaml同级目录下添加aop_config.yaml配置文件文件内容

flutter_tools_hook:
  - project_name: 'beike_aspectd'
    exec_path: 'bin/starter.snapshot'

由于需要修改到引擎源码,因此需要到Flutter sdk下添加开源库的flutter_tools.patch补丁。 github连接inner/flutter_tools.patch下载下来,打入到Flutter sdk

#cd到flutter sdk 中 flutter_tools所在路径
MacBook-Pro-3:flutter_tools hbb$ pwd
/Users/hbb/lib/flutter/packages/flutter_tools

#打上补丁 /Users/hbb/AndroidStudioProject替换为你自己的项目路径
MacBook-Pro-3:flutter_tools hbb$ git apply /Users/hbb/AndroidStudioProjects/Beike_AspectD/inner/flutter_tools.patch 
#此时需要删除bin/cache/flutter_tools.stamp文件

# 重新build
MacBook-Pro-3:flutter_tools hbb$ flutter packages get
Building flutter tool...
Running "flutter pub get" in flutter_tools...                    1,382ms

编写get方法hook相关代码,创建aop_impl.dart。这里做演示,只演示hook方法。
更多用法请查看参考资料的源码链接中的README.md

import 'package:beike_aspectd/aspectd.dart';

@Aspect()
@pragma("vm:entry-point")
class CallDemo {
  @pragma("vm:entry-point")
  CallDemo();

//实例方法,我的项目名为channel_demo,@Call(文件名,类名,-方法名)
  @Call("package:channel_demo/main.dart", "_MyHomePageState", "-_incrementCounter")
  @pragma("vm:entry-point")
  void _incrementCounter4(PointCut pointcut) {
    print('[beike_aspectd]: call instance method2!');
    pointcut.proceed();
  }
}

在你自己项目的main.dartimport
添加ignore: unused_import避免被编译器tree shake优化掉。

// ignore: unused_import
import 'package:channel_demo/aop_impl.dart';

image.png

注:目前仅支持的Flutter版本为1.22.4 2.2.2 2.5.3 切换到对应版本的Flutter SDK即可

运行代码,以下打印代码Aop成功注入

image.png

最终运行效果

image.png

至此,结束

原理概括

这里借用aspectd的原理图

image.png

一句话概括:编译时替换产物

恩,好像可以为所欲为了~

参考资料

github.com/XianyuTech/…
github.com/LianjiaTech…