自定义Gradle插件和AspectJ实战

xiaoxiao2021-02-28  22

生成gradle插件步骤

create new Moduleselect Android Library把生成的module(例如:plugin)里面的东西都删除(除了build.gradle,但是要被gradle里面的所有内容删除)在plugin里面新增一个“src”文件夹,往src文件夹新增main文件夹,再往main文件夹新增groovy和resources文件夹。resources目录下新建文件夹META-INF,META-INF文件夹下新建gradle-plugins文件夹。在groovy目录下新建项目包名,就像Java包名那样。

打开Module下的build.gradle文件,输入

apply plugin: 'groovy' apply plugin: 'maven' dependencies { compile gradleApi()//gradle sdk compile localGroovy()//groovy sdk compile 'com.android.tools.build:gradle:2.2.2' compile 'org.javassist:javassist:3.20.0-GA' compile 'org.aspectj:aspectjtools:1.8.1' } uploadArchives { repositories.mavenDeployer { repository(url: uri('../repo')) pom.groupId = 'com.dawn.plugin' pom.artifactId = 'gradleplugin' pom.version = '1.0.0' } } repositories { jcenter() }

uploadArchives闭包里面配置的是将插件发布到本地仓库。

上面的group和version的定义会被使用,作为maven库的坐标的一部分,group会被作为坐标的groupId,version会被作为坐标的version,而坐标的artifactId组成即module名,我们让其取一个别名moduleName。然后maven本地仓库的目录就是当前项目目录下的repo目录。

下面我们在groovy下的包名下新建一个文件,命名为AspectjPlugin.groovy,注意有groovy后缀,然后在里面输入,注意包名替换为你自己的包名。

package com.dawn.plugin import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main import org.gradle.api.Plugin import org.gradle.api.Project /** * @使用ajc编译java代码 , 同 时 织 入 切 片 代 码 * 使用 AspectJ 的编译器(ajc,一个java编译器的扩展) * 对所有受 aspect 影响的类进行织入。 * 在 gradle 的编译 task 中增加额外配置,使之能正确编译运行。 */ public class AspectjPlugin implements Plugin<Project> { void apply(Project project) { project.dependencies { compile 'org.aspectj:aspectjrt:1.8.9' } final def log = project.logger log.error "========================"; log.error "Aspectj切片开始编织Class!"; log.error "========================"; project.android.applicationVariants.all { variant -> def javaCompile = variant.javaCompile javaCompile.doLast { String[] args = ["-showWeaveInfo", "-1.8", "-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; } } } } } }

然后在resources/META-INF/gradle-plugins目录下新建一个properties文件,注意该文件的命名就是你只有使用插件的名字,这里命名为com.dawn.plugin.aspectj.properties,在里面输入

implementation-class=com.dawn.plugin.AspectjPlugin

这时候,右侧的gradle Toolbar就会在module下多出一个task

点击uploadArchives这个Task,就会在项目下多出一个repo目录,里面存着这个gradle插件。

以及在根目录的build.gradle文件添加配置:

repositories { //... maven{ url uri('repo') } } dependencies { //... classpath 'com.dawn.plugin:gradleplugin:1.0.0' }

先Rebuild Project,最后在app下的build.gradle添加配置

import com.dawn.plugin.AspectjPlugin apply plugin: AspectjPlugin //... compile 'org.aspectj:aspectjrt:1.8.9'

一、防止View短时间内多次点击

1. 自定义注解

@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface SingleClick { }

2. SingleClickAspect

@Aspect public class SingleClickAspect { static int TIME_TAG = R.id.click_time; public static final int MIN_CLICK_DELAY_TIME = 1000;//间隔时间600ms //execution方法里面要填写你自己的完整的包名路径:xxx.xxx.xxx.SingleClick @Pointcut("execution(@dawn.com.aspectjdemo.SingleClick * *(..))") public void methodAnnotated() { } @Around("methodAnnotated()") public void aroundJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable{ View view=null; for (Object arg :joinPoint.getArgs()){ if(arg instanceof View ){ view =(View)arg; } } if(view!=null){ Object tag=view.getTag(TIME_TAG); long lastClickTime= ((tag != null) ? (long) tag : 0); LogUtils.showLog( "lastClickTime:" + lastClickTime); long currentTime= Calendar.getInstance().getTimeInMillis(); if(currentTime -lastClickTime >MIN_CLICK_DELAY_TIME){//过滤掉600毫秒内的连续点击 view.setTag(TIME_TAG,currentTime); LogUtils.showLog( "currentTime:" + currentTime); joinPoint.proceed();//执行原方法 } } } }

使用方法:标注在onClick上

@SingleClick public void onClick(View view) { ... }

或者任何参数内有view可以做为参照系(view可以不是onClick的view,仅仅作为时间tag依附对象作为参照)的方法上,例如TRouter的页面跳转,防止连续快速点击重复跳页现象:

public class RouterHelper { @SingleClick // 防止连续点击 public static void go(String actionName, HashMap data, View view) { TRouter.go(actionName, data, view); } }

二、拦截未登录用户的权限

1.自定义注解

@Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface CheckLogin { }

2. CheckLoginAspect

@Aspect public class CheckLoginAspect { @Pointcut("execution(@dawn.com.aspectjdemo.annotation.CheckLogin * *(..))") public void methodCheckLogin() { } @Around("methodCheckLogin()") public void aroundCheckLogin(ProceedingJoinPoint joinPoint) throws Throwable { if (null == UserInfoSp.getUser()) { LogUtils.showLog("还未登录,请先登录"); //跳转到登录界面 return; } joinPoint.proceed();//执行原方法 } }

使用方法,标注要某方法上 :

@CheckLogin @Override public void onClick(View view) { Toast.makeText(this, "获取用户信息", Toast.LENGTH_SHORT).show(); }
转载请注明原文地址: https://www.6miu.com/read-2631736.html

最新回复(0)