AOP for Flutter(Dart)

Related tags

Utilities aspectd
Overview

AspectD

Awesome Flutter

Salute to AspectJ.

AspectD 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.

Besides, AspectD provides a dill transformer container above which developers can implement their own transformers like hook, json, mirrors, etc.

Design

Aspectd Diagram

Suppose you have a flutter project named example located in hf_dir.

Installation

1. Create a dart package named aspectd_impl in hf_dir/example

flutter create --template=package aspectd_impl

2. Add aspectd&example dependency to aspectd_impl package

dependencies:
  flutter:
    sdk: flutter
  aspectd:
    git:
      url: git@github.com:alibaba-flutter/aspectd.git
      ref: stable/v2.0.0
  example:
    path: ../example

Remember to change the branch matching your flutter environment (stable supported currently). Fetch package dependency in aspectd_impl package

flutter packages get

3. Modify aspectd_impl package

aspectd_impl.dart(entrypoint)

import 'package:example/main.dart' as app;
import 'aop_impl.dart';

void main()=> app.main();

aop_impl.dart(aop implementation)

import 'package:aspectd/aspectd.dart';

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

  @Execute("package:example/main.dart", "_MyHomePageState", "-_incrementCounter")
  @pragma("vm:entry-point")
  void _incrementCounter(PointCut pointcut) {
    pointcut.proceed();
    print('KWLM called!');
  }
}

4. Patch flutter_tools to apply aspectd.dart.snapshot

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

On Windows, use "git am --reject --whitespace=fix aspectd\0001-aspectd.patch" to apply the patch instead.

As 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://github.com/alibaba-flutter/aspectd/issues/5 for more.

If 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/flutter/packages/flutter_tools/lib/src/aspectd.dart.

const String aspectdImplPackageRelPath = '..';
const String aspectdImplPackageName = 'aspectd_impl';

Step 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.

If 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.

If the flutter version you want is not supported yet, see UPGRADE.md for more.

Tutorial

Now AspectD provides three ways to do AOP programming.

call

Every callsites for a specific function would be manipulated.

import 'package:aspectd/aspectd.dart';

@Aspect()
@pragma("vm:entry-point")
class CallDemo{
  @Call("package:app/calculator.dart","Calculator","-getCurTime")
  @pragma("vm:entry-point")
  Future<String> getCurTime(PointCut pointcut) async{
    print('Aspectd:KWLM02');
    print('${pointcut.sourceInfos.toString()}');
    Future<String> result = pointcut.proceed();
    String test = await result;
    print('Aspectd:KWLM03');
    print('${test}');
    return result;
  }

  @Call("package:app/calculator.dart","Calculator","+getCurTemporature")
  @pragma("vm:entry-point")
  String getCurTemporature(PointCut pointcut) {
    print('Aspectd:KWLM04');
    print('${pointcut.sourceInfos.toString()}');
    try{
      String res = pointcut.proceed();
    } catch (error, trace){
      print('Aspectd:KWLM05');
    }
    return null;
  }

  @Call("package:flutter/src/widgets/binding.dart","","+runApp")
  @pragma("vm:entry-point")
  static void runAppKWLM(PointCut pointcut){
    print('Aspectd:KWLM07');
    print('${pointcut.sourceInfos.toString()}');
    pointcut.proceed();
  }
}

In this case, notice that @Aspect() is needed to mark a class so that the aspectd will know that this class contains AspectD annotation informations. @pragma("vm:entry-point") is needed so that the class/function will not be removed by tree-shaking. For @Call("package:app/calculator.dart","Calculator","-getCurTime"), there are several things to know. Now call/execute/inject 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.

Besides, 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.

execute

Every implementation for a specific function would be manipulated.

import 'package:aspectd/aspectd.dart';

@Aspect()
@pragma("vm:entry-point")
class ExecuteDemo{
  @Execute("package:app/calculator.dart","Calculator","-getCurTime")
  @pragma("vm:entry-point")
  Future<String> getCurTime(PointCut pointcut) async{
    print('Aspectd:KWLM12');
    print('${pointcut.sourceInfos.toString()}');
    Future<String> result = pointcut.proceed();
    String test = await result;
    print('Aspectd:KWLM13');
    print('${test}');
    return result;
  }

  @Execute("package:app/calculator.dart","Calculator","+getCurTemporature")
  @pragma("vm:entry-point")
  String getCurTemporature(PointCut pointcut) {
    print('Aspectd:KWLM14');
    print('${pointcut.sourceInfos.toString()}');
    try{
      String res = pointcut.proceed();
    } catch (error, trace){
      print('Aspectd:KWLM15');
    }
    return null;
  }

  @Execute("package:flutter/src/widgets/binding.dart","","+runApp")
  @pragma("vm:entry-point")
  static void runAppKWLM(PointCut pointcut){
    print('Aspectd:KWLM17');
    print('${pointcut.sourceInfos.toString()}');
    pointcut.proceed();
  }
}

inject

For a original function like below:(package:flutter/src/widgets/gesture_detector.dart)

  @override
  Widget build(BuildContext context) {
    final Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};

    if (onTapDown != null || onTapUp != null || onTap != null || onTapCancel != null) {
      gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
        () => TapGestureRecognizer(debugOwner: this),
        (TapGestureRecognizer instance) {
          instance
            ..onTapDown = onTapDown
            ..onTapUp = onTapUp
            ..onTap = onTap
            ..onTapCancel = onTapCancel;
        },
      );
    }
...
}
import 'package:aspectd/aspectd.dart';
import 'package:flutter/services.dart';

@Aspect()
@pragma("vm:entry-point")
class InjectDemo{
  @Inject("package:flutter/src/widgets/gesture_detector.dart","GestureDetector","-build", lineNum:452)
  @pragma("vm:entry-point")
  static void onTapBuild() {
    Object instance; //Aspectd Ignore
    Object context; //Aspectd Ignore
    print(instance);
    print(context);
    print('Aspectd:KWLM25');
  }
}

