AspectJ In Android Studio

開發(fā)工具:Android Studio
參考鏈接:
1.一個流傳廣泛到不知道哪個是原版的博客
2.基于上面內(nèi)容中第二種方式配置的具體說明
3.基于上述方法的測試代碼庫
4.一個插件 gradle-android-aspectj-plugin
5.另一個插件 gradle_plugin_android_aspectjx
6.Aspect Oriented Programming in Android


做安卓都知道 OOP 面向?qū)ο缶幊腆镆K鼘⒁幌盗惺挛锍橄蠡魑常阉麄冇泄驳膶傩约系揭黄鹂粒蔀槟芨叨雀爬骋活惥唧w事物的概念。比如交通工具是一個抽象概念,而具體實現(xiàn)則有汽車酒奶、自行車等等废麻,相信走在安卓開發(fā)路上的我們都很熟悉,但是在面向?qū)ο缶幊痰倪^程中邦马,我們遇到這樣的問題:需要對某些事件進行統(tǒng)一的處理,比如統(tǒng)計埋點宴卖、權限控制滋将、日志打印。顯然症昏,我們可以自定義一個類随闽,然后在不同事件中分別調(diào)用指定方法,這樣的思想在我們?nèi)粘5木幊讨幸呀?jīng)有了相當成熟的應用肝谭,但是終究還是不夠智能和便捷掘宪。
于是乎,偉大的 AOP 出現(xiàn)了攘烛,解決了許許多多的問題魏滚,而今天,我們就來簡單了解一下 AOP坟漱。

一鼠次、什么是AOP ?

AOP是Aspect Oriented Programming的縮寫芋齿,也就是題目里說的面相切面編程腥寇。它通過預編譯或者運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護。AOP 是 OOP的延續(xù)觅捆,也是函數(shù)式編程的一種衍生泛型赦役。利用AOP可以對業(yè)務邏輯的各個部分進行隔離,從而使得業(yè)務邏輯之間的耦合度降低栅炒,提高程序的可重用性掂摔。
還不是很了解的可以去稍微看一下,有點多赢赊,簡單看看就好乙漓。百度鏈接

二、運行時AOP框架

Dexposed域携,這是是阿里巴巴無線事業(yè)部第一個重量級 Andorid 開源軟件簇秒,基于 ROOT 社區(qū)著名開源項目Xposed 改造剝離了 ROOT 部分,演化為服務于所在應用自身的 AOP 框架秀鞭。它支撐了阿里大部分 App 的在線分鐘級客戶端 bugfix 和線上調(diào)試能力趋观。
但是扛禽,它在2015年貌似就已經(jīng)停止更新了
但是,它在2015年貌似就已經(jīng)停止更新了
但是皱坛,它在2015年貌似就已經(jīng)停止更新了
看看github上的更新數(shù)據(jù):

[alibaba](https://github.com/alibaba)/[dexposed](https://github.com/alibaba/dexposed)截圖

安卓5.0使用ART虛擬機后编曼,這個庫的支持就一直停留在 testing 再也沒變過。前段時間剩辟,埋點數(shù)據(jù)和ios嚴重不符合掐场,才發(fā)現(xiàn)了這個問題,為此重新整理一下贩猎。

三熊户、預編譯AOP框架 -- AspectJ

由于找不到合適的運行時框架,我們決定使用預編譯的AOP框架 -- AspectJ吭服。根據(jù)網(wǎng)上目前的資料來看嚷堡,可以使用的主要有兩種方法:

  • 1.使用插件 gradle-android-aspectj-plugin
  • 2.自己配置 Gradle,添加腳本艇棕。

這種情況下蝌戒,為了快速開發(fā),一般當然會選擇先考察插件的可使用性沼琉。
(如果想看自己配置 Gradle 的方法北苟,可以直接跳到后面看 3.4 ~):-)
根據(jù)資料,gradle-android-aspectj-plugin 這個插件是不能支持 data-binding 的打瘪,雖然我公司也用不到友鼻,但是總希望能找到一個更優(yōu)的解決方案。于是乎瑟慈,我在公眾號中找到了需要的東西——根據(jù)上面的插件改良的插件桃移。并且在原作者的Github上屋匕,這個插件也得到了推薦葛碧。

gradle-android-aspectj-plugin 首頁

那么下面,就了解一下這個插件的使用:

3.1 使用插件的走一波效果

工程- gradle

buildscript {
    ...
    dependencies {
        ...
        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.0.8'
    }
}

app - gradle

apply plugin: 'android-aspectjx'
//更詳細的使用作者在readme中已經(jīng)舉例寫得很明白了过吻,可以自行參考上面的鏈接
aspectjx {
    //加入需要織入代碼的第三方庫
    includeJarFilter '...xxx', '...xxx'
    
    //排除不需要織入代碼的第三方庫
    excludeJarFilter '...xxx'
}
dependencies{
        ...
        compile 'org.aspectj:aspectjrt:1.8.9'
}

