一些需要知道的:
- Aspectj在android中却音,都是通過注解完成庶柿,如@AspectJ,@Pointcut....看铆。
- Aspectj的代碼需要專門的編譯器編譯才能使用,在android中剩彬,通過添加一些gradle代碼酷麦,來達(dá)到,這篇文章有介紹喉恋。
- 具體學(xué)習(xí)aspectj可以參考這里
-
遇到aspectj無法匹配到方法沃饶,或者無效時(shí),請(qǐng)先查看message編譯信息轻黑,以此定位問題糊肤。常見的如 invalid pointcut xxxx。
- AspectjX會(huì)和帶有TransForm功能的插件相沖突氓鄙,常見的有: retroLambda馆揉,butterKnife好像也是。
幾種引入aspectj的方法
1. 依賴aspectj
這種方法并不在此篇文章講述范圍中抖拦,如果需要升酣,可以點(diǎn)擊這里。
2. 使用滬江aspectjX插件
滬江公司出的一款aspect插件态罪,只需要在 項(xiàng)目.gradle文件中添加
build.gradle(project)
dependencies {
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.0.10'
}
bulid.gradle(相關(guān) module)
apply plugin: 'android-aspectjx'
之后你就可以愉快的使用AspectJ進(jìn)行切面代碼編寫了噩茄。
如果遇到gradle報(bào)錯(cuò),但是原因是空复颈,如:
app:transformClassesWithRetrolambdaForDebug error
那么請(qǐng)使用下面的方法绩聘,這個(gè)錯(cuò)誤沒有辦法解決,它的原因是:Transform 插件沖突【遥可以查看這里
一些問題
每次都需要在gradle中配置一大段代碼驯遇,來使gradle支持Aspectj代碼的編譯芹彬,有沒有簡單的辦法蓄髓?
這問題好解決,封裝唄舒帮,也就是自定義一個(gè)gradle插件來專門干這個(gè)事情会喝。
- 創(chuàng)建一個(gè)module(java),module名字必須是buildsrc玩郊,然后刪除java文件夾肢执,只留下src/main。(不明白可以直接看下面的包結(jié)構(gòu))
- 在src/main文件夾下新建一個(gè)目錄為 groovy译红,然后在groovy中预茄,創(chuàng)建一個(gè)包(包名無所謂,只是最后你其他模塊應(yīng)用這個(gè)插件時(shí)候侦厚,是根據(jù)包名應(yīng)用)
- 打開此module的gradle文件耻陕,全刪,然后放入如下代碼(記得同步)
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
compile 'com.android.tools.build:gradle:2.3.1'
compile 'org.aspectj:aspectjtools:1.8.10'
compile 'org.aspectj:aspectjrt:1.8.10'
}
repositories {
jcenter()
}
- 在剛才的包中創(chuàng)建一個(gè)文件刨沦,后綴名為groovy诗宣,代碼:
package com.hxh.aspjplugin
import com.android.build.gradle.AppPlugin
import com.android.build.gradle.LibraryPlugin
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
import org.gradle.api.tasks.compile.JavaCompile
public class AspectjPlugin implements Plugin<Project> {
void apply(Project project) {
//得到當(dāng)前module的插件類型,是application還是lib
System.out.println("========================");
System.out.println("Aspject開始編譯!");
System.out.println("========================");
def hasApp = project.plugins.withType(AppPlugin)
def hasLib = project.plugins.withType(LibraryPlugin)
if (!hasApp && !hasLib) {
throw new IllegalStateException("'android' or 'android-library' plugin required.")
}
final def log = project.logger
final def variants
if (hasApp) {
variants = project.android.applicationVariants
} else {
variants = project.android.libraryVariants
}
project.dependencies {
// TODO this should come transitively
compile 'org.aspectj:aspectjrt:1.8.6'
}
variants.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", 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;
}
}
}
}
System.out.println("========================");
System.out.println("Aspject編譯結(jié)束!");
System.out.println("========================");
}
}
- clean -》 make 不出意外想诅,你就能看到編譯信息了
- 最后預(yù)覽一下整體結(jié)構(gòu)
- 其他模塊依賴這個(gè)插件
apply plugin: com.hxh.aspjplugin.AspectjPlugin
當(dāng)然召庞,自定義gradle插件并不止這一種方法,你可以參考這里来破,我使用的這篇文章中第二種方法篮灼。
aspj無效,或者無法匹配到方法
- 檢查表達(dá)式是否正確徘禁,如果你的表達(dá)式是這樣的(它不是錯(cuò)誤的):
//應(yīng)用了DataSave注解诅诱,并且有個(gè)參數(shù)為ann
public final String method_piex1 = "execution(@routerlib.hxh.com.corelib_annotation1.annotation.DataSave * *(..)) && @annotation(ann)";
//上面的表達(dá)式并不是錯(cuò)誤的,但是在你仔細(xì)檢查表達(dá)式?jīng)]發(fā)現(xiàn)問題的話晌坤,那么你可以這樣描述你的表達(dá)式
public final String method_piex = "@within(routerlib.hxh.com.corelib_annotation1.annotation.DataSave) || @annotation(routerlib.hxh.com.corelib_annotation1.annotation.DataSave)";
- 是否引入了aspectj的依賴并且添加了編譯aspectj文件的代碼 逢艘。或者插件(使用aspectjX時(shí)候)
當(dāng)如上都否定時(shí)候骤菠,如果你使用的是自定義gradle插件方法它改,而且當(dāng)前自定義的gradle插件是一種可發(fā)布狀態(tài)的,那么請(qǐng)改為【針對(duì)當(dāng)前項(xiàng)目的gradle插件】商乎,可以參考這里央拖。
使用AspectjX,然后編譯一直不通過,而且錯(cuò)誤信息還是空
上面有相關(guān)解釋鲜戒,所以专控,請(qǐng)更換引入aspectj的方式。
使用JDK1.8 的問題
當(dāng)你遇到遏餐,編譯正常通過伦腐,但是aspectj的代碼就是不執(zhí)行的時(shí)候,錯(cuò)誤的信息為:
Invalid byte tag in constant pool 18
如果你當(dāng)前應(yīng)用的jdk版本為1.8失都,那么你要這么做
- 檢查你的aspectj 的版本柏蘑,讓其為1.8.10(包含)以上
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
compile 'com.android.tools.build:gradle:2.3.1'
compile 'org.aspectj:aspectjtools:1.8.10'//這兩句
compile 'org.aspectj:aspectjrt:1.8.10'//這兩句
}
repositories {
jcenter()
}
編譯出現(xiàn) No such property: project for class: com.android.build.gradle.LibraryPlugin的問題
這是因?yàn)镚radle 2.3+ 后,配置變了
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
log.debug "ajc args: " + Arrays.toString(args)
變更為:
"-bootclasspath",android.bootClasspath.join(File.pathSeparator)]
log.debug "ajc args: " + Arrays.toString(args)
持續(xù)更新中....