After that, the original build function will look like below:

  @override
  Widget build(BuildContext context) {
    final Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};

    if (onTapDown != null || onTapUp != null || onTap != null || onTapCancel != null) {
      gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
        () => TapGestureRecognizer(debugOwner: this),
        (TapGestureRecognizer instance) {
          instance
            ..onTapDown = onTapDown
            ..onTapUp = onTapUp
            ..onTap = onTap
            ..onTapCancel = onTapCancel;
        },
    	print(instance);
    	print(context);
    	print('Aspectd:KWLM25');
      );
    }
...
}

Notice that //Aspectd Ignore part when using injection, we need to compile the aop package successfully so we need to declare the instance/context variable. However, when injecting to origin function (build in this case), variable declaration

Object instance; //Aspectd Ignore 
Object context; //Aspectd Ignore

would be discarded to avoid overring the original one.

Compatibility

Stable version >= 1.0, currently v2.0.0

Notice

Because of the dart compilation implementation, there are several points to pay attention to:

  1. package:aspectd_impl/aspectd_impl.dart should contains the main entry for aspectd_impl package and contains a app.main call.
  2. Every aop implementation file should be imported by aspectd_impl.dart so that it will work in debug mode.
  3. @pragma("vm:entry-point") is needed to mark class/function to avoid been trimmed by tree-shaking.
  4. inject might fail in some cases while call&execute are expected to be more stable.
  5. 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.
  6. If you want to hook an instance method, the hook class should declare a default constructor and mark it with @pragma("vm:entry-point").

Contact

If you meet any problem when using AspectD, file a issue or contact me directly.

Contact Author

