天天看點

基于Kotlin實作注解生成器(Annotation Processor)APTAnnotationProcessorAnnotationProcessor和Provided差別用Kotlin實作一個簡單的Processor demo

随着一些使用注解生成器(annotationProcessor)的架構的流行,例如ButterKnife、dagger2、EventBus 3.0。我需要了解注解生成器的相關知識。

APT

APT(Annotation Processing Tool)是一種處理注解的工具,它對源代碼檔案進行檢測,找出其中的Annotation。根據注解自動生成代碼。Annotation處理器在處理Annotation時可以根據源檔案中的Annotation生成額外的源檔案和其他的檔案(檔案具體的内容由Annotation處理器的編寫者決定),APT還會編譯生成源檔案和原來的源檔案,将它們一起生成class檔案。

APT工作流程

  1. 定義注解(@XXXX)
  2. APT掃描代碼中的注解
  3. APT依據定義好的注解處理方式進行操作,生成.java檔案
  4. build工程,生成.class檔案

AnnotationProcessor

AnnotationProcessor是APT工具中的一種,是google開發的内置架構,不需要引入,可以直接在build.gradle檔案中使用:

dependencies {
     annotationProcessor project(':xx')
     annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}
           

AnnotationProcessor和Provided差別

  • AnnotationProcessor隻在編譯的時候執行依賴的庫,但是庫最終不打包到apk中,編譯庫中的代碼沒有直接使用的意義,也沒有提供開放的api調用,最終的目的是得到編譯庫中生成的檔案,供我們調用
  • Provided雖然也是編譯時執行,最終不會打包到apk中,但是跟

    AnnotationProcessor

    有着根本的不同。
A、B、C都是Library
A依賴了C,B也依賴了C
App需要同時使用A、B、C
那麼其中A(或者B)可以修改與C的依賴關系為Provided
           

由于App使用的aar依賴,是以A、B、C都要編譯生成aar,最終會和app一起打包生成apk,但是A、B在編譯時又需要依賴C,那麼就需要

Provided

了,

Provided

隻是確定A、B成功編譯生成aar,并不把C編譯進A和B。

Provided

起到了避免依賴重複資源的作用。

由于gradle版本問題,在使用注解生成器還是有差別的,具體看以看這篇文章

用Kotlin實作一個簡單的Processor demo

  • 新增一個Java Library Module,這裡需要注意的是Java Library 不是Android Library。然後在建立一個AptCreate
@Target(AnnotationTarget.CLASS) // 作用在類上
@Retention(AnnotationRetention.RUNTIME) // 存活時間是運作時
annotation class AptCreate
           
  • 再新增一個Java Library Module,這裡同樣是Java Library,配置

    build.gradle

    ,下面是代碼。
apply plugin: 'java-library'
apply plugin: 'kotlin'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':aptlib')
    compile 'com.squareup:javapoet:1.9.0'
    compile "org.jetbrains.kotlin:kotlin-stdlib:1.2.21"
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"
           
  • aptprocessor Library

    中建立AptTestProcess類。
class AptTestProcess : AbstractProcessor() {

    override fun getSupportedAnnotationTypes(): Set<String> {
        val types = LinkedHashSet<String>()
        types.add(AptCreate::class.java.canonicalName)
        return types
    }

    override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment?): Boolean {
        //TODO("not implemented")
        // To change body of created functions use File | Settings | File Templates.
        System.out.println("======>start")

        /**
         * 定義了方法
         */
        val main = MethodSpec.methodBuilder("printHello")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                .returns(Void.TYPE)
                .addParameter(Array<String>::class.java, "args")
                .addStatement("\$T.out.println(\$S)", System::class.java, "Hello, Kotlin!")
                .build()

        /**
         * 定義類
         */
        val helloWorld = TypeSpec.classBuilder("HelloWorld")
                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                .addMethod(main)
                .build()

        /**
         * 定義包名
         */
        val javaFile = JavaFile.builder("com.knight.apt", helloWorld)
                .build()

        try {
            javaFile.writeTo(processingEnv.filer)
        } catch (e: IOException) {
            e.printStackTrace()
        }
        System.out.println("=======>end")
        return false
    }
}
           
  • 自定義注解類的使用,在在其他Library中添加對

    aptlib

    aptprocess

    的依賴,在代碼中這樣使用
@AptCreate
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}
           
  • Module

    的build.gradle代碼如下:
apply plugin: 'com.android.application'

android {
    compileSdkVersion 
    defaultConfig {
        applicationId "com.knight.apt"
        minSdkVersion 
        targetSdkVersion 
        versionCode 
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'

    //這兩行是主要的
    compile project(':aptlib')
    annotationProcessor project(':aptprocess')
}
           
  • 編譯工程,在

    build/generated/source/apt/debug

    下就能找到生成的類,如下圖:
基于Kotlin實作注解生成器(Annotation Processor)APTAnnotationProcessorAnnotationProcessor和Provided差別用Kotlin實作一個簡單的Processor demo

遇到的坑

  • 這裡遇到第一個坑,因為用的是

    Kotlin

    ,使用

    auto-service

    一直不生效,是以這裡使用了

    META-INF/services/javax.annotation.processing.Processor

    ,并加上:
  • 遇到的第二個坑,在使用的時候需要使用Java類,不能使用Kotlin來使用自定義注解。否則不會自動生成相應的代碼。

源碼下載下傳