APT
Annotation Processing Tool
注解處理工具
在編譯時(shí)尺碰,掃描處理注解信息
常用于生成代碼,如 Dagger , EventBus , Butter Knife , Data Binding 這些庫(kù)
KAPT
Kotlin Annotation Processing Tool
Kotlin 注解處理工具
kapt 的用法詳見(jiàn) 官方參考文檔
實(shí)踐
參考 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
創(chuàng)建注解
@Retention(RetentionPolicy.CLASS) // 注解保留到字節(jié)碼文件,即編譯期
@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
創(chuàng)建注解處理器
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
目錄下創(chuàng)建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);
}
}
點(diǎn)擊 Make Project ,執(zhí)行編譯
可以看到 Build Output
出現(xiàn)以下輸出
擴(kuò)展
使用 Google 的 auto-service
庫(kù)簡(jiǎn)化 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
目錄
執(zhí)行 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')
}
遇到的一些問(wèn)題
1. 編譯警告 Incremental annotation processing requested
原因
這是 Kotlin 1.3.50 的 bug僚祷,自 1.3.31 起佛致,kapt 支持增量注解處理,詳見(jiàn)官方文檔 和 增量編譯
解決方法
-
版本降級(jí)
使用 1.3.41 或以下版本
-
禁用增量編譯
在項(xiàng)目根目錄下的
gradle.properties
文件中辙谜,添加kapt.incremental.apt=false
2. 編譯警告 unknown enum constant AnnotationTarget.XXX
原因
混編俺榆,編譯時(shí)找不到 Kotlin 的類
解決方法
添加 Kotlin 依賴
dependencies {
...
implementation"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
3. 提示 Kotlin not configured
原因
沒(méi)添加 Kotlin 依賴
解決方法
在 build.gradle
中添加依賴
dependencies {
...
implementation"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
4. 編譯錯(cuò)誤 error: cannot find symbol class XXX
原因
沒(méi)使用 Kotlin 插件
解決方法
在 build.gradle
中添加插件
apply plugin: 'kotlin'
5. Build Output 沒(méi)有打印注解處理器的信息
原因
處理器使用 Kotlin 編寫,而 build.gradle
中使用 annotationProcessor
解決方法
使用 kapt
替換 annotationProcessor
6. 編譯錯(cuò)誤 Annotation processors must be explicitly declared now
原因
注解的定義和處理器在同一個(gè)module中
解決方法
-
按照提示筷弦,可以在
build.gradle
中添加配置肋演,但這種操作已經(jīng)過(guò)期并且之后會(huì)移除,不建議使用android { ... defaultConfig { ... javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true } }
-
分離 注解的定義 和 處理器
如 實(shí)踐 小節(jié)中烂琴,注解的定義為
annotation
module,而處理器為compiler
module