AspectJ介紹(一)
AOP概念
AOP是Aspect Oriented Programming的縮寫,即『面向切面程式設計』。它和我們平時接觸到的OOP都是程式設計的不同思想,OOP,即『面向物件程式設計』,它提倡的是將功能模組化,物件化,而AOP的思想,則不太一樣,它提倡的是針對同一類問題的統一處理,當然,我們在實際程式設計過程中,不可能單純的安裝AOP或者OOP的思想來程式設計,很多時候,可能會混合多種程式設計思想,大家也不必要糾結該使用哪種思想,取百家之長,才是正道
AspectJ
AspectJ實際上是對AOP程式設計思想的一個實踐,當然,除了AspectJ以外,還有很多其它的AOP實現,例如ASMDex,但目前最好、最方便的,依然是AspectJ。
發現問題
當初做自己的專案,有部分程式碼我不想讓別人通過反編譯知道其邏輯,我做過很多防護措施:
- 程式碼混淆
- 核心方法Native
- 動態載入dex,載入dex之前dex檔案加密
- 動態載入so
- 所有宣告字串加密
- 使用3方加固平臺(治標不治本)
- 插入程式碼花指令,jui工具編譯方法報錯
前面5要措施,都不是今天要講的核心,其實第5條措施和今天說的有一些關聯,但是實現邏輯原理是不一樣的(不是今天的重點),說下第6條,對抗反編譯其實就是對抗反編譯工具,jadx丶jui都可以看程式碼,我發現有部分程式碼jui是編譯出錯的,這段程式碼在實際功能找中沒有任何作用,但是插入這段程式碼jui工具就會編譯出錯,這就和花指令是一個到了,無效的程式碼,給破解這帶來難度,插入這代花指令程式碼,一開始我使用入侵的形式(其實就是手動複製貼上),慢慢的核心方法越來越多,導致我閱讀自己的程式碼都開始費勁了,學習了AspectJ,可以完美解決這個問題,廢話不說開始
解決問題
- 當時我的方案是,通過ASM+Transformer庫來完成這種邏輯,其實這種邏輯是可以實現的,我也能完成,但是在對ASM對class,由於我在方法內部插入的程式碼過多,ASM的class的位元組碼過於複雜,總是出錯,開發成本非常高,上手難度很大,但是ASM庫非常強大,更加靈活
- AsepcJ來解決(今天的主角),學習成本低,上手簡單,完美解決問題
AspectJ的設計理念(概念)
Advice(通知)
注入到class檔案中的程式碼。典型的 Advice 型別有 before、after 和 around,分別表示在目標方法執行之前、執行後和完全替代目標方法執行的程式碼。 除了在方法中注入程式碼,也可能會對程式碼做其他修改,比如在一個class中增加欄位或者介面。
Joint point(連線點)
程式中可能作為程式碼注入目標的特定的點,例如一個方法呼叫或者方法入口。
Pointcut(切入點)
告訴程式碼注入工具,在何處注入一段特定程式碼的表示式。例如,在哪些 joint points 應用一個特定的 Advice。切入點可以選擇唯一一個,比如執行某一個方法,也可以有多個選擇,比如,標記了一個定義成@DebguTrace 的自定義註解的所有方法。
整合AspectJ
整合分為2種方法,建議外掛整合
外掛整合AspectJ
- 建立主專案app
- 建立library,AsepctJ
- 根目錄的build.gradle,插入 classpath ‘com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4’
- AsepctJ的build.gradle,依賴 api ‘org.aspectj:aspectjrt:1.8.9’
- App主專案,依賴 implementation project(’:aspectj’) ,應用plugin外掛apply plugin: ‘com.hujiang.android-aspectjx’ 開源外掛地址講的很清楚,看下就會拉
gradle整合
來個簡單demo爽一下
app就是需要主專案,aspectj就是需要做插程式碼的library,看了上面的方式應該都會整合好了AspectJ
程式碼
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showMsg("我好牛B哦");
}
public void showMsg(String msg){
Log.d("wyz", msg);
}
}
AspectJ類
// 1:所需要插入程式碼的類,必須使用@Aspect註解
@Aspect
public class CoreAspetJ {
// 需要注入的方法
@After("call(* com.mmvoice.aspectjdemo.MainActivity.showMsg(java.lang.String))")
public void showTaost(JoinPoint joinPoint) {
Log.d("wyz", "AspectJ:牛B個錘子");
}
}
執行效果
執行輸入了這2句,我的程式碼showMsg只打印一個Log的
總結
這一章節,主要講解了下整合方式,以及概念性的東西,以及我遇到的問題和解決問題的方式。