美文网首页
写一个自定义Android Java编译时注解失败了,但是学到了

写一个自定义Android Java编译时注解失败了,但是学到了

作者: 青岛大桥_Android到后端 | 来源:发表于2021-04-20 13:33 被阅读0次

Android 写annotation 的文章汗牛充栋。但是有些坑没明白。这里记一下。

需求

想定义一个UniTag, 自动生成 TAG的定义, 结果失败了

@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库类似。

代码结构

image.png

请注意 定义要放在java module(一定不是Android module) mylibrary (网上有人起名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; // 支持通过注解处理器创建新文件
    private Map<String, String> options; // 额外配置参数

    @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) {
                        // 显示转换元素类型
                        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());

                        //这块没完成,只是随便写了个文件,难证效果,请看网上其它的例子
                        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("//hello hello");
                        writer.flush();
                        writer.close();
                    }
                }
        } catch (Exception e) {
            e.printStackTrace();
            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
        }

        return true;
    }


}

相关文章

网友评论

      本文标题:写一个自定义Android Java编译时注解失败了,但是学到了

      本文链接:https://www.haomeiwen.com/subject/ofcnlltx.html