[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-9443":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":15,"stars30d":15,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":16,"rankGlobal":9,"rankLanguage":9,"license":17,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":20,"hasPages":18,"topics":21,"createdAt":9,"pushedAt":9,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":15,"starSnapshotCount":15,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},9443,"aspectd","XianyuTech\u002Faspectd","XianyuTech","AOP for Flutter(Dart)",null,"Dart",1111,122,30,25,0,54.27,"MIT License",false,"master",true,[],"2026-06-12 04:00:44","# AspectD\n\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSolido\u002Fawesome-flutter\">\n   \u003Cimg alt=\"Awesome Flutter\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FAwesome-Flutter-blue.svg?longCache=true&style=flat-square\" \u002F>\n\u003C\u002Fa>\n\nSalute to AspectJ.\n\nAspectD is an AOP(aspect oriented programming) framework for dart. Like other traditional aop framework,   AspectD provides call&execute grammar. Besides, as we can't use dart:mirrors in flutter, AspectD also provides a  way named inject enhancing the dart code manipulation.\n\nBesides, AspectD provides a dill transformer container above which developers can implement their own transformers like hook, json, mirrors, etc.\n\n# Design\n\n![Aspectd Diagram](https:\u002F\u002Fgw.alicdn.com\u002Fmt\u002FTB10SBIdgaH3KVjSZFjXXcFWpXa-865-771.png)\n\nSuppose you have a flutter project named example located in hf_dir.\n\n# Installation\n\n## 1. Create a dart package named aspectd_impl in hf_dir\u002Fexample\n\n```dart\nflutter create --template=package aspectd_impl\n```\n\n## 2. Add aspectd&example dependency to aspectd_impl package\n```dart\ndependencies:\n  flutter:\n    sdk: flutter\n  aspectd:\n    git:\n      url: git@github.com:XianyuTech\u002Faspectd.git\n      ref: stable\u002Fv2.2.3\n  example:\n    path: ..\u002Fexample\n```\nRemember to change the branch matching your flutter environment (stable supported currently).\nFetch package dependency in aspectd_impl package\n\n```dart\nflutter packages get\n```\n## 3. Modify aspectd_impl package\n\naspectd_impl.dart(entrypoint)\n```dart\nimport 'package:example\u002Fmain.dart' as app;\nimport 'aop_impl.dart';\n\nvoid main()=> app.main();\n```\naop_impl.dart(aop implementation)\n```dart\nimport 'package:aspectd\u002Faspectd.dart';\n\n@Aspect()\n@pragma(\"vm:entry-point\")\nclass ExecuteDemo {\n  @pragma(\"vm:entry-point\")\n  ExecuteDemo();\n\n  @Execute(\"package:example\u002Fmain.dart\", \"_MyHomePageState\", \"-_incrementCounter\")\n  @pragma(\"vm:entry-point\")\n  void _incrementCounter(PointCut pointcut) {\n    pointcut.proceed();\n    print('KWLM called!');\n  }\n}\n```\n## 4. Patch flutter_tools to apply aspectd.dart.snapshot\n```shell\ncd path-for-flutter-git-repo\ngit apply --3way path-for-aspectd-package\u002F0001-aspectd.patch\nrm bin\u002Fcache\u002Fflutter_tools.stamp\n```\nOn Windows, use \"git am --reject --whitespace=fix aspectd\\0001-aspectd.patch\" to apply the patch instead.\n\nAs flutter_tools doesn't support hooks now, the aspectd.patch is necessary currently. As flutter is evolving, this patch might fail sometimes. However, It would be simple to resolve the conflicts as AspectD only adds two hooks when building dill.  See https:\u002F\u002Fgithub.com\u002Falibaba-flutter\u002Faspectd\u002Fissues\u002F5 for more.\n\nIf you want to customize the aspectd_impl package, edit aspectdImplPackageRelPath(aspectd_impl package relative path to the example's pubspec.yaml) and aspectdImplPackageName(aspectd_impl package folder name and main entry file name) defined in path-for-flutter-git-repo\u002Fflutter\u002Fpackages\u002Fflutter_tools\u002Flib\u002Fsrc\u002Faspectd.dart. \n\n```dart\nconst String aspectdImplPackageRelPath = '..';\nconst String aspectdImplPackageName = 'aspectd_impl';\n```\n\nStep 1~3 are expected to run each time you want to add aspectd_impl to a flutter(dart) package. 4 is expected to run only once unless the dart-sdk changes. For example, If you upgrade flutter, you need to check if to re-run 4.\n\nIf you're using example with an aspectd_impl package not generated locally, remember to run `flutter packages get` in aspectd_impl package to get aspectd and check 4.\n\nIf the flutter version you want is not supported yet, see [UPGRADE.md](https:\u002F\u002Fgithub.com\u002Falibaba-flutter\u002Faspectd\u002Fblob\u002Fmaster\u002FUPGRADE.md) for more.\n\n# Tutorial\nNow AspectD provides three ways to do AOP programming.\n\n## call\nEvery callsites for a specific function would be manipulated.\n```dart\nimport 'package:aspectd\u002Faspectd.dart';\n\n@Aspect()\n@pragma(\"vm:entry-point\")\nclass CallDemo{\n  @Call(\"package:app\u002Fcalculator.dart\",\"Calculator\",\"-getCurTime\")\n  @pragma(\"vm:entry-point\")\n  Future\u003CString> getCurTime(PointCut pointcut) async{\n    print('Aspectd:KWLM02');\n    print('${pointcut.sourceInfos.toString()}');\n    Future\u003CString> result = pointcut.proceed();\n    String test = await result;\n    print('Aspectd:KWLM03');\n    print('${test}');\n    return result;\n  }\n\n  @Call(\"package:app\u002Fcalculator.dart\",\"Calculator\",\"+getCurTemporature\")\n  @pragma(\"vm:entry-point\")\n  String getCurTemporature(PointCut pointcut) {\n    print('Aspectd:KWLM04');\n    print('${pointcut.sourceInfos.toString()}');\n    try{\n      String res = pointcut.proceed();\n    } catch (error, trace){\n      print('Aspectd:KWLM05');\n    }\n    return null;\n  }\n\n  @Call(\"package:flutter\u002Fsrc\u002Fwidgets\u002Fbinding.dart\",\"\",\"+runApp\")\n  @pragma(\"vm:entry-point\")\n  static void runAppKWLM(PointCut pointcut){\n    print('Aspectd:KWLM07');\n    print('${pointcut.sourceInfos.toString()}');\n    pointcut.proceed();\n  }\n}\n```\n\nIn this case, notice that @Aspect() is needed to mark a class so that the aspectd will know that this class contains AspectD annotation informations. \n@pragma(\"vm:entry-point\") is needed so that the class\u002Ffunction will not be removed by tree-shaking.\nFor @Call(\"package:app\u002Fcalculator.dart\",\"Calculator\",\"-getCurTime\"), there are several things to know. Now call\u002Fexecute\u002Finject accept three positional parameters, package name, class name(If the procedure is a library method, this part is empty string), and function name. The function name may have a prefix('-' or '+'), '-' refers to instance method while '+' refers to library static method(like main) and class method. There is also a named parameter lineNum for inject so that AspectD know which line to inject a code snippet. The lineNum parameter is 1 based and code snippet would be injected before that line.\n\nBesides, when you want to manipulate a static method(including library method and class method), your aop method(runAppKWLM here) should also be declared static. This requirement also applies when using execute command.\n\n## execute\n\nEvery implementation for a specific function would be manipulated.\n```dart\nimport 'package:aspectd\u002Faspectd.dart';\n\n@Aspect()\n@pragma(\"vm:entry-point\")\nclass ExecuteDemo{\n  @Execute(\"package:app\u002Fcalculator.dart\",\"Calculator\",\"-getCurTime\")\n  @pragma(\"vm:entry-point\")\n  Future\u003CString> getCurTime(PointCut pointcut) async{\n    print('Aspectd:KWLM12');\n    print('${pointcut.sourceInfos.toString()}');\n    Future\u003CString> result = pointcut.proceed();\n    String test = await result;\n    print('Aspectd:KWLM13');\n    print('${test}');\n    return result;\n  }\n\n  @Execute(\"package:app\u002Fcalculator.dart\",\"Calculator\",\"+getCurTemporature\")\n  @pragma(\"vm:entry-point\")\n  String getCurTemporature(PointCut pointcut) {\n    print('Aspectd:KWLM14');\n    print('${pointcut.sourceInfos.toString()}');\n    try{\n      String res = pointcut.proceed();\n    } catch (error, trace){\n      print('Aspectd:KWLM15');\n    }\n    return null;\n  }\n\n  @Execute(\"package:flutter\u002Fsrc\u002Fwidgets\u002Fbinding.dart\",\"\",\"+runApp\")\n  @pragma(\"vm:entry-point\")\n  static void runAppKWLM(PointCut pointcut){\n    print('Aspectd:KWLM17');\n    print('${pointcut.sourceInfos.toString()}');\n    pointcut.proceed();\n  }\n}\n```\n\n## inject\nFor a original function like below:(package:flutter\u002Fsrc\u002Fwidgets\u002Fgesture_detector.dart)\n```dart\n  @override\n  Widget build(BuildContext context) {\n    final Map\u003CType, GestureRecognizerFactory> gestures = \u003CType, GestureRecognizerFactory>{};\n\n    if (onTapDown != null || onTapUp != null || onTap != null || onTapCancel != null) {\n      gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers\u003CTapGestureRecognizer>(\n        () => TapGestureRecognizer(debugOwner: this),\n        (TapGestureRecognizer instance) {\n          instance\n            ..onTapDown = onTapDown\n            ..onTapUp = onTapUp\n            ..onTap = onTap\n            ..onTapCancel = onTapCancel;\n        },\n      );\n    }\n...\n}\n```\n\n```dart\nimport 'package:aspectd\u002Faspectd.dart';\nimport 'package:flutter\u002Fservices.dart';\n\n@Aspect()\n@pragma(\"vm:entry-point\")\nclass InjectDemo{\n  @Inject(\"package:flutter\u002Fsrc\u002Fwidgets\u002Fgesture_detector.dart\",\"GestureDetector\",\"-build\", lineNum:452)\n  @pragma(\"vm:entry-point\")\n  static void onTapBuild() {\n    Object instance; \u002F\u002FAspectd Ignore\n    Object context; \u002F\u002FAspectd Ignore\n    print(instance);\n    print(context);\n    print('Aspectd:KWLM25');\n  }\n}\n```\n\nAfter that, the original build function will look like below:\n```dart\n  @override\n  Widget build(BuildContext context) {\n    final Map\u003CType, GestureRecognizerFactory> gestures = \u003CType, GestureRecognizerFactory>{};\n\n    if (onTapDown != null || onTapUp != null || onTap != null || onTapCancel != null) {\n      gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers\u003CTapGestureRecognizer>(\n        () => TapGestureRecognizer(debugOwner: this),\n        (TapGestureRecognizer instance) {\n          instance\n            ..onTapDown = onTapDown\n            ..onTapUp = onTapUp\n            ..onTap = onTap\n            ..onTapCancel = onTapCancel;\n        },\n    \tprint(instance);\n    \tprint(context);\n    \tprint('Aspectd:KWLM25');\n      );\n    }\n...\n}\n```\nNotice that `\u002F\u002FAspectd Ignore` part when using injection, we need to compile the aop package successfully so we need to declare the instance\u002Fcontext variable. However, when injecting to origin function (build in this case), variable declaration\n```dart\nObject instance; \u002F\u002FAspectd Ignore \nObject context; \u002F\u002FAspectd Ignore\n```\nwould be discarded to avoid overring the original one.\n\n# Debug\n\nRead [DEBUG.md](https:\u002F\u002Fgithub.com\u002FXianyuTech\u002Faspectd\u002Fblob\u002Fmaster\u002FDEBUG.md) for more.\n\n# Compatibility\n\nStable version >= 1.0, currently v2.2.2\n\n\n# Notice\nBecause of the dart compilation implementation, there are several points to pay attention to:\n1. package:aspectd_impl\u002Faspectd_impl.dart should contains the main entry for aspectd_impl package and contains a app.main call.\n2. Every aop implementation file should be imported by aspectd_impl.dart so that it will work in debug mode.\n3. @pragma(\"vm:entry-point\") is needed to mark class\u002Ffunction to avoid been trimmed by tree-shaking.\n4. inject might fail in some cases while call&execute are expected to be more stable.\n5. If you want to disable AspectD, remove the aspectd.dart.snapshot located in aspectd or change the name of aspectd_impl package, or remove the @Aspect() annotation. Anyone will be fine.\n6. If you want to hook an instance method, the hook class should declare a default constructor and mark it with @pragma(\"vm:entry-point\").\n\n# Contact\n\nIf you meet any problem when using AspectD, file a issue or contact me directly. \n\n[Contact Author](mailto:kang.wang1988@gmail.com)","AspectD 是一个为 Dart 和 Flutter 设计的面向切面编程（AOP）框架。它提供了一种在不使用 dart:mirrors 的情况下增强代码操作的方法，包括调用和执行语法，并且支持自定义转换器，如钩子、JSON 处理等。通过 AspectD，开发者可以轻松地在不修改原始业务逻辑的情况下添加横切关注点，例如日志记录、性能监控等功能。适用于需要对现有 Flutter 应用进行非侵入式扩展或维护的场景，尤其是在无法直接修改源码的情况下希望增加新功能或改进现有功能时。",2,"2026-06-11 03:22:40","top_language"]