Flutter aspectd(三)使用

@pragma('vm:entry-point')

在AOT编译中,如果没有被引用到的代码会丢弃掉,而AOP代码是不会被引用,需要使用该方式告诉编译器不要丢弃代码

PointCut

/// Object carrying callsite information and methods which can enable you to
/// call the original implementation.
@pragma('vm:entry-point')
class PointCut {
  /// PointCut default constructor.
  @pragma('vm:entry-point')
  PointCut(this.sourceInfos, this.target, this.function, this.stubKey,
      this.positionalParams, this.namedParams);

  /// Source infomation like file, linenum, etc for a call.
  final Map<dynamic, dynamic> sourceInfos;

  /// Target where a call is operating on, like x for x.foo().
  final Object target;

  /// Function name for a call, like foo for x.foo().
  final String function;

  /// Unique key which can help the proceed function to distinguish a
  /// mocked call.
  final String stubKey;

  /// Positional parameters for a call.
  final List<dynamic> positionalParams;

  /// Named parameters for a call.
  final Map<dynamic, dynamic> namedParams;

  /// Unified entrypoint to call a original method,
  /// the method body is generated dynamically when being transformed in
  /// compile time.
  @pragma('vm:entry-point')
  Object proceed() {
    return null;
  }
}

该对象中包含一些我们要调用或执行的代码的信息。包括源代码信息(如库名、文件名、行号等),方法调用对象,方法名,位置参数,命名参数等

proceed()是调用原始方法的入口点,pointcut.proceed()可实现对原始逻辑的调用。原始定义中的proceed方法体只是个空壳,其内容将会被在运行时动态生成

Aspect

/// Annotation indicating whether a class should be taken into consideration
/// when searching for aspectd implementations like AOP.
@pragma('vm:entry-point')
class Aspect {
  /// Aspect default constructor
  const factory Aspect() = Aspect._;

  @pragma('vm:entry-point')
  const Aspect._();
}

用来标记要进行AOP操作的类,方便AOP进行识别和提取,也可以起到开关的作用,如果希望禁掉此段AOP逻辑,移除@Aspect注解即可。

Call

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

  @Call("package:example/main.dart", "", "+appInit")
  @pragma("vm:entry-point")
  static dynamic appInit(PointCut pointcut) {
    print('[KWLM1]: Before appInit!');
    dynamic object = pointcut.proceed();
    print('[KWLM1]: After appInit!');
    return object;
  }

  @Call("package:example/main.dart", "MyApp", "+MyApp")
  @pragma("vm:entry-point")
  static dynamic myAppDefine(PointCut pointcut) {
    print('[KWLM2]: MyApp default constructor!');
    return pointcut.proceed();
  }

  @Call("package:example/main.dart", "MyHomePage", "+MyHomePage")
  @pragma("vm:entry-point")
  static dynamic myHomePage(PointCut pointcut) {
    dynamic obj = pointcut.proceed();
    print('[KWLM3]: MyHomePage named constructor!');
    return obj;
  }
}

@Call("package:example/main.dart", "MyApp", "+MyApp")中第一个参数表示的是包名,第二个参数是类名,第三个参数是方法名。其中方法名可以有一个前缀(-或+),-表示的是实例方法。而+表示的是静态方法或类方法

需要注意的是:写的aop方法的类型要和要注入的方法一致,即带有+的,方法前要有static。

Execute

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

  @Execute("package:example/main.dart", "_MyHomePageState", "-_incrementCounter")
  @pragma("vm:entry-point")
  dynamic _incrementCounter(PointCut pointcut) {
    dynamic obj = pointcut.proceed();
    print('[KWLM21]:${pointcut.sourceInfos}:${pointcut.target}:${pointcut.function}!');
    return obj;
  }

  @Execute("dart:math", "Random", "-next.*", isRegex: true)
  @pragma("vm:entry-point")
  static dynamic randomNext(PointCut pointcut) {
    dynamic obj = pointcut.proceed();
    print('[KWLM22]:randomNext!');
    return obj;
  }
}

Call和Execute的区别是插入代码的位置不同,call是插入到调用的地方,而Execute是插入到执行的地方。例如:在main方法中调用say方法,通过Call方式插入的代码会插入到main方法中,而通过Execute方式插入的代码会插入到say方法中。

Inject

@Aspect()
@pragma("vm:entry-point")
class InjectDemo{
 @Inject("package:example/main.dart","","+injectDemo", lineNum:27)
 @pragma("vm:entry-point")
 static void onInjectDemoHook1() {
   print('Aspectd:KWLM51');
 }

 @Inject("package:example/main.dart","C","+fc", lineNum:198)
 @pragma("vm:entry-point")
 static void onInjectDemoHook3() {
   print('Aspectd:KWLM52++++');
 }
}

inject就是往具体的行前插入代码。

如何使修改代码生效

对于不同位置的代码,修改后让其生效需要做的不同。分为example、aspect_impl、aspectd下的lib

example中的代码

当只修改了example中的代码时,可以直接运行就会生效

aspect_impl中的代码

当修改了aspect_impl中的代码时,需要分别在aspect_impl和example中执行flutter clean和flutter pub get之后才能生效。

aspectd下的lib下的代码

当修改了这下面的代码后,需要将flutter_frontend_server目录下的frontend_server.dart.snapshot文件删除掉,然后分别在aspect_impl和example中执行flutter clean和flutter pub get之后才能生效。

当更改flutter版本

需要重新执行如下:

git apply --3way path-for-aspectd-package/0001-aspectd.patch
rm bin/cache/flutter_tools.stamp

通过上一节分析我们知道,git apply之后,flutter源码中会新增aspectd.dart文件,该文件中会判断frontend_server.dart.snapshot是否存在,存在就使用,不存在就通过代码重新生成,所以当我们修改了lib下的代码后需要删掉frontend_server.dart.snapshot。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 下载flutter 源码 我这里使用的是1.22.2,用的是fvm管理的包 下载aspect源码 使用aspect...
    laomao_老毛阅读 1,111评论 1 3
  • 引导 在上一篇文章中,我们进行了apply patch文件,那么我们来看看apply的文件,具体做了哪些事情。可以...
    laomao_老毛阅读 618评论 0 2
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 123,975评论 2 7
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,030评论 0 4