寫一個自定義Android Java編譯時注解失敗了躺同,但是學(xué)到了點東西

Android 寫annotation 的文章汗牛充棟。但是有些坑沒明白聘惦。這里記一下某饰。

需求

想定義一個UniTag, 自動生成 TAG的定義, 結(jié)果失敗了

@UniTag(name="MYMODULE")
public class MainActivity extends AppCompatActivity {
    //想自動生成以下代碼
    //private static final String TAG = "...";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

原因是,光靠Java annotation恐怕不行善绎,還得寫IDEA(Android Studio)插件黔漂,就跟開源lombok庫類似。

代碼結(jié)構(gòu)

image.png

請注意 定義要放在java module(一定不是Android module) mylibrary (網(wǎng)上有人起名myannotation的)

而自定義的繼承自AbstractProcessor是放在mycompile里的禀酱。

然后看mycomplie的build.gradle

//mycompile module 's build.gradle
apply plugin: 'java-library'
//apply plugin: 'kotlin'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    //google autoservice
    implementation 'com.google.auto.service:auto-service:1.0-rc6'
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'

    implementation project(path: ':mylibrary')

    implementation 'com.squareup:javapoet:1.8.0'
    implementation 'com.google.guava:guava:19.0'

    sourceCompatibility = "1.8"
    targetCompatibility = "1.8"
}

再看mylibrary的build.gradle

//mylibrary module's build.gradle
apply plugin: 'java-library'
apply plugin: 'maven'

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

}

sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8

再看 app的build.gradle

//app's build.grale
apply plugin: 'com.android.application'

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "cn.zhuguangsheng.unitagutildemo"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    compileOnly project(':mylibrary')
    annotationProcessor project(':mycompile')

}

最后看整個工程的build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
//    ext {
//        kotlin_version = '1.3.72'
//    }
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.2"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        //替換成最新android-apt版本
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        //classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

接下來看源碼

定義注解

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface UniTag {
    String name() default "";
}

定義Processor

@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
    private Messager messager; // Log 日志
    private Elements elementUtils; // 操作Element工具類
    private Filer filer; // 支持通過注解處理器創(chuàng)建新文件
    private Map<String, String> options; // 額外配置參數(shù)

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
        elementUtils = processingEnv.getElementUtils();
        filer = processingEnv.getFiler();
        options = processingEnv.getOptions();

    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(UniTag.class.getCanonicalName());
        return types;
    }
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //Set<? extends Element> routerElements = roundEnv.getElementsAnnotatedWith(TrackName.class);

        messager.printMessage(Diagnostic.Kind.NOTE, "正在process");

        try {

            Collection<? extends Element> annotatedElements =
                    roundEnv.getElementsAnnotatedWith(UniTag.class);

            //for (TypeElement te : annotations) {
                for (Element element : annotatedElements) {
                    if (element.getKind() == ElementKind.CLASS) {
                        // 顯示轉(zhuǎn)換元素類型
                        TypeElement typeElement = (TypeElement) element;
                        // 輸出元素名稱
                        messager.printMessage(Diagnostic.Kind.NOTE,typeElement.getSimpleName());
                        System.out.println(typeElement.getSimpleName());
                        // 輸出注解屬性值
                        messager.printMessage(Diagnostic.Kind.NOTE,typeElement.getAnnotation(UniTag.class).name());
                        System.out.println(typeElement.getAnnotation(UniTag.class).name());

                        //這塊沒完成炬守,只是隨便寫了個文件,難證效果剂跟,請看網(wǎng)上其它的例子
                        String fName = TypeUtil.packageNameOf(typeElement)+ "." + typeElement.getClass().getSimpleName();
                        messager.printMessage(Diagnostic.Kind.NOTE, "fName=" + fName);
                        JavaFileObject source = processingEnv.getFiler().createSourceFile(fName);
                        Writer writer = source.openWriter();
                        writer.write("http://hello hello");
                        writer.flush();
                        writer.close();
                    }
                }
        } catch (Exception e) {
            e.printStackTrace();
            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
        }

        return true;
    }


}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劳较,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子浩聋,更是在濱河造成了極大的恐慌,老刑警劉巖臊恋,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衣洁,死亡現(xiàn)場離奇詭異,居然都是意外死亡抖仅,警方通過查閱死者的電腦和手機(jī)坊夫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撤卢,“玉大人环凿,你說我怎么就攤上這事》欧裕” “怎么了智听?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我到推,道長考赛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任莉测,我火速辦了婚禮颜骤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捣卤。我一直安慰自己忍抽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布董朝。 她就那樣靜靜地躺著鸠项,像睡著了一般。 火紅的嫁衣襯著肌膚如雪益涧。 梳的紋絲不亂的頭發(fā)上锈锤,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機(jī)與錄音闲询,去河邊找鬼久免。 笑死,一個胖子當(dāng)著我的面吹牛扭弧,可吹牛的內(nèi)容都是我干的阎姥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鸽捻,長吁一口氣:“原來是場噩夢啊……” “哼呼巴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起御蒲,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤衣赶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后厚满,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體府瞄,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年碘箍,在試婚紗的時候發(fā)現(xiàn)自己被綠了遵馆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡丰榴,死狀恐怖货邓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情四濒,我是刑警寧澤换况,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布职辨,位于F島的核電站,受9級特大地震影響复隆,放射性物質(zhì)發(fā)生泄漏拨匆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一挽拂、第九天 我趴在偏房一處隱蔽的房頂上張望惭每。 院中可真熱鬧,春花似錦亏栈、人聲如沸台腥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽黎侈。三九已至,卻和暖如春闷游,著一層夾襖步出監(jiān)牢的瞬間峻汉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工脐往, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留休吠,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓业簿,卻偏偏與公主長得像瘤礁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子梅尤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容