如何在编译器动态生成一些代码,实现一些功能?
我们用很多flutter插件时候,会动态生成一些文件,它们是如何实现的?
我自己实现一个简单的json_serializable框架,让你理解flutter中动态生成代码是如何实现的
1
pubspec.yaml里面加入
dev_dependencies
build_runner: ^2.4.8
source_gen: ^1.5.0
2
生成一个注解类,注解类就是@override这种,
要有个const构造方法,主要是写在别的方法或者类上面标注下,让编译器识别,可以执行特殊操作
class JsonAnnotation {
const JsonAnnotation();
}
再新建一个文件test_model 写一个model, model顶部@注解类
import 'package:my_app/builder/zhujie/json_annotation.dart';
@JsonAnnotation()
class TestModel {
String name;
int age;
TestModel(this.name, this.age);
}
3
新建一个json_builder.dart类
这个类就是生成的代码文件名字,以及生成代码逻辑所在,你可以仿照下面逻辑,实现自己的需求
<JsonAnnotation> 就是把有上面注解JsonAnnotation的类都执行下下面生成代码的操作,
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:my_app/builder/zhujie/json_annotation.dart';
import 'package:source_gen/source_gen.dart';
// LibraryBuilder 生成独立的dart文件
Builder testJsonBuilder(BuilderOptions options) =>
LibraryBuilder(JsonBuilder());
class JsonBuilder extends GeneratorForAnnotation<JsonAnnotation> {
@override
generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
if (element is! ClassElement) {
throw InvalidGenerationSource('入参必须是个class', element: element);
}
var className = element.name;
final buffer = StringBuffer();
buffer.writeln('import \'${element.librarySource.shortName}\';');
buffer.writeln('extension ${className}JsonExtension on $className {');
buffer.writeln(' Map<String, dynamic> toJson() {');
buffer.writeln(' final Map<String, dynamic> data = {};');
for (var field in element.fields) {
buffer.writeln(' data[\'${field.name}\'] = ${field.name};');
}
buffer.writeln(' return data;');
buffer.writeln(' }');
buffer.writeln('static fromJson(Map<String, dynamic> json) {');
buffer.writeln(' return $className(');
for (var field in element.fields) {
buffer.writeln(' json[\'${field.name}\'],');
}
buffer.writeln(' );');
buffer.writeln('}');
buffer.writeln(' }');
return buffer.toString();
}
}
4
pubspec.yaml 同级目录新建一个 build.yaml文件,写入执行上面代码配置
配置刚才写的代码路径,入口函数名字testJsonBuilder,把.dart文件生成一个.g.dart文件
这是上面代码执行入口,配置完成后 执行命令就可以运行生成代码逻辑
builders:
testJsonBuilder:
import: "package:my_app/builder/json_builder.dart"
builder_factories: [ "testJsonBuilder" ]
build_extensions: { '.dart': [ '.g.dart' ] }
build_to: source
auto_apply: root_package
5 cd到项目跟目录,命令行执行命令
dart run build_runner build
运行结束就生成了一个test_model.g.dart 文件
里面内容如下,下面内容都是上面第三步写出来的,你可以按照你的需求生产任何代码
import 'test_model.dart';
extension TestModelJsonExtension on TestModel {
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['name'] = name;
data['age'] = age;
return data;
}
static fromJson(Map<String, dynamic> json) {
return TestModel(
json['name'],
json['age'],
);
}
}
6 测试model转json
test() {
TestModel testModel = TestModel('中国', 18);
Map<String, dynamic> map = testModel.toJson();
jdLog('map---$map');
TestModel newModel = TestModelJsonExtension.fromJson(map);
jdLog('newModel---${newModel.name} ${newModel.age}');
}
打印结果如下
flutter: [home_page.dart line:32] map---{name: 中国, age: 18}
flutter: [home_page.dart line:34] newModel---中国 18
说明我们实现了一个简单的json转model插件,复杂功能的话,你自己完善逻辑就好了,demo地址 https://gitee.com/kuaipai/my_app.git