美文网首页Android精选程序员Android开发经验谈
AndroidStudio 配置 AspectJ 环境实现AOP

AndroidStudio 配置 AspectJ 环境实现AOP

作者: 皮卡搜 | 来源:发表于2018-01-29 09:12 被阅读456次

    昨天看了一段android配置aspectj实现AOP的直播视频,就试着自己配置了一下,可能是因为我自己的AndroidStudio环境的问题,碰到了不少的坑(其实还是因为对gradle理解的不多),但总归是配置好了,就分享一下。

    试了两种方式,不过项目下的build.gradle,没什么变化,直接看一下代码吧:
    build.gradle(项目下)

    buildscript {
        ext {
            //android appcompat支持库版本
            androidSupportVersion = '26.1.0'
            //编译的 SDK 版本,如API20
            compileSdkVersion = 26
            //构建工具的版本,其中包括了打包工具aapt、dx等,如API20对应的build-tool的版本就是20.0.0
            buildToolsVersion = "26.0.2"
            //兼容的最低 SDK 版本
            minSdkVersion = 15
            //向前兼容,保存新旧两种逻辑,并通过 if-else 方法来判断执行哪种逻辑
            targetSdkVersion = 26
            //kotlin版本号
            kotlin_version = '1.2.10'
    
            kotlinVersion = "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
            appcompatV7 = "com.android.support:appcompat-v7:$androidSupportVersion"
            appcompatDesign = "com.android.support:design:$androidSupportVersion"
            constraintLayout = 'com.android.support.constraint:constraint-layout:1.0.2'
        }
        repositories {
            google()
            jcenter()
            mavenCentral()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:3.0.1'
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
            classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1'
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
            classpath 'org.aspectj:aspectjtools:1.8.13'
            classpath 'org.aspectj:aspectjweaver:1.8.13'
        }
    
    }
    
    allprojects {
        repositories {
            google()
            jcenter()
            mavenCentral()
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
    

    看着一大堆,主要就是下面这几行配置,其他的是我自己项目中用到的,根据自己需要配置就行。

    buildscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'org.aspectj:aspectjtools:1.8.13'
            classpath 'org.aspectj:aspectjweaver:1.8.13'
        }
    }
    
    repositories {
        mavenCentral()
    }
    

    其实这几行配置在app的build.gradle里也是可以的,但是因为项目下的build.gradle里已经有buildscript {}、allprojects {repositories{} },就配置在这里了。

    然后有两种配置方式:

    第一种
    只有一个主Module app的情况下,配置app的build.gradle:

    apply plugin: 'com.android.application'
    
    apply plugin: 'kotlin-android'
    
    apply plugin: 'kotlin-android-extensions'
    
    apply plugin: 'org.greenrobot.greendao'
    
    android {
        compileSdkVersion rootProject.ext.compileSdkVersion
        buildToolsVersion rootProject.ext.buildToolsVersion
        defaultConfig {
            applicationId "填入自己的applicationId"
            minSdkVersion rootProject.ext.minSdkVersion
            targetSdkVersion rootProject.ext.targetSdkVersion
            versionCode 1
            versionName "1.0"
            //Lambda配置
    //        jackOptions.enabled = true
    //        android.compileOptions.sourceCompatibility 1.8
            buildConfigField "boolean", "LOG", "true"// 显示Log
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            //支持矢量图
            vectorDrawables.useSupportLibrary = true
            ndk {
                //选择要添加的对应cpu类型的.so库。
                abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64', 'mips', 'mips64'
            }
        }
    
        buildTypes {
            release {
                minifyEnabled false
                buildConfigField "boolean", "LOG", "false"// 显示Log
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
    
    
        }
    
        //Lambda配置
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    
        dataBinding {
            enabled true
        }
    
        greendao {
            schemaVersion 1//数据库版本号
            daoPackage 'com.test.qby.newtestapplication.greendao'//设置DaoMaster、DaoSession、Dao包名
            targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录
            //targetGenDirTest:设置生成单元测试目录
            //generateTests:设置自动生成单元测试用例
        }
    
        lintOptions {
            abortOnError true
        }
    
    }
    
    
    dependencies {
        implementation fileTree(include: ['*.jar'], dir: 'libs')
        implementation rootProject.ext.kotlinVersion
        implementation rootProject.ext.appcompatV7
        implementation rootProject.ext.constraintLayout
        compile rootProject.ext.appcompatDesign
        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 'jp.wasabeef:glide-transformations:3.0.1'
        // If you want to use the GPU Filters
        compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1'
        //腾讯bugly
        compile 'com.tencent.bugly:crashreport:latest.release'
        compile 'com.tencent.bugly:nativecrashreport:latest.release'
        //retrofit
        compile 'com.squareup.retrofit2:retrofit:2.3.0'
        compile 'com.squareup.retrofit2:converter-gson:2.3.0'
        compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
        compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'
        //rxJava
        compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
        // Because RxAndroid releases are few and far between, it is recommended you also
        // explicitly depend on RxJava's latest version for bug fixes and new features.
        compile 'io.reactivex.rxjava2:rxjava:2.1.8'
        //greenDao
        compile 'org.greenrobot:greendao:3.2.0'
        //换肤功能
        compile 'com.zhy:changeskin:4.0.2'
        //AOP面向切面编程,加入这行就不用在libs下引入jar包了,不然要写成compile file(libs/aspectjrt.jar)
        compile 'org.aspectj:aspectjrt:1.8.13'
    }
    /*
    //在项目下配置了,此处就不需要了
    buildscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'org.aspectj:aspectjtools:1.8.13'
            classpath 'org.aspectj:aspectjweaver:1.8.13'
        }
    }
    
    repositories {
        mavenCentral()
    }
    */
    
    import org.aspectj.bridge.IMessage
    import org.aspectj.bridge.MessageHandler
    import org.aspectj.tools.ajc.Main
    
    final def log = project.logger
    final def variants = project.android.applicationVariants
    
    variants.all { variant ->
        if (!variant.buildType.isDebuggable()) {
            log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
            return
        }
    
        JavaCompile javaCompile = variant.javaCompile
        javaCompile.doLast {
            String[] args = ["-showWeaveInfo",
                             "-1.5",
                             "-inpath", javaCompile.destinationDir.toString(),
                             "-aspectpath", javaCompile.classpath.asPath,
                             "-d", javaCompile.destinationDir.toString(),
                             "-classpath", javaCompile.classpath.asPath,
                             "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
            log.debug "ajc args: " + Arrays.toString(args)
    
            MessageHandler handler = new MessageHandler(true)
            new Main().run(args, handler)
            for (IMessage message : handler.getMessages(null, true)) {
                switch (message.getKind()) {
                    case IMessage.ABORT:
                    case IMessage.ERROR:
                    case IMessage.FAIL:
                        log.error message.message, message.thrown
                        break
                    case IMessage.WARNING:
                        log.warn message.message, message.thrown
                        break
                    case IMessage.INFO:
                        log.info message.message, message.thrown
                        break
                    case IMessage.DEBUG:
                        log.debug message.message, message.thrown
                        break
                }
            }
        }
    }
    
    

    这一个gradle主要的东西就是这些:

    //AOP面向切面编程,加入这行就不用在libs下引入jar包了,不然要写成compile file(libs/aspectjrt.jar)
    compile 'org.aspectj:aspectjrt:1.8.13'
    
    import org.aspectj.bridge.IMessage
    import org.aspectj.bridge.MessageHandler
    import org.aspectj.tools.ajc.Main
    
    final def log = project.logger
    final def variants = project.android.applicationVariants
    
    variants.all { variant ->
        if (!variant.buildType.isDebuggable()) {
            log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
            return
        }
    
        JavaCompile javaCompile = variant.javaCompile
        javaCompile.doLast {
            String[] args = ["-showWeaveInfo",
                             "-1.5",
                             "-inpath", javaCompile.destinationDir.toString(),
                             "-aspectpath", javaCompile.classpath.asPath,
                             "-d", javaCompile.destinationDir.toString(),
                             "-classpath", javaCompile.classpath.asPath,
                             "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
            log.debug "ajc args: " + Arrays.toString(args)
    
            MessageHandler handler = new MessageHandler(true)
            new Main().run(args, handler)
            for (IMessage message : handler.getMessages(null, true)) {
                switch (message.getKind()) {
                    case IMessage.ABORT:
                    case IMessage.ERROR:
                    case IMessage.FAIL:
                        log.error message.message, message.thrown
                        break
                    case IMessage.WARNING:
                        log.warn message.message, message.thrown
                        break
                    case IMessage.INFO:
                        log.info message.message, message.thrown
                        break
                    case IMessage.DEBUG:
                        log.debug message.message, message.thrown
                        break
                }
            }
        }
    }
    

    下面那一堆是用命令在编译最后做一些关联的,具体的我也不懂,只管加上好了。

    第二种
    有多个module都需要用到aspectj,特别是组件开发的情况下,不可能每个module都配置一下,所以就需要新建一个aspectj的module作为项目的library。
    app下build.gradle需要修改:

    //AOP面向切面编程,加入这行就不用在libs下引入jar包了,不然要写成compile file(libs/aspectjrt.jar)
    compile 'org.aspectj:aspectjrt:1.8.13'
    

    去掉,改为

    implementation project(':aspectjlib')
    

    不过上面这句在你添加module依赖的时候会自动生成。

    新建library的build.gradle配置如下:

    apply plugin: 'com.android.library'
    
    android {
        compileSdkVersion rootProject.ext.compileSdkVersion
        buildToolsVersion rootProject.ext.buildToolsVersion
        defaultConfig {
            minSdkVersion rootProject.ext.minSdkVersion
            targetSdkVersion rootProject.ext.targetSdkVersion
            versionCode 1
            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 rootProject.ext.appcompatV7
        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'
        //AOP
        compile 'org.aspectj:aspectjrt:1.8.13'
    }
    
    import org.aspectj.bridge.IMessage
    import org.aspectj.bridge.MessageHandler
    import org.aspectj.tools.ajc.Main
    
    android.libraryVariants.all { variant ->
        JavaCompile javaCompile = variant.javaCompile
        javaCompile.doLast {
            String[] args = ["-showWeaveInfo",
                             "-1.5",
                             "-inpath", javaCompile.destinationDir.toString(),
                             "-aspectpath", javaCompile.classpath.asPath,
                             "-d", javaCompile.destinationDir.toString(),
                             "-classpath", javaCompile.classpath.asPath,
                             "-bootclasspath", android.bootClasspath.join(
                    File.pathSeparator)]
    
            MessageHandler handler = new MessageHandler(true)
            new Main().run(args, handler)
    
            def log = project.logger
            for (IMessage message : handler.getMessages(null, true)) {
                switch (message.getKind()) {
                    case IMessage.ABORT:
                    case IMessage.ERROR:
                    case IMessage.FAIL:
                        log.error message.message, message.thrown
                        break
                    case IMessage.WARNING:
                    case IMessage.INFO:
                        log.info message.message, message.thrown
                        break
                    case IMessage.DEBUG:
                        log.debug message.message, message.thrown
                        break
                }
            }
        }
    }
    

    注意:下面那一堆跟app的gradle中的稍微有点区别,一个是module,一个是library,gradle中的东西不一样。

    两种配置方式基本就是这样了,使用方法我也是刚了解一点,记录一下简单的计算性能的用法吧
    自定义注解类:

    package com.test.qby.aspectjlib.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * Created by qby on 2018/1/26 0026.
     * 自定义注解
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface IFirstAnnotation {
        String value();
    }
    

    @Target 注解目标,表示注解使用在什么地方,这里是METHOD方法;@Retention 保留策略,表示注解调用时机,这里RUNTIME运行时

    切面类

    import android.widget.Toast;
    
    import com.test.qby.aspectjlib.annotation.IFirstAnnotation;
    import com.test.qby.newtestapplication.app.MyApplication;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.TypeVariable;
    import java.util.Locale;
    
    /**
     * Created by qby on 2018/1/26 0026.
     * 自定义注解行为
     */
    @Aspect
    public class MethodBehaviorAspect {
        private static final String TAG = "aspect_aby";
    
        @Pointcut("execution(@com.test.qby.aspectjlib.annotation.IFirstAnnotation * *(..))")
        public void firstMethodAnnotationBehavior() {
        }
    
        @Pointcut("execution(* com.test.qby.newtestapplication.ui.MainActivity.aspectClick(android.view.View))")
        public void secondMethodAnnotationBehavior() {
        }
    
        @Around("firstMethodAnnotationBehavior()")
        public Object wavePointcutAround(ProceedingJoinPoint joinPoint) throws Throwable {
    
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            // 类名
            String className = methodSignature.getDeclaringType().getSimpleName();
            // 方法名
            String methodName = methodSignature.getName();
            // 功能名
            IFirstAnnotation behaviorTrace = methodSignature.getMethod()
                    .getAnnotation(IFirstAnnotation.class);
            String value = behaviorTrace.value();
    //        String value = "点击";
            long start = System.currentTimeMillis();
            Object result = joinPoint.proceed();
            long duration = System.currentTimeMillis() - start;
            Log.e(TAG, String.format("%s类中%s方法执行%s功能,耗时:%dms", className, methodName, value, duration));
            Toast.makeText(MyApplication.getContext(), String.format(Locale.CHINESE, "%s类中%s方法执行%s功能,耗时:%dms", className, methodName, value, duration), Toast.LENGTH_SHORT).show();
            return result;
        }
    }
    

    @Aspect指定切面类;@Pointcut切入点;@Around是切入方式Advice的一种,表示在切入点前后插入代码,还有@Before、@After;Pointcut语法,execution,表示根据Advice在执行方法内部代码前后插入代码,call,表示根据Advice在调用方法前后插入代码......

    页面调用

    @IFirstAnnotation("测试Aspect")
    public void aspectClick(View view) {
         try {
             Thread.sleep(new Random().nextInt(1000));
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     }
    

    @IFirstAnnotation调用注解,()内部为在IFirstAnnotation中写的value的值,去掉value()后此处去掉()
    注意:在MethodBehaviorAspect 类中如果有用到Context,可直接使用joinPoint.getTarget()类型转换成Context,这里是由于项目使用了databinding,部分getTarget()获取到的值不能强转为Context,所以这里用的MyApplication获取的Context

    这只是个人的初步尝试,里面当然还有很多内容需要去学,刚看了CSDN上有人写的几篇关于AOP的内容,都挺详细的,给出其中一个地址,自己看吧:http://blog.csdn.net/xwh_1230/article/details/78225258

    相关文章

      网友评论

      • 明朗__:多模块开发 是不是每个模块都要引用 这个aop 库
      • etrnel:打包出来的正式包试过吗?我试着正式的不管用,debug版的倒是起作用:sob:
        996d0e774a5a:if (!variant.buildType.isDebuggable()) {
        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return
        }

        把这段去掉,或者设置为false。这段表示只在debug模式下有用
        皮卡搜:这个还真不清楚,之前写的时候就是自己写了个demo尝试了一下,没有打正式包:flushed: ,有时间再试一下
        etrnel:Androidstudio 3.0.1 gradle 4.1。如果是2.3.3的话倒是都起作用
      • Random92:你好,我按照你的写法的确实现了切面,但是仅限于在Java代码中,请问你有没有实现在Kotlin代码中使用Aspectj
        皮卡搜:@Random92 查阅了一下,Aspectj不支持Kotlin,github上有个aspectjx支持,你有时间的话,可以试试:https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx
        Random92:@皮卡搜 恩恩,我试过是不能在Kotlin中使用的,正纠结问题出在哪里。。。
        皮卡搜:没用上就没改在kotlin中使用,有时间可以试试
      • 吹泡泡的鱼_ac4e:你好,我按照你写的今天折腾了一天,但是import org.aspect.一直报错,我的org里面没有aspect,我也不太清楚怎么回事,你是看的什么视频,方便分享吗,感激不尽
        皮卡搜:@吹泡泡的鱼_ac4e 在build.gradle中:添加依赖后同步一下,再写下面的那一堆,import org.要手动写,点后面才会有输入提示,这三句导包的你直接复制好了。
        吹泡泡的鱼_ac4e:@皮卡搜 哦哦,是的 ,不好意思啦,写错了,但是我在app下面的build.gradle添加了这句话,还是找不到包,我担心是aspectj环境没配好,但是我在终端输出ajc也是有出现相应操作语句之类的:sob:
        皮卡搜:视频是直播的,没有录播视频~~,你写错了吧,import org.aspectj.*,不是aspect。这个是在
        compile 'org.aspectj:aspectjrt:1.8.13'
        这里面的,你添加这个就肯定会有的。

      本文标题:AndroidStudio 配置 AspectJ 环境实现AOP

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