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

主動註冊

在自定義的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使用教程

附錄

Github

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章