Comments
  • kernel 0.3.29 from git git@github.com:alibaba-flutter/sdk.git at eb9d9e in pkg/kernel

    kernel 0.3.29 from git [email protected]:alibaba-flutter/sdk.git at eb9d9e in pkg/kernel

    您好 请问我在aspectd 目录下 flutter packages get 之后 出现这个错误

    Target kernel_snapshot failed: FileSystemException: Cannot open file, path = '/Users/quyanhui/Documents/aspectd/aspectd_impl/.packages' (OS Error: No such file or directory, errno = 2) build failed. Command PhaseScriptExecution failed with a nonzero exit code note: Using new build system note: Building targets in parallel note: Planning build note: Constructing build description

    opened by robin0822 7
  •  flutter build apk 出错 运行example时没效果

    flutter build apk 出错 运行example时没效果

    Git error. Command: git fetch
    fatal: not a git repository (or any of the parent directories): .git
    Git error. Command: git fetch
    fatal: not a git repository (or any of the parent directories): .git
    Git error. Command: git fetch
    fatal: not a git repository (or any of the parent directories): .git
    Git error. Command: git fetch
    fatal: not a git repository (or any of the parent directories): .git

    opened by ckdgit 7
  • 跑了example工程中的例子 没有效果

    跑了example工程中的例子 没有效果

    [✓] Flutter (Channel master, v1.8.5-pre.77, on Mac OS X 10.14 18A391, locale zh-Hans-CN) • Flutter version 1.8.5-pre.77 at /Users/hb/development/flutter • Framework revision 8e5fb8c35d (3 hours ago), 2019-08-07 22:29:24 -0400 • Engine revision f200ee13aa • Dart version 2.5.0 (build 2.5.0-dev.1.0 f29f41f1a5)

    flutter git 目录执行过 git apply --3way path-for-aspectd-package/0001-aspectd.patch rm bin/cache/flutter_tools.stamp

    操作

    opened by Knight-ZXW 5
  • Inject 如何使用?

    Inject 如何使用?

    Hi All,

    我想在如下的一个方法中插入一段代码,如代码中注释所示

    void _handleTabControllerTick() {
        if (_controller.index != _currentIndex) {
          _currentIndex = _controller.index;
         //想要在这个位置插入一段代码
          if (widget.isScrollable)
            _scrollToCurrentIndex();
        }
        setState(() {
          // Rebuild the tabs after a (potentially animated) index change
          // has completed.
        });
      }
    

    因为这里的 _controller 和 _currentIndex 是 private 的,所以我想使用 Inject,在使用的时候发现必须要设置 lineNum,否则就会出错,因为 hook 的代码在未来可能会发生变化,现在有如下问题:

    1. 不使用 lineNum 是否可行?
    2. 有没有其他方式来做这个功能?
    3. 如何能拿到 _controller 和 _currentIndex,因为如果能拿到这两个值,我就可以判断是否需要进行 hook
    opened by GvcZhang 4
  • 配置协助~

    配置协助~

    我把库下载到了本地 但是跑不起来

    image

    想问一下pubspec.yaml里面的以来地址可以改成 https://github.com/alibaba-flutter/sdk.git 吗

    不知道为啥 不管用https还是ssh都好慢 flutter pub get 一直卡住....... 有没有什么好办法

    image

    opened by ConnyYue 4
  • 类的构造函数中包含widget参数,编译报错,求大佬帮忙看下

    类的构造函数中包含widget参数,编译报错,求大佬帮忙看下

    发现只要有类的无名构造函数中含有widget就无法编译通过。比如下面D类,在调用的时候有给widget传值,编译就会报错,把widget赋值给去掉,就可以正常插入代码,并成功打印。

    截屏2020-12-25 上午12 19 45 截屏2020-12-25 上午12 21 37

    Unhandled exception: Crash when compiling null, at character offset null: NoSuchMethodError: The getter 'line' was called on null. Receiver: null Tried calling: line #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5) #1 _WidgetCallSiteTransformer._constructLocation (package:kernel/transformations/track_widget_constructor_locations.dart:164:59) #2 _WidgetCallSiteTransformer._computeLocation (package:kernel/transformations/track_widget_constructor_locations.dart:272:30) #3 _WidgetCallSiteTransformer._addLocationArgument (package:kernel/transformations/track_widget_constructor_locations.dart:223:7) #4 _WidgetCallSiteTransformer.visitConstructorInvocation (package:kernel/transformations/track_widget_constructor_locations.dart:238:5) #5 ConstructorInvocation.accept (package:kernel/ast.dart:4204:44) #6 MapEntry.transformChildren (package:kernel/ast.dart:5504:21) #7 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #8 TreeVisitor.visitMapEntry (package:kernel/visitor.dart:265:37) #9 MapEntry.accept (package:kernel/ast.dart:5491:38) #10 transformList (package:kernel/ast.dart:9699:27) #11 MapLiteral.transformChildren (package:kernel/ast.dart:5454:5) #12 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #13 TreeVisitor.defaultExpression (package:kernel/visitor.dart:144:43) #14 TreeVisitor.visitMapLiteral (package:kernel/visitor.dart:186:41) #15 MapLiteral.accept (package:kernel/ast.dart:5441:44) #16 transformList (package:kernel/ast.dart:9699:27) #17 Arguments.transformChildren (package:kernel/ast.dart:3813:5) #18 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #19 TreeVisitor.visitArguments (package:kernel/visitor.dart:261:39) #20 Arguments.accept (package:kernel/ast.dart:3803:38) #21 ConstructorInvocation.transformChildren (package:kernel/ast.dart:4215:29) #22 _WidgetCallSiteTransformer.visitConstructorInvocation (package:kernel/transformations/track_widget_constructor_locations.dart:230:10) #23 ConstructorInvocation.accept (package:kernel/ast.dart:4204:44) #24 transformList (package:kernel/ast.dart:9699:27) #25 Arguments.transformChildren (package:kernel/ast.dart:3813:5) #26 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #27 TreeVisitor.visitArguments (package:kernel/visitor.dart:261:39) #28 Arguments.accept (package:kernel/ast.dart:3803:38) #29 StaticInvocation.transformChildren (package:kernel/ast.dart:4149:29) #30 _WidgetCallSiteTransformer.visitStaticInvocation (package:kernel/transformations/track_widget_constructor_locations.dart:202:10) #31 StaticInvocation.accept (package:kernel/ast.dart:4138:44) #32 VariableDeclaration.transformChildren (package:kernel/ast.dart:7001:33) #33 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #34 TreeVisitor.defaultStatement (package:kernel/visitor.dart:203:41) #35 TreeVisitor.visitVariableDeclaration (package:kernel/visitor.dart:225:7) #36 VariableDeclaration.accept (package:kernel/ast.dart:6987:43) #37 transformList (package:kernel/ast.dart:9699:27) #38 Block.transformChildren (package:kernel/ast.dart:5881:5) #39 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #40 TreeVisitor.defaultStatement (package:kernel/visitor.dart:203:41) #41 TreeVisitor.visitBlock (package:kernel/visitor.dart:206:31) #42 Block.accept (package:kernel/ast.dart:5873:43) #43 FunctionNode.transformChildren (package:kernel/ast.dart:2948:19) #44 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #45 TreeVisitor.visitFunctionNode (package:kernel/visitor.dart:260:45) #46 FunctionNode.accept (package:kernel/ast.dart:2932:38) #47 Procedure.transformChildren (package:kernel/ast.dart:2436:27) #48 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #49 _WidgetCallSiteTransformer.visitProcedure (package:kernel/transformations/track_widget_constructor_locations.dart:193:12) #50 Procedure.accept (package:kernel/ast.dart:2423:40) #51 transformList (package:kernel/ast.dart:9699:27) #52 Library.transformChildren (package:kernel/ast.dart:627:5) #53 WidgetCreatorTracker.transform (package:kernel/transformations/track_widget_constructor_locations.dart:504:15) #54 FlutterTarget.performPreConstantEvaluationTransformations (package:vm/target/flutter.dart:82:22) #55 KernelTarget.runBuildTransformations (package:front_end/src/fasta/kernel/kernel_target.dart:1093:19) #56 KernelTarget.buildComponent. (package:front_end/src/fasta/kernel/kernel_target.dart:390:7) #57 KernelTarget.buildComponent. (package:front_end/src/fasta/kernel/kernel_target.dart) #58 withCrashReporting (package:front_end/src/fasta/crash.dart:122:24) #59 KernelTarget.buildComponent (package:front_end/src/fasta/kernel/kernel_target.dart:380:12) #60 generateKernelInternal. (package:front_end/src/kernel_generator_impl.dart:177:38) #61 generateKernelInternal. (package:front_end/src/kernel_generator_impl.dart) #62 withCrashReporting (package:front_end/src/fasta/crash.dart:122:24) #63 generateKernelInternal (package:front_end/src/kernel_generator_impl.dart:73:10) #64 kernelForProgramInternal. (package:front_end/src/api_prototype/kernel_generator.dart:61:35) #65 CompilerContext.runWithOptions. (package:front_end/src/fasta/compiler_context.dart:135:20) #66 CompilerContext.runWithOptions. (package:front_end/src/fasta/compiler_context.dart) #67 CompilerContext.runInContext.. (package:front_end/src/fasta/compiler_context.dart:123:46) #68 new Future.sync (dart:async/future.dart:223:31) #69 CompilerContext.runInContext. (package:front_end/src/fasta/compiler_context.dart:123:19) #70 _rootRun (dart:async/zone.dart:1190:13) #71 _CustomZone.run (dart:async/zone.dart:1093:19) #72 _runZoned (dart:async/zone.dart:1630:10) #73 runZoned (dart:async/zone.dart:1550:10) #74 CompilerContext.runInContext (package:front_end/src/fasta/compiler_context.dart:122:12) #75 CompilerContext.runWithOptions (package:front_end/src/fasta/compiler_context.dart:133:10) #76 kernelForProgramInternal (package:front_end/src/api_prototype/kernel_generator.dart:60:32) #77 kernelForProgram (package:front_end/src/api_prototype/kernel_generator.dart:52:17) #78 compileToKernel (package:vm/kernel_front_end.dart:381:28) #79 FrontendCompiler.compile. (package:frontend_server/frontend_server.dart:542:54) #80 new Future. (dart:async/future.dart:175:37) #81 _rootRun (dart:async/zone.dart:1182:47) #82 _CustomZone.run (dart:async/zone.dart:1093:19) #83 _CustomZone.runGuarded (dart:async/zone.dart:997:7) #84 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1037:23) #85 _rootRun (dart:async/zone.dart:1190:13) #86 _CustomZone.run (dart:async/zone.dart:1093:19) #87 _CustomZone.bindCallback. (dart:async/zone.dart:1021:23) #88 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15) #89 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:397:19) #90 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:428:5) #91 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)

    #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5) #1 _WidgetCallSiteTransformer._constructLocation (package:kernel/transformations/track_widget_constructor_locations.dart:164:59) #2 _WidgetCallSiteTransformer._computeLocation (package:kernel/transformations/track_widget_constructor_locations.dart:272:30) #3 _WidgetCallSiteTransformer._addLocationArgument (package:kernel/transformations/track_widget_constructor_locations.dart:223:7) #4 _WidgetCallSiteTransformer.visitConstructorInvocation (package:kernel/transformations/track_widget_constructor_locations.dart:238:5) #5 ConstructorInvocation.accept (package:kernel/ast.dart:4204:44) #6 MapEntry.transformChildren (package:kernel/ast.dart:5504:21) #7 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #8 TreeVisitor.visitMapEntry (package:kernel/visitor.dart:265:37) #9 MapEntry.accept (package:kernel/ast.dart:5491:38) #10 transformList (package:kernel/ast.dart:9699:27) #11 MapLiteral.transformChildren (package:kernel/ast.dart:5454:5) #12 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #13 TreeVisitor.defaultExpression (package:kernel/visitor.dart:144:43) #14 TreeVisitor.visitMapLiteral (package:kernel/visitor.dart:186:41) #15 MapLiteral.accept (package:kernel/ast.dart:5441:44) #16 transformList (package:kernel/ast.dart:9699:27) #17 Arguments.transformChildren (package:kernel/ast.dart:3813:5) #18 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #19 TreeVisitor.visitArguments (package:kernel/visitor.dart:261:39) #20 Arguments.accept (package:kernel/ast.dart:3803:38) #21 ConstructorInvocation.transformChildren (package:kernel/ast.dart:4215:29) #22 _WidgetCallSiteTransformer.visitConstructorInvocation (package:kernel/transformations/track_widget_constructor_locations.dart:230:10) #23 ConstructorInvocation.accept (package:kernel/ast.dart:4204:44) #24 transformList (package:kernel/ast.dart:9699:27) #25 Arguments.transformChildren (package:kernel/ast.dart:3813:5) #26 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #27 TreeVisitor.visitArguments (package:kernel/visitor.dart:261:39) #28 Arguments.accept (package:kernel/ast.dart:3803:38) #29 StaticInvocation.transformChildren (package:kernel/ast.dart:4149:29) #30 _WidgetCallSiteTransformer.visitStaticInvocation (package:kernel/transformations/track_widget_constructor_locations.dart:202:10) #31 StaticInvocation.accept (package:kernel/ast.dart:4138:44) #32 VariableDeclaration.transformChildren (package:kernel/ast.dart:7001:33) #33 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #34 TreeVisitor.defaultStatement (package:kernel/visitor.dart:203:41) #35 TreeVisitor.visitVariableDeclaration (package:kernel/visitor.dart:225:7) #36 VariableDeclaration.accept (package:kernel/ast.dart:6987:43) #37 transformList (package:kernel/ast.dart:9699:27) #38 Block.transformChildren (package:kernel/ast.dart:5881:5) #39 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #40 TreeVisitor.defaultStatement (package:kernel/visitor.dart:203:41) #41 TreeVisitor.visitBlock (package:kernel/visitor.dart:206:31) #42 Block.accept (package:kernel/ast.dart:5873:43) #43 FunctionNode.transformChildren (package:kernel/ast.dart:2948:19) #44 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #45 TreeVisitor.visitFunctionNode (package:kernel/visitor.dart:260:45) #46 FunctionNode.accept (package:kernel/ast.dart:2932:38) #47 Procedure.transformChildren (package:kernel/ast.dart:2436:27) #48 Transformer.defaultTreeNode (package:kernel/visitor.dart:653:10) #49 _WidgetCallSiteTransformer.visitProcedure (package:kernel/transformations/track_widget_constructor_locations.dart:193:12) #50 Procedure.accept (package:kernel/ast.dart:2423:40) #51 transformList (package:kernel/ast.dart:9699:27) #52 Library.transformChildren (package:kernel/ast.dart:627:5) #53 WidgetCreatorTracker.transform (package:kernel/transformations/track_widget_constructor_locations.dart:504:15) #54 FlutterTarget.performPreConstantEvaluationTransformations (package:vm/target/flutter.dart:82:22) #55 KernelTarget.runBuildTransformations (package:front_end/src/fasta/kernel/kernel_target.dart:1093:19) #56 KernelTarget.buildComponent. (package:front_end/src/fasta/kernel/kernel_target.dart:390:7) #57 KernelTarget.buildComponent. (package:front_end/src/fasta/kernel/kernel_target.dart) #58 withCrashReporting (package:front_end/src/fasta/crash.dart:122:24) #59 KernelTarget.buildComponent (package:front_end/src/fasta/kernel/kernel_target.dart:380:12) #60 generateKernelInternal. (package:front_end/src/kernel_generator_impl.dart:177:38) #61 generateKernelInternal. (package:front_end/src/kernel_generator_impl.dart) #62 withCrashReporting (package:front_end/src/fasta/crash.dart:122:24) #63 generateKernelInternal (package:front_end/src/kernel_generator_impl.dart:73:10) #64 kernelForProgramInternal. (package:front_end/src/api_prototype/kernel_generator.dart:61:35) #65 CompilerContext.runWithOptions. (package:front_end/src/fasta/compiler_context.dart:135:20) #66 CompilerContext.runWithOptions. (package:front_end/src/fasta/compiler_context.dart) #67 CompilerContext.runInContext.. (package:front_end/src/fasta/compiler_context.dart:123:46) #68 new Future.sync (dart:async/future.dart:223:31) #69 CompilerContext.runInContext. (package:front_end/src/fasta/compiler_context.dart:123:19) #70 _rootRun (dart:async/zone.dart:1190:13) #71 _CustomZone.run (dart:async/zone.dart:1093:19) #72 _runZoned (dart:async/zone.dart:1630:10) #73 runZoned (dart:async/zone.dart:1550:10) #74 CompilerContext.runInContext (package:front_end/src/fasta/compiler_context.dart:122:12) #75 CompilerContext.runWithOptions (package:front_end/src/fasta/compiler_context.dart:133:10) #76 kernelForProgramInternal (package:front_end/src/api_prototype/kernel_generator.dart:60:32) #77 kernelForProgram (package:front_end/src/api_prototype/kernel_generator.dart:52:17) #78 compileToKernel (package:vm/kernel_front_end.dart:381:28) #79 FrontendCompiler.compile. (package:frontend_server/frontend_server.dart:542:54) #80 new Future. (dart:async/future.dart:175:37) #81 _rootRun (dart:async/zone.dart:1182:47) #82 _CustomZone.run (dart:async/zone.dart:1093:19) #83 _CustomZone.runGuarded (dart:async/zone.dart:997:7) #84 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1037:23) #85 _rootRun (dart:async/zone.dart:1190:13) #86 _CustomZone.run (dart:async/zone.dart:1093:19) #87 _CustomZone.bindCallback. (dart:async/zone.dart:1021:23) #88 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15) #89 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:397:19) #90 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:428:5) #91 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)

    Oops; flutter has exited unexpectedly: "FileSystemException: Cannot open file, path = 'build/flutter_assets/.last_build_id' (OS Error: No such file or directory, errno = 2)".

    A crash report has been written to /Users/local-admin/Documents/code2/aspectd/aspectd_impl/flutter_01.log. This crash may already be reported. Check GitHub for similar crashes. https://github.com/flutter/flutter/issues?q=is%3Aissue+FileSystemException%3A+Cannot+open+file%2C+path+%3D+%27build%2Fflutter_assets%2F.last_build_id%27+%28OS+Error%3A+No+such+file+or+directory%2C+errno+%3D+2%29

    To report your crash to the Flutter team, first read the guide to filing a bug. https://flutter.dev/docs/resources/bug-reports

    Create a new GitHub issue by pasting this link into your browser and completing the issue template. Thank you! https://git.io/JLXS0

    flutter doctor 信息:

    Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel unknown, 1.22.4, on macOS 11.1 20C69 darwin-x64, locale zh-Hans-CN) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1) [✓] Xcode - develop for iOS and macOS (Xcode 12.3) [✓] Chrome - develop for the web [✓] Android Studio (version 4.0) [✓] VS Code (version 1.52.1) [✓] Connected device (3 available)

    • No issues found!

    opened by ameryzhu 4
  • Fix build release

    Fix build release

    关于release下问题:

    因为release 下是aot模式,会进行全局的静态分析(TFA),代码逻辑在:

    //kernel_front_end.dart
    Future<KernelCompilationResults> compileToKernel(
        Uri source, CompilerOptions options,
        {bool includePlatform: false,
        bool aot: false,
        bool useGlobalTypeFlowAnalysis: false,
        Map<String, String> environmentDefines,
        bool enableAsserts: true,
        bool genBytecode: false,
        BytecodeOptions bytecodeOptions,
        bool dropAST: false,
        bool useProtobufTreeShaker: false,
        bool useProtobufTreeShakerV2: false,
        bool minimalKernel: false,
        bool treeShakeWriteOnlyFields: false,
        String fromDillFile: null}) async {
         ...
           // Run global transformations only if component is correct.
           //debug下不执行,release下aot为true会执行
      if ((aot || minimalKernel) && component != null) {
        await runGlobalTransformations(
            options.target,
            component,
            useGlobalTypeFlowAnalysis,
            enableAsserts,
            useProtobufTreeShaker,
            useProtobufTreeShakerV2,
            errorDetector,
            minimalKernel: minimalKernel,
            treeShakeWriteOnlyFields: treeShakeWriteOnlyFields);
            ...
      }
         ...
    
    }
    

    比如,执行flutter build apk命令,报错堆栈如下:

    Invalid argument(s): Iterables do not have same length.                 
    #0      MapBase._fillMapWithIterables (dart:collection/maps.dart:92:7)  
    #1      new LinkedHashMap.fromIterables (dart:collection/linked_hash_map.dart:127:13)
    #2      Substitution.fromPairs (package:kernel/type_algebra.dart:242:13)
    #3      DirectMethodInvocation.getStaticType (package:kernel/ast.dart:3542:25)
    #4      SummaryCollector._staticDartType (package:vm/transformations/type_flow/summary_collector.dart:1173:12)
    #5      SummaryCollector._staticType (package:vm/transformations/type_flow/summary_collector.dart:1176:36)
    #6      SummaryCollector._makeCall (package:vm/transformations/type_flow/summary_collector.dart:1080:26)
    #7      SummaryCollector.visitDirectMethodInvocation (package:vm/transformations/type_flow/summary_collector.dart:1519:12)
    #8      DirectMethodInvocation.accept (package:kernel/ast.dart:3528:44) 
    #9      SummaryCollector._visit (package:vm/transformations/type_flow/summary_collector.dart:853:42)
    #10     SummaryCollector.visitReturnStatement (package:vm/transformations/type_flow/summary_collector.dart:2058:37)
    #11     ReturnStatement.accept (package:kernel/ast.dart:6541:43)        
    #12     SummaryCollector._visit (package:vm/transformations/type_flow/summary_collector.dart:853:42)
    #13     List.forEach (dart:core-patch/growable_array.dart:313:8)        
    #14     SummaryCollector.visitBlock (package:vm/transformations/type_flow/summary_collector.dart:1923:21)
    #15     Block.accept (package:kernel/ast.dart:5873:43)                  
    #16     SummaryCollector._visit (package:vm/transformations/type_flow/summary_collector.dart:853:42)
    #17     SummaryCollector.createSummary (package:vm/transformations/type_flow/summary_collector.dart:758:9)
    #18     TypeFlowAnalysis.getSummary (package:vm/transformations/type_flow/analysis.dart:1451:52)
    #19     _DirectInvocation._processFunction (package:vm/transformations/type_flow/analysis.dart:287:42)
    #20     _DirectInvocation.process (package:vm/transformations/type_flow/analysis.dart:212:14)
    #21     _WorkList.processInvocation (package:vm/transformations/type_flow/analysis.dart:1347:32)
    #22     _DispatchableInvocation.process.<anonymous closure> (package:vm/transformations/type_flow/analysis.dart:437:44)
    #23     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
    #24     _DispatchableInvocation.process (package:vm/transformations/type_flow/analysis.dart:412:12)
    #25     _WorkList.processInvocation (package:vm/transformations/type_flow/analysis.dart:1347:32)
    #26     TypeFlowAnalysis.applyCall (package:vm/transformations/type_flow/analysis.dart:1581:23)
    #27     Call.apply (package:vm/transformations/type_flow/summary.dart:265:31)
    #28     Summary.apply (package:vm/transformations/type_flow/summary.dart:702:33)
    #29     _DirectInvocation._processFunction (package:vm/transformations/type_flow/analysis.dart:296:24)
    #30     _DirectInvocation.process (package:vm/transformations/type_flow/analysis.dart:212:14)
    #31     _WorkList.processInvocation (package:vm/transformations/type_flow/analysis.dart:1347:32)
    #32     _DispatchableInvocation.process.<anonymous closure> (package:vm/transformations/type_flow/analysis.dart:437:44)
    #33     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
    #34     _DispatchableInvocation.process (package:vm/transformations/type_flow/analysis.dart:412:12)
    #35     _WorkList.processInvocation (package:vm/transformations/type_flow/analysis.dart:1347:32)
    #36     TypeFlowAnalysis.applyCall (package:vm/transformations/type_flow/analysis.dart:1581:23)
    #37     Call.apply (package:vm/transformations/type_flow/summary.dart:265:31)
    #38     Summary.apply (package:vm/transformations/type_flow/summary.dart:702:33)
    #39     _DirectInvocation._processFunction (package:vm/transformations/type_flow/analysis.dart:296:24)
    #40     _DirectInvocation.process (package:vm/transformations/type_flow/analysis.dart:212:14)
    #41     _WorkList.processInvocation (package:vm/transformations/type_flow/analysis.dart:1347:32)
    #42     _DispatchableInvocation.process.<anonymous closure> (package:vm/transformations/type_flow/analysis.dart:437:44)
    #43     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
    #44     _DispatchableInvocation.process (package:vm/transformations/type_flow/analysis.dart:412:12)
    #45     _WorkList.processInvocation (package:vm/transformations/type_flow/analysis.dart:1347:32)
    #46     _WorkList.process (package:vm/transformations/type_flow/analysis.dart:1290:7)
    #47     TypeFlowAnalysis.process (package:vm/transformations/type_flow/analysis.dart:1469:14)
    #48     transformComponent (package:vm/transformations/type_flow/transformer.dart:78:20)
    #49     runGlobalTransformations (package:vm/kernel_front_end.dart:502:5)
    #50     compileToKernel (package:vm/kernel_front_end.dart:393:11)       
    <asynchronous suspension>                                               
    #51     FrontendCompiler.compile.<anonymous closure> (package:frontend_server/frontend_server.dart:542:54)
    #52     new Future.<anonymous closure> (dart:async/future.dart:175:37)  
    #53     _rootRun (dart:async/zone.dart:1182:47)                         
    #54     _CustomZone.run (dart:async/zone.dart:1093:19)                  
    #55     _CustomZone.runGuarded (dart:async/zone.dart:997:7)             
    #56     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1037:23)
    #57     _rootRun (dart:async/zone.dart:1190:13)                         
    #58     _CustomZone.run (dart:async/zone.dart:1093:19)                  
    #59     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1021:23)
    #60     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
    #61     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:397:19)   
    #62     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:428:5)
    #63     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
    

    可以看到是在TypeFlowAnalysis.process过程中报错,

    具体报错的地方:

      DartType getStaticType(StaticTypeContext context) {
       ...
        return Substitution.fromPairs(
                target.function.typeParameters, arguments.types)
            .substituteType(returnType);
      }
    

    因为传入fromPairs方法两个list参数的长度不一样,通过Map.fromIterables转化成Map就会报错。

    因为在构建DirectMethodInvocation的时候,对Argument参数的创建有问题:

    //创建DirectMethodInvocation
    final DirectMethodInvocation mockedInvocation = DirectMethodInvocation(
            AsExpression(PropertyGet(ThisExpression(), Name('target')),
                InterfaceType(originalClass, Nullability.legacy)),
            originalStubProcedure,
            AopUtils.concatArguments4PointcutStubCall(originalProcedure));
            
    //该方法对Arguments少了types的添加
     static Arguments concatArguments4PointcutStubCall(Member member) {
        final Arguments arguments = Arguments.empty();
         ...
          arguments.positional.add(asExpression);
          ...
          arguments.named.addAll(namedEntries);
          ...
     //缺少以下过程
        for(TypeParameter typeParameter in member.function.typeParameters){
        arguments.types.add(typeParameter.defaultType);
       }
        return arguments;
      }
    

    添加types字段虽然能解决长度不一致的问题,但是考虑到dart-sdk目前已经删除了DirectMethodInvocation等类,个人认为直接修改为MethodInvocation更佳。 image

    若分析有误或者不足还请见谅~

    opened by fightcoder 4
  • Inject方法可以用在自己写的方法中么

    Inject方法可以用在自己写的方法中么

    您好, 请问一下@inject可以注入到自己写的方法中么? 比方说 注入到 官方 example 的_incrementCounter 中, image 比方说想在【91】行写入一个输出

    ` @Inject("package:example/lib/main.dart","_MyHomePageState","-_incrementCounter",lineNum:91)

    @pragma("vm:entry-point")

    static void counterHook() {

    int count;//Aspectd Ignore

    int _counter;//Aspectd Ignore

    print("[KWLM12]:count:$count,counter:$_counter");

    //【91】行 }`

    但是无法注入 生成文件app.aspectd.dill.txt显示 如下图, image

    opened by kelciej 4
  • a package may not list itself as a dependency conflict

    a package may not list itself as a dependency conflict

    I have a flutter project called testproject I have created a dart package names aspectd_impl inside my project and in the pubspec I have added the dependency

    dependencies:
      flutter:
        sdk: flutter
      aspectd:
        git:
          url: https://github.com/alibaba-flutter/aspectd.git
          ref: master
      testproject:
        path: ../
    

    even if I make it to example it gives an error

    dependencies:
      flutter:
        sdk: flutter
      aspectd:
        git:
          url: https://github.com/alibaba-flutter/aspectd.git
          ref: master
      example:
        path: ../
    
    
    ../pubspec.yaml: "name" field doesn't match expected name "example".
    
    
    opened by maheshmnj 4
  • 在readComponent后直接writeComponentFile,报错,Reference to root::dart:collection is not bound to an AST node. A library was expected

    在readComponent后直接writeComponentFile,报错,Reference to root::dart:collection is not bound to an AST node. A library was expected

    在您的基础上尝试修改component时,read之后直接write就报错了.

    Unhandled exception: Reference to root::dart:collection is not bound to an AST node. A library was expected #请教下是什么原因呢

    Steps to Reproduce

    1.void readComponent(Component component, {bool checkCanonicalNames: false}) 2. void writeComponentFile(Component component)

    Logs

    Unhandled exception:
    Reference to root::dart:collection is not bound to an AST node. A library was expected
    #0      Reference.asLibrary (package:kernel/ast.dart:217:7)
    #1      _PrivateName.library (package:kernel/ast.dart:4764:38)
    #2      CanonicalName.getChildFromQualifiedName (package:kernel/canonical_name.dart:117:32)
    #3      CanonicalName.getChildFromMember (package:kernel/canonical_name.dart:123:10)
    #4      Class.computeCanonicalNames (package:kernel/ast.dart:917:21)
    #5      Library.computeCanonicalNames (package:kernel/ast.dart:423:14)
    #6      Component.computeCanonicalNamesForLibrary (package:kernel/ast.dart:5784:13)
    #7      Component.computeCanonicalNames (package:kernel/ast.dart:5778:7)
    

    Finally, paste the output of running flutter doctor -v here.

    Doctor summary (to see all details, run flutter doctor -v):
    [✓] Flutter (Channel stable, v1.5.4-hotfix.2, on Mac OS X 10.13.6 17G2208, locale zh-Hans-CN)
     
    [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    [✓] iOS toolchain - develop for iOS devices (Xcode 10.1)
    [✓] Android Studio (version 3.4)
    [!] IntelliJ IDEA Ultimate Edition (version 2018.2.4)
        ✗ Flutter plugin not installed; this adds Flutter specific functionality.
        ✗ Dart plugin not installed; this adds Dart specific functionality.
    [✓] Connected device (1 available)
    
    
    opened by ckdgit 4
  • 在release模式下,call library级别的方法,编译出错。

    在release模式下,call library级别的方法,编译出错。

    @kangwang1988
    反复测试发现一个问题,我给一个library方法添加call aop,debug模式下能正常编译,而且运行结果也正确。release模式下,出现“Dart snapshot generator failed with exit code -6”错误,生成的app.dill文件,转为txt查看了下,也是正确的,但是最后在flutter/bin/flutter中出错。 以下是我的测试代码: image

    image

    错误日志: image

    opened by galaxybruce 4
  • Inject hook GestureDetector无效

    Inject hook GestureDetector无效

    我使用tag1.0.5的AspectD和flutter1.22.6,尝试像样例那样使用Inject hook GestureDetector 不成功。有人知道是什么原因吗?或者该怎么调试

    @Inject("package:flutter/src/widgets/gesture_detector.dart","GestureDetector","-build", lineNum:794) @pragma("vm:entry-point") static void onTapBuild() { Object instance; //Aspectd Ignore Object context; //Aspectd Ignore print(instance); print(context); print('---onTapBuild---'); }

    opened by lwy980328 0
  • 我适配了2.5.4,大大简化了注入逻辑

    我适配了2.5.4,大大简化了注入逻辑

    项目地址https://github.com/lancexin/aspect_frontend_server 现在暂时只支持execute模式

    该方法和aspectd的区别

    1. aspectd不支持flutter 2.5.3,本项目是基于flutter 2.5.3测试
    2. aspectd的编译需要对dart sdk中的vm进行修改,本项目不需要
    3. aspectd使用前需要对flutter tools的代码进行修改,本项目只需要替换flutter sdk对应的frontend_server.dart.snapshot即可
    4. aspectd的实现原理过于复杂,本项目去掉了Call,Inject等用法保留了Execute用法的同时对注入逻辑进行了简化
    5. aspectd还需要aspect_impl等,本项目可以直接在主程序代码中添加注入代码,也可以用plugin的方式添加
    6. 本项目不需要引入任何第三方包,用pragma注解完成对应插桩
    7. 可以有限制支持hot reload,完全支持hot restart,免去了冷重启的烦恼
    8. 为了性能优化inject方法限制必须是static的

    为什么用pragma注解,而不是自定义注解?

    本项目是在aot优化后再对字节码进行修改,aot优化后只有白名单中的注解才能被识别到,pragma是在白名单中的注解.

    opened by lancexin 7
Owner
null
Dart wrapper via dart:ffi for https://github.com/libusb/libusb

libusb Dart wrapper via dart:ffi for https://github.com/libusb/libusb Environment Windows(10) macOS Linux(Ubuntu 18.04 LTS) Usage Checkout example Fea

Woodemi Co., Ltd 28 Dec 20, 2022
Extensible Dart interpreter for Dart with full interop

dart_eval is an extensible interpreter for the Dart language, written in Dart. It's powered under the hood by the Dart analyzer, so it achieves 100% c

Ethan 169 Dec 28, 2022
Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.

Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.

Google 905 Jan 2, 2023
Ecosistema de paquetes para Dart y Flutter desarrollados y mantenidos por la comunidad de Flutter Cuba relacionados con la tienda cubana de aplicaciones para dispositivos Android llamada Apklis.

Ecosistema de paquetes para Dart y Flutter desarrollados y mantenidos por la comunidad de Flutter Cuba relacionados con la tienda cubana de aplicacion

Flutter Cuba 12 Oct 24, 2022
Environment specific config generator for Dart and Flutter applications during CI/CD builds

Environment Config Generator Environment specific config generator. Allows to specify env configuration during CI/CD build. Primarily created to simpl

Denis Beketsky 86 Dec 2, 2022
🚀The Flutter dart code generator from zeplin. ex) Container, Text, Color, TextStyle, ... - Save your time.

Flutter Gen Zeplin Extension ?? The Flutter dart code generator from zeplin. ex) Container, Text, Color, TextStyle, ... - Save your time. ⬇ 1.1k Getti