AspectTest

@Aspect
public class AspectTest {

    private static final String TAG = "AspectTest";
    // 復制代碼需要注意修改下面的 com.arno.testaspectj 為你的包名
    private static final String ACTI_ONCREATE = "execution(com.arno.testaspectj.MainActivity.onCreate(..))";
    
    @Before(ACTI_ONCREATE )
    public void onActivityCreate(JoinPoint joinPoint) throws Throwable {
        Log.d(TAG, "onActivityCreate: " +  joinPoint.getSignature().toString());
    }
   
}

主界面什么也沒動进泼,這樣工程就應該可以跑起來了。
If you meet any problem纤虽,I recommend strongly to update your gradle first乳绕,clean your project and run it.
在進入 MainActivity 后,打開控制臺逼纸,你就會看到我們對應的日志打印洋措。這是最簡單的實現(xiàn),我們可以看到杰刽,在沒有更改 MainActivity 中代碼的情況下菠发,我們成功截取了 onCreate 方法的調(diào)用王滤,并在它調(diào)用之前打印了日志。
那么下面讓我們看看使用 AspectJ 需要了解哪些元素滓鸠。

3.2 AspectJ 相關詞匯了解
  • 橫向切面:傳統(tǒng)的面相對象編程雁乡,每個單元就是一個類,在單一功能上可以很好地實現(xiàn)糜俗,但是他們通常會和其他類共同或者相關聯(lián)的需求踱稍。比如日志、埋點等悠抹,盡管每個主類都有不同的功能珠月,但是在細節(jié)功能需求上,會出現(xiàn)很多相同的代碼楔敌。這就是我們 AspectJ 的功能桥温,將不同的類橫向切面,將某些需要添加相同代碼的切點集合到一起做處理梁丘,減少代碼的冗余和類之間的耦合侵浸。
  • Advice:注入到類文件當中的代碼以及我們?nèi)绾巫⑷脒@些代碼。前面例子中的 @Before 就是插入的方法氛谜,而日志打印就是具體的代碼掏觉。
  • Join Point:程序中的一個特定切點,可能是切入代碼的目標
  • Pointcut:看了下各種各樣的說法值漫,拿捏不準澳腹。但是根據(jù)用的時候的感受來看,應該是具體定義的 Join Point杨何,是特殊的Join Point酱塔。
  • Aspect:Aspect 是 Pointcut 和 advice 的結合
  • Weaving:織入代碼的過程
3.3 Advice - Before && After && Around

以上三種切入方式是最常用的,切入方式如英文單詞的意思危虱,非常好理解羊娃。我們以下面的代碼為例,說明調(diào)用過程埃跷。

@xxx注解("execution(com.arno.testaspectj.MainActivity.onCreate(..))")
public void onActivityCreate(JoinPoint joinPoint) throws Throwable {
    Log.d(TAG, msg);
}
  • Before 注解效果:
@Before ("execution(com.arno.testaspectj.MainActivity.onCreate(..))")
public void onActivityCreate(JoinPoint joinPoint) throws Throwable {
    Log.d(TAG, msg);
}
// -- 執(zhí)行順序
Log.d(TAG,msg)
MainActivity.onCreate(.)
  • After 注解效果:
@After ("execution(com.arno.testaspectj.MainActivity.onCreate(..))")
public void onActivityCreate(JoinPoint joinPoint) throws Throwable {
    Log.d(TAG, msg);
}
// -- 執(zhí)行順序
MainActivity.onCreate(.)
Log.d(TAG,msg)
  • Around 注解效果:
@After ("execution(com.arno.testaspectj.MainActivity.onCreate(..))")
public void onActivityCreate(ProceedingJoinPoint proceedingJoinPoint ) throws Throwable {
    Log.d(TAG, msg);
    proceedingJoinPoint.proceed();
    Log.d(TAG,msg2);
}
// -- 執(zhí)行順序
Log.d(TAG,msg)
MainActivity.onCreate(.)
Log.d(TAG,msg2)
3.4 自己配置 Gradle 插件蕊玷,添加腳本

根據(jù)博客的說法,我照搬了一套弥雹,放到我的 Gradle 文件中去垃帅,然后報紅,以下文件無法導入剪勿。

import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

之后我升級了一下 Gradle 版本贸诚,編譯成功。但是配置了一些切入點,卻并不執(zhí)行相關內(nèi)容酱固。于是上網(wǎng)找了些資料二鳄,發(fā)現(xiàn)不少人和我一樣對著這個英文資料在配置 aspectj 。有人說媒怯,配置中的 java 版本改一下就可以了订讼。

