Android 注解器开发流程

如何停止时间:亲吻。
如何时间旅行:阅读。
如何逃脱时间:音乐。
如何感受时间:写作。
如何释放时间:呼吸。

前言

Android使用注解生成器生成Java代码~

  • 官方介绍:添加注释处理器。

接入流程

创建Annotation

关于反射的基础知识可见:第12章 元编程与注解、反射 《Kotlin 项目实战开发》

  • 在Android Studio中创建一个Java Library,名称叫做x_annotation
  • x_annotation的Gradle的配置如下:
apply plugin: 'java-library'
apply plugin: 'kotlin'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

sourceCompatibility = "7"
targetCompatibility = "7"
  • 之后,在Library中定义一些注解。
@Target({METHOD, CONSTRUCTOR})
@Retention(CLASS)
public @interface XAnnotation {
}

创建Compiler

  • 在Android Studio中创建一个Java Library,名称叫做x_compiler

配置Gradle

  • x_compiler的Gradle的配置如下:
apply plugin: 'java-library'
apply plugin: 'kotlin'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // JavaPoet is a Java API for generating .java source files.
    // 源码:https://github.com/square/javapoet
    implementation 'com.squareup:javapoet:1.12.1'
    implementation project(':x_annotation')

    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

sourceCompatibility = "7"
targetCompatibility = "7"

注册Processor

手动注册

  • 创建javax.annotation.processing.Processor
    • 创建文件夹:mkdir -p src/main/resources/META-INF/services/
    • 进入目录:cd src/main/resources/META-INF/services/
    • 创建文件:touch javax.annotation.processing.Processor
    • 在文件中增加Process的包名和类名:com.notzuonotdied.flutter.x_compiler.XCompiler
➜  android git:(master) ✗ tree x_compiler 
super_channel_compiler
├── build.gradle
├── libs
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── notzuonotided
│       │           └── flutter
│       │               └── x_compiler
│       │                   └── XCompiler.kt
│       └── resources
│           └── META-INF
│               └── services
│                   └── javax.annotation.processing.Processor
└── super_channel_compiler.iml

11 directories, 4 files
  • 看看文件的内容:
➜  services git:(master)cat javax.annotation.processing.Processor
com.notzuonotdied.flutter.x_compiler.XCompiler

主动注册

需要在gradle中依赖谷歌提供的库:

compileOnly 'com.google.auto.service:auto-service:1.0-rc5'

在自定义的Processor上增加注解即可。

@AutoService(Processor::class)
class SuperChannelCompiler : AbstractProcessor() {

}

自定义Processor

这里使用了JavaPoet,如果不懂的,可以见这份使用文档:JavaPoet的使用指南。

src/main/java/com/notzuonotdied/flutter/x_compiler/XCompiler.kt的实现如下:

import java.util.*
import java.io.IOException
import javax.annotation.processing.*
import javax.lang.model.element.Modifier
import javax.lang.model.element.TypeElement
import javax.lang.model.util.Elements

import com.squareup.javapoet.JavaFile
import com.squareup.javapoet.TypeSpec

class SuperChannelCompiler : AbstractProcessor() {
    /**
     * 文件相关的辅助类
     */
    private var mFiler: Filer? = null

    /**
     * 元素相关的辅助类
     */
    private var mElementUtils: Elements? = null

    /**
     * 日志相关的辅助类
     */
    private var mMessager: Messager? = null

    /**
     * 这个函数会被注解生成器调用,在这里初始化需要的一些变量
     *
     * @param processingEnvironment
     */
    @Synchronized
    override fun init(processingEnvironment: ProcessingEnvironment) {
        super.init(processingEnvironment)
        mElementUtils = processingEnv.elementUtils
        mMessager = processingEnv.messager
        mFiler = processingEnv.filer
    }

    /**
     * 生成代码
     * */
    override fun process(set: Set<TypeElement?>, roundEnvironment: RoundEnvironment): Boolean {
        val finderClass = TypeSpec.classBuilder("XGeneratedClass")
                .addModifiers(Modifier.PUBLIC)
                .build()
        try {
            JavaFile.builder("com.notzuonotdied.flutter.x_compile", finderClass)
                    .addFileComment("Generated code from x_compile Do not modify!")
                    .build()
                    .writeTo(mFiler)
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return true
    }

    /**
     * 责任链模式:用于判断这个是否由该注解生成器处理
     */
    override fun getSupportedAnnotationTypes(): Set<String> {
        val types: MutableSet<String> = LinkedHashSet()
        types.add(XAnnotation::class.java.canonicalName)
        return types
    }
}

使用

在主工程的Gradle中配置如下:

dependencies {
    implementation project(":x_annotation")
    annotationProcessor project(":x_compiler")
}

在主工程中使用x_annotation定义的注解,点击编译即可。编译完成后,可以在工程下的/build/app/generated/ap_generated_sources/debug/out/com/notzuonotdied/flutter/x_compile目录看到我们生成的类XGeneratedClass,文件内容如下:

// Generated code from x_compile Do not modify!
package com.notzuonotdied.flutter.x_compile;

public class XGeneratedClass {
}
  • 大功告成,_

支持Kotlin

在Butter Knife中可以看到一句话,If you are using Kotlin, replace annotationProcessor with kapt。我们的注解器也一样,如果要支持Kotlin,也需要使用kapt。在主工程的Gradle中配置如下:

apply plugin: 'kotlin-kapt'

dependencies {
    implementation project(":x_annotation")
    kapt project(":x_compiler")

    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

注意: 如果你不使用kapt,那么你的RoundEnvironment中是找不到kclass的。即没办法找到Kotlin的class文件。

JavaPoet使用教程

  • JavaPoet的基本使用
  • JavaPoet的使用指南
  • Android编译时代码生成之二(javapoet)
  • JavaPoet 看这一篇就够了

附录

  • Android 学习使用annotationprocessor自动生成java文件
  • Java注解解析-搭建自己的注解处理器(CLASS注解使用篇)
  • JavaPoet is a Java API for generating .java source files.
  • Java Annotation Processor 小记

Github

  • KotlinPoet
  • JavaPoet

你可能感兴趣的:(Android进阶)