NAVER 49 Oct 12, 2022
Simple & Beautiful Note taking app written in dart with flutter UI toolkit.

Notes is a privacy oriented, Secure ,beautiful and fast application made in flutter, it supports various features like adding and saving notes. Hiding

null 26 Dec 30, 2022
generate massive amounts of fake data in dart and flutter

generate massive amounts of fake data in Dart & Flutter Faker.dart is a dart port of the famous faker.js package for the web and NodeJS ?? Usage faker

Cas van Luijtelaar 26 Nov 28, 2022
A simple Flutter / Dart Utility class for converting complex objects to uri and query string

A simple Flutter / Dart Utility class for converting complex or nested objects to uri and query strings you can follow the the article on how this cla

Opata Joshua 5 Sep 7, 2022
Log snapshot management solution (iOS/Android/Web/Server) built with Flutter/Dart using Bloc pattern and Firebase Firestore backend.

Log snapshot management solution (iOS/Android/Web/Server) built with Flutter/Dart using Bloc pattern and Firebase Firestore backend.

Alexey Perov 5 Nov 9, 2022
An encapsulation made around openrouteservice API for Dart and Flutter projects.

An encapsulation made around openrouteservice API for Dart and Flutter projects. Made for easy generation of Routes and Directions on Maps, Isochrones, Time-Distance Matrix, Pelias Geocoding, POIs, Elevation and routing Optimizations using their amazing API.