String[] args = ["-showWeaveInfo",
                         "-1.7", // <-- java 版本
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", plugin.project.android.bootClasspath.join(
                File.pathSeparator)
        ]

然而沒有用,這期間扇苞,我試了各種方法欺殿,包括但不僅限于:clean project,rebuild project鳖敷,new project... 后來我在 stackoverflow 上找到了一個答案:不靠譜的鏈接
按照它做了脖苏,然而。呵呵 :-(
后面在 stackoverflow 上又有新發(fā)現(xiàn)定踱,但是鏈接已經(jīng)找不到了棍潘,總之就是不能用 = = ,白叨叨了我好久崖媚,有點費時間亦歉。
所以,乖乖用插件吧畅哑。

-------------------------------------- 分割線 ------------------------------------------------

07/26
使用過程中發(fā)現(xiàn)如下問題:

  1. 在對 android.app.Activity.onResume() 方法織入代碼時肴楷,如果其子類中沒有重寫這個方法,那么是無法織入代碼的荠呐。(也就是說赛蔫,即使在onResume中不做任何操作,同樣要override)泥张。前文中呵恢,我一直默認使用 execution,但是如果使用 call媚创,那么即使你重寫了 onResume 也無法織入代碼渗钉,由于織入代碼的位置問題,必須要在代碼中調(diào)用了這個方法筝野,才能成功織入晌姚。
  2. 在對 com.xxx.xx.BaseActivity.onResume() 方法織入代碼時粤剧,如果 BaseActivity 和其子類都重寫了 onResume() 方法歇竟,那么織入的代碼會被調(diào)用兩次。
  3. 對組合的自定義 pointcut 進行代碼織入的時候抵恋,joinPoint.getArgs() 獲取的參數(shù)是范圍較小的方法的參數(shù)焕议。
  4. 組合自定義 pointcut 的時候,withincode + execution 無法成功織入代碼弧关。
    5.無法切割對象盅安,所有的代碼織入都必須在界面的方法中唤锉。

如果有新發(fā)現(xiàn),歡迎戳我戳我戳我别瞭! 謝謝

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末窿祥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蝙寨,更是在濱河造成了極大的恐慌晒衩,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件墙歪,死亡現(xiàn)場離奇詭異听系,居然都是意外死亡,警方通過查閱死者的電腦和手機虹菲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門靠胜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人毕源,你說我怎么就攤上這事浪漠。” “怎么了霎褐?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵郑藏,是天一觀的道長。 經(jīng)常有香客問我瘩欺,道長必盖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任俱饿,我火速辦了婚禮歌粥,結果婚禮上,老公的妹妹穿的比我還像新娘拍埠。我一直安慰自己失驶,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布枣购。 她就那樣靜靜地躺著嬉探,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棉圈。 梳的紋絲不亂的頭發(fā)上涩堤,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音分瘾,去河邊找鬼胎围。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的白魂。 我是一名探鬼主播汽纤,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼福荸!你這毒婦竟也來了蕴坪?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤敬锐,失蹤者是張志新(化名)和其女友劉穎辞嗡,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滞造,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡续室,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谒养。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挺狰。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖买窟,靈堂內(nèi)的尸體忽然破棺而出丰泊,到底是詐尸還是另有隱情,我是刑警寧澤始绍,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布瞳购,位于F島的核電站,受9級特大地震影響亏推,放射性物質(zhì)發(fā)生泄漏学赛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一吞杭、第九天 我趴在偏房一處隱蔽的房頂上張望盏浇。 院中可真熱鬧,春花似錦芽狗、人聲如沸绢掰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滴劲。三九已至,卻和暖如春顾复,著一層夾襖步出監(jiān)牢的瞬間班挖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工捕透, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留聪姿,地道東北人碴萧。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓乙嘀,卻偏偏與公主長得像末购,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子虎谢,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,504評論 25 707
  • AspectJ in Android 系列: AspectJ in Android (一)婴噩,AspectJ 基礎概...
    JohnnyShieh閱讀 4,777評論 5 23
  • AOP之AspectJ - 代碼注入 [TOC] 一擎场、AOP簡介 1.1 什么是AOP編程 AOP是Aspect ...
    everlastxgb閱讀 2,514評論 2 10
  • 花開陽光路! 現(xiàn)在正是攀枝花爬滿枝頭的季節(jié)几莽。我是在攀枝花上的大學迅办,攀枝花市是全國唯一一個以花命名的城市,攀枝花是攀...
    成都楊林閱讀 213評論 0 0
  • 冬天最美好的事章蚣; 冬天有熱乎的被窩睡站欺; 有無線網(wǎng)聯(lián); 有火鍋吃纤垂; 實乃冬日美事矾策。
    古蘊閱讀 569評論 0 0