- 3.Java-APT & Dart-APT对比以及 Dart-APT 的特殊性
- 4.Dart-APT Generator 源码浅析
初识 Dart 注解处理以及代码生成
第一节我先带你以最简单的demo,快速认识一下Flutter的注解处理和代码生成的样子,具体的API细节我们放后面细细道来。
Flutter,其实也就是Dart的注解处理依赖于 source_gen。它的详细资料可以在它的 Github 主页查看,这里我们不做过多展开,你只需要知道[ Dart-APT Powered by source_gen]
在Flutter中应用注解以及生成代码仅需一下几个步骤:
- 1.依赖 source_gen
- 2.创建注解
- 3.创建生成器
- 4.创建Builder
- 5.编写配置文件
1.依赖 source_gen
第一步,在你工程的 pubspec.yaml 中引入 source_gen。如果你仅在本地使用且不打算将这个代码当做一个库发布出去:
dev_dependencies:
source_gen:
否则
dependencies:
source_gen:
2.创建注解和使用
比起 java 中的注解创建,Dart 的注解创建更加朴素,没有多余的关键字,实际上只是一个构造方法需要修饰成 const 的普通 Class 。
例如,申明一个没有参数的注解:
class TestMetadata {
const TestMetadata();
}
使用:
@TestMetadata()
class TestModel {}
申明一个有参数的注解:
class ParamMetadata {
final String name;
final int id;
const ParamMetadata(this.name, this.id);
}
使用:
@ParamMetadata(“test”, 1)
class TestModel {}
3.创建生成器
类似 Java-APT 的 Processor ,在 Dart 的世界里,具有相同职责的是 Generator。
你需要创建一个 Generator,继承于 GeneratorForAnnotation, 并实现: generateForAnnotatedElement 方法。
还要在 GeneratorForAnnotation 的泛型参数中填入我们要拦截的注解。
class TestGenerator extends GeneratorForAnnotation {
@override
generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
return “class Tessss{}”;
}
}
返回值是一个 String,其内容就是你将要生成的代码。
你可以通过 generateForAnnotatedElement 方法的三个参数获取注解的各种信息,用来生成相对应的代码。三个参数的具体使用我们后面细讲。
这里我们仅简单的返回一个字符串 “class Tessss{}”,用来看看效果。
4.创建Builder
Generator 的执行需要 Builder 来触发,所以现在我们要创建一个Builder。
非常简单,只需要创建一个返回类型为 Builder 的全局方法即可:
Builder testBuilder(BuilderOptions options) =>
LibraryBuilder(TestGenerator());
方法名随意,重点需要关注的是返回的对象。
示例中我们返回的是 LibraryBuilder 对象,构造方法的参数是我们上一步创建的TestGenerator对象。
实际上根据不同的需求,我们还有其他Builder对象可选,Builder 的继承树:
- Builder
- _Builder
- PartBuilder
- LibraryBuilder
- SharedPartBuilder
- MultiplexingBuilder
PartBuilder 与 SharedPartBuilder 涉及到 dart-part 关键字的使用,这里我们暂时不做展开,通常情况下 LibraryBuilder 已足以满足我们的需求。 MultiplexingBuilder 支持多个Builder的添加。
5.创建配置文件
在项目根目录创建 build.yaml 文件,其意义在于 配置 Builder 的各项参数:
builders:
testBuilder:
import: “package:flutter_annotation/test.dart”
builder_factories: [“testBuilder”]
build_extensions: {“.dart”: [“.g.part”]}
auto_apply: root_package
build_to: source
配置信息的详细含义我们后面解释。重点关注的是,通过 import 和 builder_factories 两个标签,我们指定了上一步创建的 Builder。
6.运行 Builder
命令行中执行命令,运行我们的 Builder
$ flutter packages pub run build_runner build
受限于Flutter 禁止反射的缘故,你不能再像Android中使用编译时注解那样,coding 阶段使用接口,编译阶段生成实现类,运行阶段通过反射创建实现类对象。在Flutter中,你只能先通过命令生成代码,然后再直接使用生成的代码。
可以看到命令还是偏长的,一个可行的建议是将命令封装成一个脚本。
不出意外的话,命令执行成功后将会生成一个新的文件:TestMode