APT
Annotation Processing Tool
注解处理工具
在编译时,扫描处理注解信息
常用于生成代码,如 Dagger , EventBus , Butter Knife , Data Binding 这些库
KAPT
Kotlin Annotation Processing Tool
Kotlin 注解处理工具
kapt 的用法详见 官方参考文档
实践
参考 EventBus 和 Butter Knife
1. 新建 Module annotation
,类型为 Java Library
build.gradle
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
创建注解
@Retention(RetentionPolicy.CLASS) // 注解保留到字节码文件,即编译期
@Target(ElementType.TYPE) // 可作用于类、接口(包括注解)、枚举上
public @interface Function {
String name() default "";
}
2. 新建 Module compiler
,类型为 Java Library
build.gradle
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':annotation')
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
创建注解处理器
public class FunctionAnnotationProcessor extends AbstractProcessor {
private Messager mMessager;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mMessager = processingEnvironment.getMessager();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Function.class);
for (Element element : elements) {
mMessager.printMessage(Diagnostic.Kind.WARNING, "find element: " + element.getSimpleName());
}
return false;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
types.add(Function.class.getName());
return types;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}
添加 SPI (Service Provider Interface) 配置文件
- 在
main
目录下创建resources/META-INF/services
目录,新建javax.annotation.processing.Processor
文件
-
在该文件中添加注解处理器的完整类名
me.jack.compiler.FunctionAnnotationProcessor
3. 在 Application Module 中使用注解
build.gradle
...
dependencies {
...
implementation project(':annotation')
annotationProcessor project(':compiler')
}
添加注解到类上
@Function(name = "Home")
public class HomeActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
}
}
点击 Make Project ,执行编译
可以看到 Build Output
出现以下输出
扩展
使用 Google 的 auto-service
库简化 SPI 配置文件操作
在 compiler
module 的 build.gradle
添加依赖
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
在 FunctionAnnotationProcessor
类添加注解
@AutoService(Processor.class)
public class FunctionAnnotationProcessor extends AbstractProcessor {
...
}
删除 resources
目录
执行 Build
-> Rebuild Project
操作
依然可以看到输出
find element: HomeActivity
使用 Kotlin 编写
需要在 build.gradle
中添加 Kotlin 依赖,并使用 kapt
替换 annotationProcessor
Module compiler 的 build.gradle
文件如下
apply plugin: 'java-library'
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation project(':annotation')
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
kapt 'com.google.auto.service:auto-service:1.0-rc4'
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
Application Module 如果使用注解的类是 Kotlin 编写,则需要在 build.gradle
同样使用 kapt
替换 annotationProcessor
,否则处理器扫描不到该类
...
dependencies {
...
implementation project(':annotation')
kapt project(':compiler')
}
遇到的一些问题
1. 编译警告 Incremental annotation processing requested
原因
这是 Kotlin 1.3.50 的 bug,自 1.3.31 起,kapt 支持增量注解处理,详见官方文档 和 增量编译
解决方法
-
版本降级
使用 1.3.41 或以下版本
-
禁用增量编译
在项目根目录下的
gradle.properties
文件中,添加kapt.incremental.apt=false
2. 编译警告 unknown enum constant AnnotationTarget.XXX
原因
混编,编译时找不到 Kotlin 的类
解决方法
添加 Kotlin 依赖
dependencies {
...
implementation"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
3. 提示 Kotlin not configured
原因
没添加 Kotlin 依赖
解决方法
在 build.gradle
中添加依赖
dependencies {
...
implementation"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
4. 编译错误 error: cannot find symbol class XXX
原因
没使用 Kotlin 插件
解决方法
在 build.gradle
中添加插件
apply plugin: 'kotlin'
5. Build Output 没有打印注解处理器的信息
原因
处理器使用 Kotlin 编写,而 build.gradle
中使用 annotationProcessor
解决方法
使用 kapt
替换 annotationProcessor
6. 编译错误 Annotation processors must be explicitly declared now
原因
注解的定义和处理器在同一个module中
解决方法
-
按照提示,可以在
build.gradle
中添加配置,但这种操作已经过期并且之后会移除,不建议使用android { ... defaultConfig { ... javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true } }
-
分离 注解的定义 和 处理器
如 实践 小节中,注解的定义为
annotation
module,而处理器为compiler
module