1. 程式人生 > >自定義Gradle外掛和AspectJ實戰

自定義Gradle外掛和AspectJ實戰

生成gradle外掛步驟

  1. create new Module
  2. select Android Library
  3. 把生成的module(例如:plugin)裡面的東西都刪除(除了build.gradle,但是要被gradle裡面的所有內容刪除)
  4. 在plugin裡面新增一個“src”資料夾,往src資料夾新增main資料夾,再往main資料夾新增groovy和resources資料夾。
  5. resources目錄下新建資料夾META-INF,META-INF資料夾下新建gradle-plugins資料夾。
  6. 在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

image

點選uploadArchives這個Task,就會在專案下多出一個repo目錄,裡面存著這個gradle外掛。

image

以及在根目錄的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();
 }

AOP的實際應用場景會不斷更新,待續……

相關推薦

定義Gradle外掛AspectJ實戰

生成gradle外掛步驟 create new Module select Android Library 把生成的module(例如:plugin)裡面的東西都刪除(除了build.gradle,但是要被gradle裡面的所有內容刪除) 在plugin

定義 Gradle 外掛學習記錄

參考:https://juejin.im/entry/577bc26e165abd005530ead8 ## 建立Model 1.在Android studio 中建立Model,切換到project模式; 2.刪除model下的除build.gradle檔案和src/main目錄以

定義Gradle外掛(一)

Google已經建議Android開發全部轉向Android Studio開發,Android Studio 是使用gradle編譯、打包的,那麼問題來了,gradle可是有一堆東西...,為了測底瞭解gradle,今天就來學習下如何寫自己的gradle外掛(當然外掛原

安卓開發通過定義Gradle外掛實現自動化埋點

一 埋點現狀: 公司APP在實際開發中埋點是一個很碎片化的問題,我總結了以下幾點: 1.變化快,埋點文件經常變化,開發人員不得不修改程式碼,造成了一定的風險 2.頁面埋點之前是通過把握Activity和Fragment的生命週期實現大部分的統一配置,但是這裡面又牽扯到 Fr

【AndroidStudio】定義gradle外掛:無需釋出,僅用於當前專案

最近由於工作需要,想要做個gradle外掛輔助一下,各種難易程度的講解文章也看了不少,腦子裡的資訊比較亂,在這抽個時間整理一下。 因為是最近剛接觸gradle外掛的製作,剛開始除錯的時候構造的是可釋出的外掛模組,每次修改都得重新發布到本地,麻煩死了~ 在這裡提供一個免釋出

定義gradle外掛從入門到放棄

       最近參與基礎架構組的crashly收集專案,其中一個環節就是收集專案中使用到的公司內部的依賴庫和混淆後的mapping檔案, 然後呼叫python檔案實現檔案和資料欄位的上傳。請求網路上傳資料這塊python使用的程式碼量非常少就幾行程式碼的事情,所以我在專案中

Android如何定義Gradle外掛

Android-如何自定義gradle外掛 自定義gradle外掛可以實現定製自己的構建流程,以達到複用目的; 1. 自定義外掛方式 自定義外掛有三種方式 新增腳步 在你的app專案的build.gradle中直接使用groovy腳步語言編寫外掛

定義Gradle外掛(二)

上一篇部落格已經介紹瞭如何實現簡單的自定義gradle外掛,今天介紹如何自定義Task。 一、自定義Task          1、直接沿用上一篇的程式碼,copy一份改名CustomPluginTask          在plugin\src\main\groov

使用AndroidStudio定義Gradle外掛

1.概述 目標:編寫一個Gradle外掛,學習自定義Gradle外掛。 功能:利用lint自動刪除無用資源。 實現思路:先執行lint任務,通過解析生成的xml檔案,找到id為UnusedResources的檔案路徑,並遍歷刪除,輸出日誌。 開發工具:Andr

為Android Studio編寫定義Gradle外掛的教程

Google已經建議Android開發全部轉向Android Studio開發,Android Studio 是使用gradle編譯、打包的,那麼問題來了,gradle可是有一堆東西...,為了徹底瞭解gradle,今天就來學習下如何寫自己的gradle外掛(當然外掛原始碼是使用groovy寫的),先看如下

通過定義Gradle外掛修改編譯後的class檔案

或許你會覺得沒有必要這樣做,可是有一種應用場景就是,為每個編譯後的class檔案新增一行程式碼。比如:在每個Java類的建構函式中加一句System.out.println("I Love HuaChao!");(PS:莫吐槽~,莫嘲笑~),如果你每次建

定義 gradle plugin,教你如何 hook 系統 task 位元組碼

一、開源背景 大家在自己寫 library 的時候估計也遇到過這種困惑:一個 library 中的某個類中有些方法或類只想給該 library 中的類使用,並不想暴露出去,但是由於專案的包的層級關係,不得不把方法寫為 public ,導致暴露給了外界!!! 當時這個問題確實困惑了我一段時間,總不

【Android定義View實戰】之定義評價打分控制元件RatingBar,可以定義星星大小間距

在Android開發中,我們經常會用到對商家或者商品的評價,運用星星進行打分。然而在Android系統中自帶的打分控制元件,RatingBar特別不好用,間距和大小無法改變。所以,我就自定義了一個特別好用的打分控制元件。在專案中可以直接使用,特別簡

定義檢視控制元件】實戰篇--支援滑動動畫的開關按鈕(SwitcheButton)

菜鳥日記: 之前嘗試去了解繼承View實現自定義檢視控制元件,學習了通過程式碼確實可以繪製一些:字元,幾何圖形。但是正真開發中我們可能做不到精確繪製圖形。想想工作量就很頭大。所以通過美術圖片來實現控制元件的內容是很明智便捷的達到目的的好辦法。現在我們就來看看用點陣圖資源來實

ionicionic2 環境下編寫定義cordova外掛

1 增加android的平臺 對於一個ionic專案,在主目錄下通過以下命令列增加android平臺。 cordova platform add android 然後在platforms目錄下就會出現一個android資料夾: 之後可以使用配置了

【Flutter 實戰定義動畫-漣漪雷達掃描

![](https://img2020.cnblogs.com/other/467322/202008/467322-20200826065915000-1924599008.png) > 老孟導讀:此篇文章是 Flutter 動畫系列文章第五篇,本文介紹2個自定義動畫:**漣漪**和**雷達掃描*

定義服務 factory service

控制器 ctr div ava json對象 html src com 沒有 1、使用factory 方法 必須有返回值 即return ,factory只是調用普通的function,可以返回任何東西。 HTML 代碼 <body ng-app="myApp

php curl如何設置定義請求頭打印請求頭信息

設置 發出 cnblogs lose 請求 clas false 自定義 col $header = [ ‘client:h5‘, ‘token:test‘, ]; curlRequest($url, $params, true, 10, $header

iOS開發-AFNetworking封裝Get(定義HTTP Header)Post請求及文件下載

謝謝 filepath pos cat style -type poe repo eth 前面提到AFNetworking是一個很強大的網絡三方庫,首先你需要引入AFNetworking三方庫;如封裝的有誤還請指出,謝謝! 1.Get請求 /**Get請求 url 服務器

ASP.NET MVC下定義錯誤頁展示錯誤頁的幾種方式

提供服務 one url attribute 運行 16px execute 釋放 namespace 在網站運行中,錯誤是不可避免的,錯誤頁的產生也是不可缺少的。 這幾天看了博友的很多文章,自己想總結下我從中學到的和實際中配置的。 首先,需要知道產生錯誤頁的來源,一種