Dhiman Seal 20 Oct 10, 2022
The Dart Time Machine is a date and time library for Flutter, Web, and Server with support for timezones, calendars, cultures, formatting and parsing.

The Dart Time Machine is a date and time library for Flutter, Web, and Server with support for timezones, calendars, cultures, formatting and parsing.

null 2 Oct 8, 2021
Sentry SDK for Dart and Flutter

Bad software is everywhere, and we're tired of it. Sentry is on a mission to help developers write better software faster, so we can get back to enjoy

Sentry 606 Dec 31, 2022
Automatically generate usecase classes from your repository class definition in Dart and Flutter

Repo Case Automatically generate usecase classes from your repository class definition in Dart and Flutter. Check out the official guide on repo_case

Sandro Maglione 5 Jul 30, 2022
A flutter plugin for execute dart code in background.

flutter_background_service A flutter plugin for execute dart code in background. Android No additional setting required. To change notification icon,

Eka Setiawan Saputra 160 Dec 27, 2022
Future based HTTP client for the Dart and Flutter

Uno Future based HTTP client for the Dart and Flutter. Uno, inspired by Axios, bringing a simple and robust experience to the crossplatform apps in Fl

Flutterando 56 Dec 16, 2022
OpenAPI generator for Dart & Flutter

Fantom Fantom is a cli tool for generating API layer based on OpenAPI Spec. Usage Install fantom $ dart pub global activate fantom Generate API client

6thSolution 13 Oct 18, 2022
OpenAPI generator for Dart & Flutter

Fantom Fantom is a cli tool for generating API layer based on OpenAPI Spec. Usage Install fantom $ dart pub global activate fantom Generate API client

REKAB 13 Oct 18, 2022
Reference implementation for the Zenon SDK for Dart and Flutter apps compatible

Zenon Dart SDK Reference implementation for the Zenon SDK for Dart and Flutter apps compatible with the Zenon Alphanet - Network of Momentum Phase 0.

null 8 Nov 23, 2022