Flutter 热更新无侵入方案(生成运行时库)
导读
已经很久没有写相关的文章了,主要在于每天研究时间很短,二是忙着研究怎么生成运行时库。虽然目前还有很多没有实现,我现在先同步一个大概的完成实现吧。
基本完成对于下面的运行库生成的支持
- 类只读属性的获取
- 类设置属性的设置
- 类初始化方法调用
- 类方法的调用
- 类静态属性的获取
- 类静态属性的设置
- 类方法的调用
- 全局属性的获取
- 全局属性的设置
- 全局方法的调用
- 基础枚举值的获取
分析当前库的所有依赖
pub get
对于需要分析的库中将所有库生成支持运行时支持的库,需要分析出来所有的依赖库列表,这就需要我们提前执行pub get
拉取所有的依赖库。
读取 package_config.json 里面的信息
在~/.dart_tool/package_config.json
这个文件可以获取到最新的依赖的信息,主要包括如下的信息。
- configVersion 当前配置版本号- generated 配置生成的具体时间- generator 配置生成者- generatorVersion 生成者的对应 Dart 版本- packages 依赖库列表- name 库名称- rootUri 库对应的本地地址- packageUri 库源文件对应的路径- languageVersion 当前库要求的 Dart 版本- configVersion 当前配置版本号 - generated 配置生成的具体时间 - generator 配置生成者 - generatorVersion 生成者的对应 Dart 版本 - packages 依赖库列表 - name 库名称 - rootUri 库对应的本地地址 - packageUri 库源文件对应的路径 - languageVersion 当前库要求的 Dart 版本- configVersion 当前配置版本号 - generated 配置生成的具体时间 - generator 配置生成者 - generatorVersion 生成者的对应 Dart 版本 - packages 依赖库列表 - name 库名称 - rootUri 库对应的本地地址 - packageUri 库源文件对应的路径 - languageVersion 当前库要求的 Dart 版本
将配置的 JSON 信息转换成对象
import 'package:darty_json_safe/darty_json_safe.dart';class PackageConfig {late int configVersion;late String generated;late String generator;late String generatorVersion;late List<PackageInfo> packages;PackageConfig.fromJson(Map<String, dynamic> json) {final jsonValue = JSON(json);configVersion = jsonValue["configVersion"].intValue;generated = jsonValue["generated"].stringValue;generator = jsonValue["generator"].stringValue;generatorVersion = jsonValue["generatorVersion"].stringValue;packages = jsonValue["packages"].listValue.map((e) => PackageInfo.fromJson(e)).toList();}}class PackageInfo {late String name;late String rootUri;late String packageUri;late String languageVersion;PackageInfo.fromJson(Map<String, dynamic> json) {final jsonValue = JSON(json);name = jsonValue["name"].stringValue;rootUri = jsonValue["rootUri"].stringValue;packageUri = jsonValue["packageUri"].stringValue;languageVersion = jsonValue["languageVersion"].stringValue;}}import 'package:darty_json_safe/darty_json_safe.dart'; class PackageConfig { late int configVersion; late String generated; late String generator; late String generatorVersion; late List<PackageInfo> packages; PackageConfig.fromJson(Map<String, dynamic> json) { final jsonValue = JSON(json); configVersion = jsonValue["configVersion"].intValue; generated = jsonValue["generated"].stringValue; generator = jsonValue["generator"].stringValue; generatorVersion = jsonValue["generatorVersion"].stringValue; packages = jsonValue["packages"] .listValue .map((e) => PackageInfo.fromJson(e)) .toList(); } } class PackageInfo { late String name; late String rootUri; late String packageUri; late String languageVersion; PackageInfo.fromJson(Map<String, dynamic> json) { final jsonValue = JSON(json); name = jsonValue["name"].stringValue; rootUri = jsonValue["rootUri"].stringValue; packageUri = jsonValue["packageUri"].stringValue; languageVersion = jsonValue["languageVersion"].stringValue; } }import 'package:darty_json_safe/darty_json_safe.dart'; class PackageConfig { late int configVersion; late String generated; late String generator; late String generatorVersion; late List<PackageInfo> packages; PackageConfig.fromJson(Map<String, dynamic> json) { final jsonValue = JSON(json); configVersion = jsonValue["configVersion"].intValue; generated = jsonValue["generated"].stringValue; generator = jsonValue["generator"].stringValue; generatorVersion = jsonValue["generatorVersion"].stringValue; packages = jsonValue["packages"] .listValue .map((e) => PackageInfo.fromJson(e)) .toList(); } } class PackageInfo { late String name; late String rootUri; late String packageUri; late String languageVersion; PackageInfo.fromJson(Map<String, dynamic> json) { final jsonValue = JSON(json); name = jsonValue["name"].stringValue; rootUri = jsonValue["rootUri"].stringValue; packageUri = jsonValue["packageUri"].stringValue; languageVersion = jsonValue["languageVersion"].stringValue; } }
这里我用到自己之前发布的一个库darty_json_safe来解析就没用到官方解析的库了。
生成运行库
我们将上面分析出来的依赖配置信息放在可以全局访问,用于后续方便我们查找将关联类型的类进行引入。
分析库的路径
我们从 PackageInfo 中字段 rootUri 可以拿到依赖库具体的详细的地址,每个地址都是一个对应版本库的依赖,比如我们拿着 yaml 这个依赖库为例子。
file:///Users/king/.pub-cache/hosted/pub.flutter-io.cn/yaml-3.1.2file:///Users/king/.pub-cache/hosted/pub.flutter-io.cn/yaml-3.1.2file:///Users/king/.pub-cache/hosted/pub.flutter-io.cn/yaml-3.1.2
对于上面的地址,我们不能直接拿来进行使用,我们需要去掉最开始的字符串file://
运行库生成地址
我们将生成的运行库存放在本机电脑 $HOME/.runtime
目录,这个 $HOME 参数我们可以引用 process_run
这个库通过下面的方法可以获取到
platformEnvironment["HOME"] // 获取本机 HOME 目录platformEnvironment["HOME"] // 获取本机 HOME 目录platformEnvironment["HOME"] // 获取本机 HOME 目录
分析代码
具体分析的代码可以参考下面的文件
AnalysisContextCollection
为了可以拿到当前分析库的代码信息,我们需要通过库 analyzer 中 AnalysisContextCollection 类来分析代码信息。
AnalysisContextCollection(sdkPath: getDartPath(),includedPaths: [join(packagePath, "lib")],);AnalysisContextCollection( sdkPath: getDartPath(), includedPaths: [join(packagePath, "lib")], );AnalysisContextCollection( sdkPath: getDartPath(), includedPaths: [join(packagePath, "lib")], );
第一个参数是本地 Dart 库的地址,不设置分析就会报错。
第二个参数是分析源代码的文件夹或者具体文件路径
Dart 库的地址
我们可以通过下面的代码进行获取
String getDartPath() {// 获取当前 Dart 命令的具体路径String dartCommandPath = whichSync("dart") ?? "";// 将获取的 Dart 路径获取到当前文件夹 之后添加 cache/dart-sdkreturn join(dirname(dartCommandPath), "cache", "dart-sdk");}String getDartPath() { // 获取当前 Dart 命令的具体路径 String dartCommandPath = whichSync("dart") ?? ""; // 将获取的 Dart 路径获取到当前文件夹 之后添加 cache/dart-sdk return join(dirname(dartCommandPath), "cache", "dart-sdk"); }String getDartPath() { // 获取当前 Dart 命令的具体路径 String dartCommandPath = whichSync("dart") ?? ""; // 将获取的 Dart 路径获取到当前文件夹 之后添加 cache/dart-sdk return join(dirname(dartCommandPath), "cache", "dart-sdk"); }
分析当前库的 pubspec 信息
可以引入 pubspec_parse 这个库来分析 pubspec.yaml 的信息。
final sourceFile = join(packagePath, "pubspec.yaml");pubspec = Pubspec.parse(await File(sourceFile).readAsString());final sourceFile = join(packagePath, "pubspec.yaml"); pubspec = Pubspec.parse(await File(sourceFile).readAsString());final sourceFile = join(packagePath, "pubspec.yaml"); pubspec = Pubspec.parse(await File(sourceFile).readAsString());
分析代码文件
我们从提供的库路径获取到目录下面所有的源文件,我们默认为所有的的依赖库的源文件都在 lib 这个目录下。
// 获取到当前需要分析目录下面所有的子元素List<FileSystemEntity> entitys = await Directory(dir).list(recursive: true).toList();// 获取到当前需要分析目录下面所有的子元素 List<FileSystemEntity> entitys = await Directory(dir).list(recursive: true).toList();// 获取到当前需要分析目录下面所有的子元素 List<FileSystemEntity> entitys = await Directory(dir).list(recursive: true).toList();
通过 AnalysisContext 对象拿到对应代码文件的分析结果
AnalysisContext context = analysisContextCollection.contextFor(path);SomeResolvedLibraryResult result = await context.currentSession.getResolvedLibrary(path);AnalysisContext context = analysisContextCollection.contextFor(path); SomeResolvedLibraryResult result = await context.currentSession.getResolvedLibrary(path);AnalysisContext context = analysisContextCollection.contextFor(path); SomeResolvedLibraryResult result = await context.currentSession.getResolvedLibrary(path);
SomeResolvedLibraryResult 存在有多个子类,我们暂时只分析 ResolvedLibraryResult 这个子类的内容。
分析 Class
获取当前代码文件所有可以被公开访问的类
final classes = result.element.units[0].classes.where((element) {return !element.name.isPrivate;});bool get isPrivate => startsWith("_");final classes = result.element.units[0].classes.where((element) { return !element.name.isPrivate; }); bool get isPrivate => startsWith("_");final classes = result.element.units[0].classes.where((element) { return !element.name.isPrivate; }); bool get isPrivate => startsWith("_");
虽然 result.element.units 是一个数组 但是目前还没有遇到存在两个的,所以就暂时用一个座位分析研究
每一个类分析出来都是一个 ClassElement 对象,我们可以从这里面找到需要的信息。
- String name // 获取类名称- List<FieldElement> fields // 获取类的属性- PropertyAccessorElement getter // 获取只读的属性- PropertyAccessorElement setter // 获取可以设置的属性- List<MethodElement> methods // 获取类的方法- List<ConstructorElement> constructors // 获取类的构造方法- Bool isAbstract // 是否是抽象类- String name // 获取类名称 - List<FieldElement> fields // 获取类的属性 - PropertyAccessorElement getter // 获取只读的属性 - PropertyAccessorElement setter // 获取可以设置的属性 - List<MethodElement> methods // 获取类的方法 - List<ConstructorElement> constructors // 获取类的构造方法 - Bool isAbstract // 是否是抽象类- String name // 获取类名称 - List<FieldElement> fields // 获取类的属性 - PropertyAccessorElement getter // 获取只读的属性 - PropertyAccessorElement setter // 获取可以设置的属性 - List<MethodElement> methods // 获取类的方法 - List<ConstructorElement> constructors // 获取类的构造方法 - Bool isAbstract // 是否是抽象类
分析 PropertyAccessorElement
- String name // 属性名称- String isStatic // 是否是静态属性- String name // 属性名称 - String isStatic // 是否是静态属性- String name // 属性名称 - String isStatic // 是否是静态属性
对于属性的名称我们要处理本身就带有 $和=号的特殊字符
对于 $ 我们可以添加 \进行转移
对于尾部带有 = 的我们需要将 = 号进行移除
分析 MethodElement
- String name // 获取方法名称- List<ParameterElement> parameters // 获取方法参数列表- String name // 获取方法名称 - List<ParameterElement> parameters // 获取方法参数列表- String name // 获取方法名称 - List<ParameterElement> parameters // 获取方法参数列表
分析 ConstructorElement
- String name // 构造方法名称可能为空- List<ParameterElement> parameters // 构造的参数列表- String name // 构造方法名称可能为空 - List<ParameterElement> parameters // 构造的参数列表- String name // 构造方法名称可能为空 - List<ParameterElement> parameters // 构造的参数列表
分析 ParameterElement
- String name // 参数名称- bool isNamed // 是否是名字参数- bool hasDefaultValue // 是否有默认值- String defaultValueCode // 默认值- String name // 参数名称 - bool isNamed // 是否是名字参数 - bool hasDefaultValue // 是否有默认值 - String defaultValueCode // 默认值- String name // 参数名称 - bool isNamed // 是否是名字参数 - bool hasDefaultValue // 是否有默认值 - String defaultValueCode // 默认值
分析 FunctionElement
- String name // 全局方法名称- List<ParameterElement> parameters // 全局方法参数- String name // 全局方法名称 - List<ParameterElement> parameters // 全局方法参数- String name // 全局方法名称 - List<ParameterElement> parameters // 全局方法参数
分析 EnumElement
- String name // 枚举名称- List<FieldElementImpl> constructors // 枚举值- String name 枚举值名称- String name // 枚举名称 - List<FieldElementImpl> constructors // 枚举值 - String name 枚举值名称- String name // 枚举名称 - List<FieldElementImpl> constructors // 枚举值 - String name 枚举值名称
生成代码
我们已经通过分析代码拿到了基本的信息,剩下的我们通过获取的值通过 Mustache 模版语法来实现我们的生成代码。
对于 Mustache 我们可以通过 mustache_template 这个库来提供支持。
flutter_runtime
flutter_runtime是提供运行时基础能力的,后续会根据需求调整。
abstract class FlutterRuntime<T> {// 当前运行类的实例final T runtime;FlutterRuntime(this.runtime);// 获取当前类公开只读的属性dynamic getField(String fieldName);// 设置类公开的设置属性void setField(String fieldName, dynamic value);// 执行当前类的公开方法dynamic call(String methodName, [Map args = const {}]);// 根据类名创建当前类实例dynamic createInstance(String packageName,String libraryPath,String className, [Map args = const {},]) {return null;}}abstract class FlutterRuntime<T> { // 当前运行类的实例 final T runtime; FlutterRuntime(this.runtime); // 获取当前类公开只读的属性 dynamic getField(String fieldName); // 设置类公开的设置属性 void setField(String fieldName, dynamic value); // 执行当前类的公开方法 dynamic call(String methodName, [Map args = const {}]); // 根据类名创建当前类实例 dynamic createInstance( String packageName, String libraryPath, String className, [ Map args = const {}, ]) { return null; } }abstract class FlutterRuntime<T> { // 当前运行类的实例 final T runtime; FlutterRuntime(this.runtime); // 获取当前类公开只读的属性 dynamic getField(String fieldName); // 设置类公开的设置属性 void setField(String fieldName, dynamic value); // 执行当前类的公开方法 dynamic call(String methodName, [Map args = const {}]); // 根据类名创建当前类实例 dynamic createInstance( String packageName, String libraryPath, String className, [ Map args = const {}, ]) { return null; } }
我们生成的每一个运行时对象都要基于这个抽象类来生成。
pubspec.yaml
对于生成的运行时库,我们需要创建一个 pubspec.yaml
name: {{pubName}}_runtimeenvironment:sdk: '>=2.18.0 <3.0.0'dependencies:flutter_runtime:path: {{{flutterRuntimePath}}}{{pubName}}:path: {{{pubPath}}}darty_json_safe: ^1.0.1name: {{pubName}}_runtime environment: sdk: '>=2.18.0 <3.0.0' dependencies: flutter_runtime: path: {{{flutterRuntimePath}}} {{pubName}}: path: {{{pubPath}}} darty_json_safe: ^1.0.1name: {{pubName}}_runtime environment: sdk: '>=2.18.0 <3.0.0' dependencies: flutter_runtime: path: {{{flutterRuntimePath}}} {{pubName}}: path: {{{pubPath}}} darty_json_safe: ^1.0.1
-
pubName
源包名
-
flutterRuntimePath
flutter_runtime 依赖的地址
-
pubPath
源包依赖的地址
生成运行时代码文件
// ignore_for_file: implementation_imports, unused_importimport 'dart:async';import 'package:flutter_runtime/flutter_runtime.dart';import 'package:darty_json_safe/darty_json_safe.dart';# 根据提供的依赖路径生成需要导入的依赖{{#paths}}import '{{{sourcePath}}}';{{/paths}}# 生成运行时 Class{{#classes}}{{>classMustache}}{{/classes}}// ignore_for_file: implementation_imports, unused_import import 'dart:async'; import 'package:flutter_runtime/flutter_runtime.dart'; import 'package:darty_json_safe/darty_json_safe.dart'; # 根据提供的依赖路径生成需要导入的依赖 {{#paths}} import '{{{sourcePath}}}'; {{/paths}} # 生成运行时 Class {{#classes}} {{>classMustache}} {{/classes}}// ignore_for_file: implementation_imports, unused_import import 'dart:async'; import 'package:flutter_runtime/flutter_runtime.dart'; import 'package:darty_json_safe/darty_json_safe.dart'; # 根据提供的依赖路径生成需要导入的依赖 {{#paths}} import '{{{sourcePath}}}'; {{/paths}} # 生成运行时 Class {{#classes}} {{>classMustache}} {{/classes}}
生成运行时 Class
class \${{className}}\$ extends FlutterRuntime<{{className}}>{# 生成必要的运行时构造器\${{className}}\$(super.runtime);# 生成只读属性的运行时方法{{>getFieldMustache}}# 生成设置属性的运行时方法{{>setFieldMustache}}# 生成方法运行时调用{{>methodMustache}}# 生成构造方法的运行时调用{{>constructorMustache}}}class \${{className}}\$ extends FlutterRuntime<{{className}}>{ # 生成必要的运行时构造器 \${{className}}\$(super.runtime); # 生成只读属性的运行时方法 {{>getFieldMustache}} # 生成设置属性的运行时方法 {{>setFieldMustache}} # 生成方法运行时调用 {{>methodMustache}} # 生成构造方法的运行时调用 {{>constructorMustache}} }class \${{className}}\$ extends FlutterRuntime<{{className}}>{ # 生成必要的运行时构造器 \${{className}}\$(super.runtime); # 生成只读属性的运行时方法 {{>getFieldMustache}} # 生成设置属性的运行时方法 {{>setFieldMustache}} # 生成方法运行时调用 {{>methodMustache}} # 生成构造方法的运行时调用 {{>constructorMustache}} }
只读属性运行时方法
@overridedynamic getField(String fieldName) {# 便利只读属性的列表{{#getFields}}# 是静态的属性{{#isStatic}}if (fieldName == "{{fieldName}}") return {{className}}.{{fieldName}};{{/isStatic}}# 不是静态属性{{^isStatic}}if (fieldName == "{{fieldName}}") return runtime.{{fieldName}};{{/isStatic}}{{/getFields}}}@override dynamic getField(String fieldName) { # 便利只读属性的列表 {{#getFields}} # 是静态的属性 {{#isStatic}} if (fieldName == "{{fieldName}}") return {{className}}.{{fieldName}}; {{/isStatic}} # 不是静态属性 {{^isStatic}} if (fieldName == "{{fieldName}}") return runtime.{{fieldName}}; {{/isStatic}} {{/getFields}} }@override dynamic getField(String fieldName) { # 便利只读属性的列表 {{#getFields}} # 是静态的属性 {{#isStatic}} if (fieldName == "{{fieldName}}") return {{className}}.{{fieldName}}; {{/isStatic}} # 不是静态属性 {{^isStatic}} if (fieldName == "{{fieldName}}") return runtime.{{fieldName}}; {{/isStatic}} {{/getFields}} }
设置属性的运行时方法
@overridevoid setField(String fieldName, dynamic value) {# 设置属性的列表{{#setFields}}{{#isStatic}}if (fieldName == "{{fieldName}}") {{className}}.{{fieldName}} = value;{{/isStatic}}{{^isStatic}}if (fieldName == "{{fieldName}}") runtime.{{fieldName}} = value;{{/isStatic}}{{/setFields}}}@override void setField(String fieldName, dynamic value) { # 设置属性的列表 {{#setFields}} {{#isStatic}} if (fieldName == "{{fieldName}}") {{className}}.{{fieldName}} = value; {{/isStatic}} {{^isStatic}} if (fieldName == "{{fieldName}}") runtime.{{fieldName}} = value; {{/isStatic}} {{/setFields}} }@override void setField(String fieldName, dynamic value) { # 设置属性的列表 {{#setFields}} {{#isStatic}} if (fieldName == "{{fieldName}}") {{className}}.{{fieldName}} = value; {{/isStatic}} {{^isStatic}} if (fieldName == "{{fieldName}}") runtime.{{fieldName}} = value; {{/isStatic}} {{/setFields}} }
方法的运行时方法
@overridedynamic call(String methodName,[Map args = const {}]) {# 类中的方法列表{{#methods}}{{>functionMustache}}{{/methods}}}# functionMustache# 是否是自定义调用代码 针对一些[]这种数组和字典的方式{{#isCustomCall}}if (methodName == '{{methodName}}') return {{{customCallCode}}};{{/isCustomCall}}{{^isCustomCall}}if (methodName == '{{methodName}}') return runtime.{{methodName}}(# 方法的参数列表{{#parameters}}# 是名称参数{{#isNamed}}{{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}},{{/isNamed}}# 不是名称参数{{^isNamed}}{{>createInstanceMustache}}{{>defaultValueMustache}},{{/isNamed}}{{/parameters}});{{/isCustomCall}}@override dynamic call(String methodName,[Map args = const {}]) { # 类中的方法列表 {{#methods}} {{>functionMustache}} {{/methods}} } # functionMustache # 是否是自定义调用代码 针对一些[]这种数组和字典的方式 {{#isCustomCall}} if (methodName == '{{methodName}}') return {{{customCallCode}}}; {{/isCustomCall}} {{^isCustomCall}} if (methodName == '{{methodName}}') return runtime.{{methodName}}( # 方法的参数列表 {{#parameters}} # 是名称参数 {{#isNamed}} {{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} # 不是名称参数 {{^isNamed}} {{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{/parameters}} ); {{/isCustomCall}}@override dynamic call(String methodName,[Map args = const {}]) { # 类中的方法列表 {{#methods}} {{>functionMustache}} {{/methods}} } # functionMustache # 是否是自定义调用代码 针对一些[]这种数组和字典的方式 {{#isCustomCall}} if (methodName == '{{methodName}}') return {{{customCallCode}}}; {{/isCustomCall}} {{^isCustomCall}} if (methodName == '{{methodName}}') return runtime.{{methodName}}( # 方法的参数列表 {{#parameters}} # 是名称参数 {{#isNamed}} {{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} # 不是名称参数 {{^isNamed}} {{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{/parameters}} ); {{/isCustomCall}}
构造方法的运行时方法
{{className}}? createRuntimeInstance(String constructorName,[Map args = const {},]) {# 是否是抽象方法 抽象方法不支持构造函数{{^isAbstract}}# 构造方法列表{{#constructors}}if (constructorName == "{{constructorName}}")return {{className}}{{#isName}}.{{constructorName}}{{/isName}}({{#parameters}}{{#isNamed}}{{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}},{{/isNamed}}{{^isNamed}}{{>createInstanceMustache}}{{>defaultValueMustache}},{{/isNamed}}{{/parameters}});{{/constructors}}{{/isAbstract}}return null;}{{className}}? createRuntimeInstance(String constructorName,[Map args = const {},]) { # 是否是抽象方法 抽象方法不支持构造函数 {{^isAbstract}} # 构造方法列表 {{#constructors}} if (constructorName == "{{constructorName}}") return {{className}}{{#isName}}.{{constructorName}}{{/isName}}( {{#parameters}} {{#isNamed}} {{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{^isNamed}} {{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{/parameters}} ); {{/constructors}} {{/isAbstract}} return null; }{{className}}? createRuntimeInstance(String constructorName,[Map args = const {},]) { # 是否是抽象方法 抽象方法不支持构造函数 {{^isAbstract}} # 构造方法列表 {{#constructors}} if (constructorName == "{{constructorName}}") return {{className}}{{#isName}}.{{constructorName}}{{/isName}}( {{#parameters}} {{#isNamed}} {{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{^isNamed}} {{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{/parameters}} ); {{/constructors}} {{/isAbstract}} return null; }
全局调用的运行时
// ignore_for_file: implementation_imports, unused_importimport 'package:flutter_runtime/flutter_runtime.dart';import 'package:darty_json_safe/darty_json_safe.dart';{{#paths}}import '{{{sourcePath}}}';{{/paths}}# 因为全局没有一个对应类 所以就直接用 dynamic 后面可以通过 null 进行创建class \$GlobalRuntime\$ extends FlutterRuntime<dynamic> {\$GlobalRuntime\$(super.runtime);# 全局的方法 直接可以调用 不需要 runtimedynamic call(String methodName, [Map args = const {}]) {{{#functions}}if (methodName == '{{methodName}}') return {{methodName}}({{#parameters}}{{#isNamed}}{{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}},{{/isNamed}}{{^isNamed}}{{>createInstanceMustache}}{{>defaultValueMustache}},{{/isNamed}}{{/parameters}});{{/functions}}}@overridegetField(String fieldName) {{{#getFields}}if (fieldName == '{{fieldName}}') return {{fieldValue}};{{/getFields}}}@overridevoid setField(String fieldName, value) {{{#setFields}}if (fieldName == "{{fieldName}}") {{fieldName}} = value;{{/setFields}}}dynamic getEnumValue(String enumName, String constructorName) {{{#enums}}if (enumName == "{{enumName}}"){{{#constructors}}if (constructorName == '{{constructorName}}') {return {{enumName}}.{{constructorName}};}{{/constructors}}}{{/enums}}return null;}}// ignore_for_file: implementation_imports, unused_import import 'package:flutter_runtime/flutter_runtime.dart'; import 'package:darty_json_safe/darty_json_safe.dart'; {{#paths}} import '{{{sourcePath}}}'; {{/paths}} # 因为全局没有一个对应类 所以就直接用 dynamic 后面可以通过 null 进行创建 class \$GlobalRuntime\$ extends FlutterRuntime<dynamic> { \$GlobalRuntime\$(super.runtime); # 全局的方法 直接可以调用 不需要 runtime dynamic call(String methodName, [Map args = const {}]) { {{#functions}} if (methodName == '{{methodName}}') return {{methodName}}( {{#parameters}} {{#isNamed}} {{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{^isNamed}} {{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{/parameters}} ); {{/functions}} } @override getField(String fieldName) { {{#getFields}} if (fieldName == '{{fieldName}}') return {{fieldValue}}; {{/getFields}} } @override void setField(String fieldName, value) { {{#setFields}} if (fieldName == "{{fieldName}}") {{fieldName}} = value; {{/setFields}} } dynamic getEnumValue(String enumName, String constructorName) { {{#enums}} if (enumName == "{{enumName}}"){ {{#constructors}} if (constructorName == '{{constructorName}}') { return {{enumName}}.{{constructorName}}; } {{/constructors}} } {{/enums}} return null; } }// ignore_for_file: implementation_imports, unused_import import 'package:flutter_runtime/flutter_runtime.dart'; import 'package:darty_json_safe/darty_json_safe.dart'; {{#paths}} import '{{{sourcePath}}}'; {{/paths}} # 因为全局没有一个对应类 所以就直接用 dynamic 后面可以通过 null 进行创建 class \$GlobalRuntime\$ extends FlutterRuntime<dynamic> { \$GlobalRuntime\$(super.runtime); # 全局的方法 直接可以调用 不需要 runtime dynamic call(String methodName, [Map args = const {}]) { {{#functions}} if (methodName == '{{methodName}}') return {{methodName}}( {{#parameters}} {{#isNamed}} {{parameterName}}:{{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{^isNamed}} {{>createInstanceMustache}}{{>defaultValueMustache}}, {{/isNamed}} {{/parameters}} ); {{/functions}} } @override getField(String fieldName) { {{#getFields}} if (fieldName == '{{fieldName}}') return {{fieldValue}}; {{/getFields}} } @override void setField(String fieldName, value) { {{#setFields}} if (fieldName == "{{fieldName}}") {{fieldName}} = value; {{/setFields}} } dynamic getEnumValue(String enumName, String constructorName) { {{#enums}} if (enumName == "{{enumName}}"){ {{#constructors}} if (constructorName == '{{constructorName}}') { return {{enumName}}.{{constructorName}}; } {{/constructors}} } {{/enums}} return null; } }
一些技术点
怎么让生成的代码不报错?
- 让生成的类所属的文件作为依赖引入
- 让默认值关联的对象所属的文件作为依赖引入
对于 [] 和 == 好方法的处理
String? get customCallCode {if (name == '[]=' && parameters.length == 2) {return '''runtime[args['${parameters[0].name}']] = args['${parameters[1].name}']''';} else if (name == '==' && parameters.length == 1) {return '''runtime == args['${parameters[0].name}']''';} else {return null;}}String? get customCallCode { if (name == '[]=' && parameters.length == 2) { return '''runtime[args['${parameters[0].name}']] = args['${parameters[1].name}']'''; } else if (name == '==' && parameters.length == 1) { return '''runtime == args['${parameters[0].name}']'''; } else { return null; } }String? get customCallCode { if (name == '[]=' && parameters.length == 2) { return '''runtime[args['${parameters[0].name}']] = args['${parameters[1].name}']'''; } else if (name == '==' && parameters.length == 1) { return '''runtime == args['${parameters[0].name}']'''; } else { return null; } }
如果判断方法名称为 [] 或者 == 就生成自定义的调用代码生成。
获取默认值对应对象所在的库文件路径
String? get defaultValueImportPath {if (!hasDefaultValue || this is! DefaultParameterElementImpl) return null;DefaultParameterElementImpl parameter = this as DefaultParameterElementImpl;final constantInitializer = parameter.constantInitializer;if (constantInitializer == null ||constantInitializer is! PrefixedIdentifier) return null;return constantInitializer.staticElement?.librarySource?.importPath;}extension SourceImport on Source {String? get importPath {final packages =Get.find<HomeController>().packageConfig.value?.packages ?? [];List<PackageInfo> infos = packages.where((element) {return fullName.startsWith(element.rootUri.replaceFirst("file://", ""));}).toList();if (infos.isEmpty) return null;PackageInfo info = infos[0];final path = fullName.split("/lib/").last;return 'package:${info.name}/$path';}}String? get defaultValueImportPath { if (!hasDefaultValue || this is! DefaultParameterElementImpl) return null; DefaultParameterElementImpl parameter = this as DefaultParameterElementImpl; final constantInitializer = parameter.constantInitializer; if (constantInitializer == null || constantInitializer is! PrefixedIdentifier) return null; return constantInitializer.staticElement?.librarySource?.importPath; } extension SourceImport on Source { String? get importPath { final packages = Get.find<HomeController>().packageConfig.value?.packages ?? []; List<PackageInfo> infos = packages.where((element) { return fullName.startsWith(element.rootUri.replaceFirst("file://", "")); }).toList(); if (infos.isEmpty) return null; PackageInfo info = infos[0]; final path = fullName.split("/lib/").last; return 'package:${info.name}/$path'; } }String? get defaultValueImportPath { if (!hasDefaultValue || this is! DefaultParameterElementImpl) return null; DefaultParameterElementImpl parameter = this as DefaultParameterElementImpl; final constantInitializer = parameter.constantInitializer; if (constantInitializer == null || constantInitializer is! PrefixedIdentifier) return null; return constantInitializer.staticElement?.librarySource?.importPath; } extension SourceImport on Source { String? get importPath { final packages = Get.find<HomeController>().packageConfig.value?.packages ?? []; List<PackageInfo> infos = packages.where((element) { return fullName.startsWith(element.rootUri.replaceFirst("file://", "")); }).toList(); if (infos.isEmpty) return null; PackageInfo info = infos[0]; final path = fullName.split("/lib/").last; return 'package:${info.name}/$path'; } }
运行库生成例子
普通类文件
// ignore_for_file: implementation_imports, unused_importimport 'dart:async';import 'package:flutter_runtime/flutter_runtime.dart';import 'package:darty_json_safe/darty_json_safe.dart';import 'package:yaml/src/event.dart';class $Event$ extends FlutterRuntime<Event> {$Event$(super.runtime);@overridedynamic getField(String fieldName) {if (fieldName == "type") return runtime.type;if (fieldName == "span") return runtime.span;}@overridevoid setField(String fieldName, dynamic value) {}@overridedynamic call(String methodName, [Map args = const {}]) {if (methodName == 'toString') return runtime.toString();}Event? createRuntimeInstance(String constructorName, [Map args = const {},]) {if (constructorName == "")return Event(args['type'],args['span'],);return null;}}class $DocumentStartEvent$ extends FlutterRuntime<DocumentStartEvent> {$DocumentStartEvent$(super.runtime);@overridedynamic getField(String fieldName) {if (fieldName == "span") return runtime.span;if (fieldName == "versionDirective") return runtime.versionDirective;if (fieldName == "tagDirectives") return runtime.tagDirectives;if (fieldName == "isImplicit") return runtime.isImplicit;if (fieldName == "type") return runtime.type;}@overridevoid setField(String fieldName, dynamic value) {}@overridedynamic call(String methodName, [Map args = const {}]) {if (methodName == 'toString') return runtime.toString();}DocumentStartEvent? createRuntimeInstance(String constructorName, [Map args = const {},]) {if (constructorName == "")return DocumentStartEvent(args['span'],versionDirective: args['versionDirective'],tagDirectives: args['tagDirectives'],isImplicit: args['isImplicit'] ?? true,);return null;}}class $DocumentEndEvent$ extends FlutterRuntime<DocumentEndEvent> {$DocumentEndEvent$(super.runtime);@overridedynamic getField(String fieldName) {if (fieldName == "span") return runtime.span;if (fieldName == "isImplicit") return runtime.isImplicit;if (fieldName == "type") return runtime.type;}@overridevoid setField(String fieldName, dynamic value) {}@overridedynamic call(String methodName, [Map args = const {}]) {if (methodName == 'toString') return runtime.toString();}DocumentEndEvent? createRuntimeInstance(String constructorName, [Map args = const {},]) {if (constructorName == "")return DocumentEndEvent(args['span'],isImplicit: args['isImplicit'] ?? true,);return null;}}class $AliasEvent$ extends FlutterRuntime<AliasEvent> {$AliasEvent$(super.runtime);@overridedynamic getField(String fieldName) {if (fieldName == "span") return runtime.span;if (fieldName == "name") return runtime.name;if (fieldName == "type") return runtime.type;}@overridevoid setField(String fieldName, dynamic value) {}@overridedynamic call(String methodName, [Map args = const {}]) {if (methodName == 'toString') return runtime.toString();}AliasEvent? createRuntimeInstance(String constructorName, [Map args = const {},]) {if (constructorName == "")return AliasEvent(args['span'],args['name'],);return null;}}class $ScalarEvent$ extends FlutterRuntime<ScalarEvent> {$ScalarEvent$(super.runtime);@overridedynamic getField(String fieldName) {if (fieldName == "span") return runtime.span;if (fieldName == "anchor") return runtime.anchor;if (fieldName == "tag") return runtime.tag;if (fieldName == "value") return runtime.value;if (fieldName == "style") return runtime.style;if (fieldName == "type") return runtime.type;}@overridevoid setField(String fieldName, dynamic value) {}@overridedynamic call(String methodName, [Map args = const {}]) {if (methodName == 'toString') return runtime.toString();}ScalarEvent? createRuntimeInstance(String constructorName, [Map args = const {},]) {if (constructorName == "")return ScalarEvent(args['span'],args['value'],args['style'],anchor: args['anchor'],tag: args['tag'],);return null;}}class $SequenceStartEvent$ extends FlutterRuntime<SequenceStartEvent> {$SequenceStartEvent$(super.runtime);@overridedynamic getField(String fieldName) {if (fieldName == "span") return runtime.span;if (fieldName == "anchor") return runtime.anchor;if (fieldName == "tag") return runtime.tag;if (fieldName == "style") return runtime.style;if (fieldName == "type") return runtime.type;}@overridevoid setField(String fieldName, dynamic value) {}@overridedynamic call(String methodName, [Map args = const {}]) {}SequenceStartEvent? createRuntimeInstance(String constructorName, [Map args = const {},]) {if (constructorName == "")return SequenceStartEvent(args['span'],args['style'],anchor: args['anchor'],tag: args['tag'],);return null;}}class $MappingStartEvent$ extends FlutterRuntime<MappingStartEvent> {$MappingStartEvent$(super.runtime);@overridedynamic getField(String fieldName) {if (fieldName == "span") return runtime.span;if (fieldName == "anchor") return runtime.anchor;if (fieldName == "tag") return runtime.tag;if (fieldName == "style") return runtime.style;if (fieldName == "type") return runtime.type;}@overridevoid setField(String fieldName, dynamic value) {}@overridedynamic call(String methodName, [Map args = const {}]) {}MappingStartEvent? createRuntimeInstance(String constructorName, [Map args = const {},]) {if (constructorName == "")return MappingStartEvent(args['span'],args['style'],anchor: args['anchor'],tag: args['tag'],);return null;}}// ignore_for_file: implementation_imports, unused_import import 'dart:async'; import 'package:flutter_runtime/flutter_runtime.dart'; import 'package:darty_json_safe/darty_json_safe.dart'; import 'package:yaml/src/event.dart'; class $Event$ extends FlutterRuntime<Event> { $Event$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "type") return runtime.type; if (fieldName == "span") return runtime.span; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } Event? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return Event( args['type'], args['span'], ); return null; } } class $DocumentStartEvent$ extends FlutterRuntime<DocumentStartEvent> { $DocumentStartEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "versionDirective") return runtime.versionDirective; if (fieldName == "tagDirectives") return runtime.tagDirectives; if (fieldName == "isImplicit") return runtime.isImplicit; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } DocumentStartEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return DocumentStartEvent( args['span'], versionDirective: args['versionDirective'], tagDirectives: args['tagDirectives'], isImplicit: args['isImplicit'] ?? true, ); return null; } } class $DocumentEndEvent$ extends FlutterRuntime<DocumentEndEvent> { $DocumentEndEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "isImplicit") return runtime.isImplicit; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } DocumentEndEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return DocumentEndEvent( args['span'], isImplicit: args['isImplicit'] ?? true, ); return null; } } class $AliasEvent$ extends FlutterRuntime<AliasEvent> { $AliasEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "name") return runtime.name; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } AliasEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return AliasEvent( args['span'], args['name'], ); return null; } } class $ScalarEvent$ extends FlutterRuntime<ScalarEvent> { $ScalarEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "anchor") return runtime.anchor; if (fieldName == "tag") return runtime.tag; if (fieldName == "value") return runtime.value; if (fieldName == "style") return runtime.style; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } ScalarEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return ScalarEvent( args['span'], args['value'], args['style'], anchor: args['anchor'], tag: args['tag'], ); return null; } } class $SequenceStartEvent$ extends FlutterRuntime<SequenceStartEvent> { $SequenceStartEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "anchor") return runtime.anchor; if (fieldName == "tag") return runtime.tag; if (fieldName == "style") return runtime.style; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) {} SequenceStartEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return SequenceStartEvent( args['span'], args['style'], anchor: args['anchor'], tag: args['tag'], ); return null; } } class $MappingStartEvent$ extends FlutterRuntime<MappingStartEvent> { $MappingStartEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "anchor") return runtime.anchor; if (fieldName == "tag") return runtime.tag; if (fieldName == "style") return runtime.style; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) {} MappingStartEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return MappingStartEvent( args['span'], args['style'], anchor: args['anchor'], tag: args['tag'], ); return null; } }// ignore_for_file: implementation_imports, unused_import import 'dart:async'; import 'package:flutter_runtime/flutter_runtime.dart'; import 'package:darty_json_safe/darty_json_safe.dart'; import 'package:yaml/src/event.dart'; class $Event$ extends FlutterRuntime<Event> { $Event$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "type") return runtime.type; if (fieldName == "span") return runtime.span; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } Event? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return Event( args['type'], args['span'], ); return null; } } class $DocumentStartEvent$ extends FlutterRuntime<DocumentStartEvent> { $DocumentStartEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "versionDirective") return runtime.versionDirective; if (fieldName == "tagDirectives") return runtime.tagDirectives; if (fieldName == "isImplicit") return runtime.isImplicit; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } DocumentStartEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return DocumentStartEvent( args['span'], versionDirective: args['versionDirective'], tagDirectives: args['tagDirectives'], isImplicit: args['isImplicit'] ?? true, ); return null; } } class $DocumentEndEvent$ extends FlutterRuntime<DocumentEndEvent> { $DocumentEndEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "isImplicit") return runtime.isImplicit; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } DocumentEndEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return DocumentEndEvent( args['span'], isImplicit: args['isImplicit'] ?? true, ); return null; } } class $AliasEvent$ extends FlutterRuntime<AliasEvent> { $AliasEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "name") return runtime.name; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } AliasEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return AliasEvent( args['span'], args['name'], ); return null; } } class $ScalarEvent$ extends FlutterRuntime<ScalarEvent> { $ScalarEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "anchor") return runtime.anchor; if (fieldName == "tag") return runtime.tag; if (fieldName == "value") return runtime.value; if (fieldName == "style") return runtime.style; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'toString') return runtime.toString(); } ScalarEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return ScalarEvent( args['span'], args['value'], args['style'], anchor: args['anchor'], tag: args['tag'], ); return null; } } class $SequenceStartEvent$ extends FlutterRuntime<SequenceStartEvent> { $SequenceStartEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "anchor") return runtime.anchor; if (fieldName == "tag") return runtime.tag; if (fieldName == "style") return runtime.style; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) {} SequenceStartEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return SequenceStartEvent( args['span'], args['style'], anchor: args['anchor'], tag: args['tag'], ); return null; } } class $MappingStartEvent$ extends FlutterRuntime<MappingStartEvent> { $MappingStartEvent$(super.runtime); @override dynamic getField(String fieldName) { if (fieldName == "span") return runtime.span; if (fieldName == "anchor") return runtime.anchor; if (fieldName == "tag") return runtime.tag; if (fieldName == "style") return runtime.style; if (fieldName == "type") return runtime.type; } @override void setField(String fieldName, dynamic value) {} @override dynamic call(String methodName, [Map args = const {}]) {} MappingStartEvent? createRuntimeInstance( String constructorName, [ Map args = const {}, ]) { if (constructorName == "") return MappingStartEvent( args['span'], args['style'], anchor: args['anchor'], tag: args['tag'], ); return null; } }
全局运行时
// ignore_for_file: implementation_imports, unused_importimport 'package:flutter_runtime/flutter_runtime.dart';import 'package:darty_json_safe/darty_json_safe.dart';import 'package:yaml/src/utils.dart';import 'package:yaml/src/charcodes.dart';import 'package:yaml/yaml.dart';import 'package:yaml/src/equality.dart';import 'package:yaml/src/yaml_node.dart';import 'package:yaml/src/event.dart';import 'package:yaml/src/token.dart';class $GlobalRuntime$ extends FlutterRuntime<dynamic> {$GlobalRuntime$(super.runtime);dynamic call(String methodName, [Map args = const {}]) {if (methodName == 'loadYaml')return loadYaml(args['yaml'],sourceUrl: args['sourceUrl'],recover: args['recover'] ?? false,errorListener: args['errorListener'],);if (methodName == 'loadYamlNode')return loadYamlNode(args['yaml'],sourceUrl: args['sourceUrl'],recover: args['recover'] ?? false,errorListener: args['errorListener'],);if (methodName == 'loadYamlDocument')return loadYamlDocument(args['yaml'],sourceUrl: args['sourceUrl'],recover: args['recover'] ?? false,errorListener: args['errorListener'],);if (methodName == 'loadYamlStream')return loadYamlStream(args['yaml'],sourceUrl: args['sourceUrl'],);if (methodName == 'loadYamlDocuments')return loadYamlDocuments(args['yaml'],sourceUrl: args['sourceUrl'],);if (methodName == 'warn')return warn(args['message'],args['span'],);if (methodName == 'deepEqualsMap') return deepEqualsMap();if (methodName == 'deepEquals')return deepEquals(args['obj1'],args['obj2'],);if (methodName == 'deepHashCode')return deepHashCode(args['obj'],);if (methodName == 'setSpan')return setSpan(args['node'],args['span'],);}@overridegetField(String fieldName) {if (fieldName == 'yamlWarningCallback') return yamlWarningCallback;if (fieldName == '\$plus') return $plus;if (fieldName == '\$minus') return $minus;if (fieldName == '\$dot') return $dot;if (fieldName == '\$0') return $0;if (fieldName == '\$9') return $9;if (fieldName == '\$F') return $F;if (fieldName == '\$N') return $N;if (fieldName == '\$T') return $T;if (fieldName == '\$f') return $f;if (fieldName == '\$n') return $n;if (fieldName == '\$o') return $o;if (fieldName == '\$t') return $t;if (fieldName == '\$x') return $x;if (fieldName == '\$tilde') return $tilde;}@overridevoid setField(String fieldName, value) {if (fieldName == "yamlWarningCallback") yamlWarningCallback = value;}dynamic getEnumValue(String enumName, String constructorName) {if (enumName == "EventType") {if (constructorName == 'streamStart') {return EventType.streamStart;}if (constructorName == 'streamEnd') {return EventType.streamEnd;}if (constructorName == 'documentStart') {return EventType.documentStart;}if (constructorName == 'documentEnd') {return EventType.documentEnd;}if (constructorName == 'alias') {return EventType.alias;}if (constructorName == 'scalar') {return EventType.scalar;}if (constructorName == 'sequenceStart') {return EventType.sequenceStart;}if (constructorName == 'sequenceEnd') {return EventType.sequenceEnd;}if (constructorName == 'mappingStart') {return EventType.mappingStart;}if (constructorName == 'mappingEnd') {return EventType.mappingEnd;}}if (enumName == "TokenType") {if (constructorName == 'streamStart') {return TokenType.streamStart;}if (constructorName == 'streamEnd') {return TokenType.streamEnd;}if (constructorName == 'versionDirective') {return TokenType.versionDirective;}if (constructorName == 'tagDirective') {return TokenType.tagDirective;}if (constructorName == 'documentStart') {return TokenType.documentStart;}if (constructorName == 'documentEnd') {return TokenType.documentEnd;}if (constructorName == 'blockSequenceStart') {return TokenType.blockSequenceStart;}if (constructorName == 'blockMappingStart') {return TokenType.blockMappingStart;}if (constructorName == 'blockEnd') {return TokenType.blockEnd;}if (constructorName == 'flowSequenceStart') {return TokenType.flowSequenceStart;}if (constructorName == 'flowSequenceEnd') {return TokenType.flowSequenceEnd;}if (constructorName == 'flowMappingStart') {return TokenType.flowMappingStart;}if (constructorName == 'flowMappingEnd') {return TokenType.flowMappingEnd;}if (constructorName == 'blockEntry') {return TokenType.blockEntry;}if (constructorName == 'flowEntry') {return TokenType.flowEntry;}if (constructorName == 'key') {return TokenType.key;}if (constructorName == 'value') {return TokenType.value;}if (constructorName == 'alias') {return TokenType.alias;}if (constructorName == 'anchor') {return TokenType.anchor;}if (constructorName == 'tag') {return TokenType.tag;}if (constructorName == 'scalar') {return TokenType.scalar;}}return null;}}// ignore_for_file: implementation_imports, unused_import import 'package:flutter_runtime/flutter_runtime.dart'; import 'package:darty_json_safe/darty_json_safe.dart'; import 'package:yaml/src/utils.dart'; import 'package:yaml/src/charcodes.dart'; import 'package:yaml/yaml.dart'; import 'package:yaml/src/equality.dart'; import 'package:yaml/src/yaml_node.dart'; import 'package:yaml/src/event.dart'; import 'package:yaml/src/token.dart'; class $GlobalRuntime$ extends FlutterRuntime<dynamic> { $GlobalRuntime$(super.runtime); dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'loadYaml') return loadYaml( args['yaml'], sourceUrl: args['sourceUrl'], recover: args['recover'] ?? false, errorListener: args['errorListener'], ); if (methodName == 'loadYamlNode') return loadYamlNode( args['yaml'], sourceUrl: args['sourceUrl'], recover: args['recover'] ?? false, errorListener: args['errorListener'], ); if (methodName == 'loadYamlDocument') return loadYamlDocument( args['yaml'], sourceUrl: args['sourceUrl'], recover: args['recover'] ?? false, errorListener: args['errorListener'], ); if (methodName == 'loadYamlStream') return loadYamlStream( args['yaml'], sourceUrl: args['sourceUrl'], ); if (methodName == 'loadYamlDocuments') return loadYamlDocuments( args['yaml'], sourceUrl: args['sourceUrl'], ); if (methodName == 'warn') return warn( args['message'], args['span'], ); if (methodName == 'deepEqualsMap') return deepEqualsMap(); if (methodName == 'deepEquals') return deepEquals( args['obj1'], args['obj2'], ); if (methodName == 'deepHashCode') return deepHashCode( args['obj'], ); if (methodName == 'setSpan') return setSpan( args['node'], args['span'], ); } @override getField(String fieldName) { if (fieldName == 'yamlWarningCallback') return yamlWarningCallback; if (fieldName == '\$plus') return $plus; if (fieldName == '\$minus') return $minus; if (fieldName == '\$dot') return $dot; if (fieldName == '\$0') return $0; if (fieldName == '\$9') return $9; if (fieldName == '\$F') return $F; if (fieldName == '\$N') return $N; if (fieldName == '\$T') return $T; if (fieldName == '\$f') return $f; if (fieldName == '\$n') return $n; if (fieldName == '\$o') return $o; if (fieldName == '\$t') return $t; if (fieldName == '\$x') return $x; if (fieldName == '\$tilde') return $tilde; } @override void setField(String fieldName, value) { if (fieldName == "yamlWarningCallback") yamlWarningCallback = value; } dynamic getEnumValue(String enumName, String constructorName) { if (enumName == "EventType") { if (constructorName == 'streamStart') { return EventType.streamStart; } if (constructorName == 'streamEnd') { return EventType.streamEnd; } if (constructorName == 'documentStart') { return EventType.documentStart; } if (constructorName == 'documentEnd') { return EventType.documentEnd; } if (constructorName == 'alias') { return EventType.alias; } if (constructorName == 'scalar') { return EventType.scalar; } if (constructorName == 'sequenceStart') { return EventType.sequenceStart; } if (constructorName == 'sequenceEnd') { return EventType.sequenceEnd; } if (constructorName == 'mappingStart') { return EventType.mappingStart; } if (constructorName == 'mappingEnd') { return EventType.mappingEnd; } } if (enumName == "TokenType") { if (constructorName == 'streamStart') { return TokenType.streamStart; } if (constructorName == 'streamEnd') { return TokenType.streamEnd; } if (constructorName == 'versionDirective') { return TokenType.versionDirective; } if (constructorName == 'tagDirective') { return TokenType.tagDirective; } if (constructorName == 'documentStart') { return TokenType.documentStart; } if (constructorName == 'documentEnd') { return TokenType.documentEnd; } if (constructorName == 'blockSequenceStart') { return TokenType.blockSequenceStart; } if (constructorName == 'blockMappingStart') { return TokenType.blockMappingStart; } if (constructorName == 'blockEnd') { return TokenType.blockEnd; } if (constructorName == 'flowSequenceStart') { return TokenType.flowSequenceStart; } if (constructorName == 'flowSequenceEnd') { return TokenType.flowSequenceEnd; } if (constructorName == 'flowMappingStart') { return TokenType.flowMappingStart; } if (constructorName == 'flowMappingEnd') { return TokenType.flowMappingEnd; } if (constructorName == 'blockEntry') { return TokenType.blockEntry; } if (constructorName == 'flowEntry') { return TokenType.flowEntry; } if (constructorName == 'key') { return TokenType.key; } if (constructorName == 'value') { return TokenType.value; } if (constructorName == 'alias') { return TokenType.alias; } if (constructorName == 'anchor') { return TokenType.anchor; } if (constructorName == 'tag') { return TokenType.tag; } if (constructorName == 'scalar') { return TokenType.scalar; } } return null; } }// ignore_for_file: implementation_imports, unused_import import 'package:flutter_runtime/flutter_runtime.dart'; import 'package:darty_json_safe/darty_json_safe.dart'; import 'package:yaml/src/utils.dart'; import 'package:yaml/src/charcodes.dart'; import 'package:yaml/yaml.dart'; import 'package:yaml/src/equality.dart'; import 'package:yaml/src/yaml_node.dart'; import 'package:yaml/src/event.dart'; import 'package:yaml/src/token.dart'; class $GlobalRuntime$ extends FlutterRuntime<dynamic> { $GlobalRuntime$(super.runtime); dynamic call(String methodName, [Map args = const {}]) { if (methodName == 'loadYaml') return loadYaml( args['yaml'], sourceUrl: args['sourceUrl'], recover: args['recover'] ?? false, errorListener: args['errorListener'], ); if (methodName == 'loadYamlNode') return loadYamlNode( args['yaml'], sourceUrl: args['sourceUrl'], recover: args['recover'] ?? false, errorListener: args['errorListener'], ); if (methodName == 'loadYamlDocument') return loadYamlDocument( args['yaml'], sourceUrl: args['sourceUrl'], recover: args['recover'] ?? false, errorListener: args['errorListener'], ); if (methodName == 'loadYamlStream') return loadYamlStream( args['yaml'], sourceUrl: args['sourceUrl'], ); if (methodName == 'loadYamlDocuments') return loadYamlDocuments( args['yaml'], sourceUrl: args['sourceUrl'], ); if (methodName == 'warn') return warn( args['message'], args['span'], ); if (methodName == 'deepEqualsMap') return deepEqualsMap(); if (methodName == 'deepEquals') return deepEquals( args['obj1'], args['obj2'], ); if (methodName == 'deepHashCode') return deepHashCode( args['obj'], ); if (methodName == 'setSpan') return setSpan( args['node'], args['span'], ); } @override getField(String fieldName) { if (fieldName == 'yamlWarningCallback') return yamlWarningCallback; if (fieldName == '\$plus') return $plus; if (fieldName == '\$minus') return $minus; if (fieldName == '\$dot') return $dot; if (fieldName == '\$0') return $0; if (fieldName == '\$9') return $9; if (fieldName == '\$F') return $F; if (fieldName == '\$N') return $N; if (fieldName == '\$T') return $T; if (fieldName == '\$f') return $f; if (fieldName == '\$n') return $n; if (fieldName == '\$o') return $o; if (fieldName == '\$t') return $t; if (fieldName == '\$x') return $x; if (fieldName == '\$tilde') return $tilde; } @override void setField(String fieldName, value) { if (fieldName == "yamlWarningCallback") yamlWarningCallback = value; } dynamic getEnumValue(String enumName, String constructorName) { if (enumName == "EventType") { if (constructorName == 'streamStart') { return EventType.streamStart; } if (constructorName == 'streamEnd') { return EventType.streamEnd; } if (constructorName == 'documentStart') { return EventType.documentStart; } if (constructorName == 'documentEnd') { return EventType.documentEnd; } if (constructorName == 'alias') { return EventType.alias; } if (constructorName == 'scalar') { return EventType.scalar; } if (constructorName == 'sequenceStart') { return EventType.sequenceStart; } if (constructorName == 'sequenceEnd') { return EventType.sequenceEnd; } if (constructorName == 'mappingStart') { return EventType.mappingStart; } if (constructorName == 'mappingEnd') { return EventType.mappingEnd; } } if (enumName == "TokenType") { if (constructorName == 'streamStart') { return TokenType.streamStart; } if (constructorName == 'streamEnd') { return TokenType.streamEnd; } if (constructorName == 'versionDirective') { return TokenType.versionDirective; } if (constructorName == 'tagDirective') { return TokenType.tagDirective; } if (constructorName == 'documentStart') { return TokenType.documentStart; } if (constructorName == 'documentEnd') { return TokenType.documentEnd; } if (constructorName == 'blockSequenceStart') { return TokenType.blockSequenceStart; } if (constructorName == 'blockMappingStart') { return TokenType.blockMappingStart; } if (constructorName == 'blockEnd') { return TokenType.blockEnd; } if (constructorName == 'flowSequenceStart') { return TokenType.flowSequenceStart; } if (constructorName == 'flowSequenceEnd') { return TokenType.flowSequenceEnd; } if (constructorName == 'flowMappingStart') { return TokenType.flowMappingStart; } if (constructorName == 'flowMappingEnd') { return TokenType.flowMappingEnd; } if (constructorName == 'blockEntry') { return TokenType.blockEntry; } if (constructorName == 'flowEntry') { return TokenType.flowEntry; } if (constructorName == 'key') { return TokenType.key; } if (constructorName == 'value') { return TokenType.value; } if (constructorName == 'alias') { return TokenType.alias; } if (constructorName == 'anchor') { return TokenType.anchor; } if (constructorName == 'tag') { return TokenType.tag; } if (constructorName == 'scalar') { return TokenType.scalar; } } return null; } }
备注
目前生成运行时的能力还很弱,比如后续将生成对象整理成注册表。还有其他类型的生成支持,还有将代码转换为可以动态运行的 JSON 文件来运行,包括后续解析运行库来支持闭包,if/for 等。
我非常希望有感兴趣的一起加入这个社区,让 Flutter 动态化的实现方案更多选择,让接入和侵入更低。