又掌握了一项新技能 - 断点调试 Gradle 插件
前言
最初開發(fā)Android應(yīng)用程序的時(shí)候,肯定是在打log調(diào)試,然后慢慢地覺得打log效率太低下了,不能快速定位問題,于是走上了斷點(diǎn)調(diào)試之路。Gradle插件也一樣,從會(huì)寫插件那一刻起到現(xiàn)在,一直用的是打log調(diào)試功能,但是同樣的這種方式效率也太低下了,這之前,我也嘗試過尋找斷點(diǎn)調(diào)試的方式,但是一直沒有成功,昨天偶然之間調(diào)通了,于是記錄一發(fā)。
之前失敗的方式
之前測(cè)試斷點(diǎn)調(diào)試的功能的時(shí)候,一直在build.gradle中直接測(cè)代碼,測(cè)試的代碼也是在project.afterEvaluate之后,然后遍歷android..applicationVariants,獲取各個(gè)信息,就像這樣子
| 12345678910111213141516171819202122232425262728293031 | buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.3'}}dependencies {compile gradleApi()compile localGroovy()}import com.android.build.gradle.api.TestVariantimport com.android.build.gradle.api.UnitTestVariantimport com.android.build.gradle.internal.variant.ApplicationVariantDataimport com.android.build.gradle.internal.api.ApplicationVariantImplproject.afterEvaluate {if (project.plugins.hasPlugin("com.android.application")) {def android = project.extensions.getByName("android")android.applicationVariants.all {ApplicationVariantImpl variant ->project.logger.error "DebuggerPlugin:${variant}"ApplicationVariantData apkVariantData = variant.getApkVariantData()ApplicationVariantData variantData = variant.getVariantData()TestVariant testVariant = variant.getTestVariant()UnitTestVariant unitTestVariant = variant.getUnitTestVariant()}}} |
于是這個(gè)斷點(diǎn)我打了一年硬是沒打住,恩,沒錯(cuò),這個(gè)東西我斷斷續(xù)續(xù)實(shí)驗(yàn)了一年也沒有成功過,也有點(diǎn)無語,原因也不知道。昨日發(fā)現(xiàn),必須得在外面包一層plugin才能打住斷點(diǎn),就像這樣子
| 123456789101112131415161718192021222324252627282930313233343536373839 | buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.3'}}dependencies {compile gradleApi()compile localGroovy()}apply plugin: DebuggerPluginimport com.android.build.gradle.api.TestVariantimport com.android.build.gradle.api.UnitTestVariantimport com.android.build.gradle.internal.variant.ApplicationVariantDataimport com.android.build.gradle.internal.api.ApplicationVariantImplclass DebuggerPlugin implements Plugin<Project> {void apply(Project project) {project.afterEvaluate {if (project.plugins.hasPlugin("com.android.application")) {def android = project.extensions.getByName("android")android.applicationVariants.all {ApplicationVariantImpl variant ->project.logger.error "DebuggerPlugin:${variant}"ApplicationVariantData apkVariantData = variant.getApkVariantData()ApplicationVariantData variantData = variant.getVariantData()TestVariant testVariant = variant.getTestVariant()UnitTestVariant unitTestVariant = variant.getUnitTestVariant()}}}}} |
具體原因也找不到,理論上來講,兩者沒有什么大的區(qū)別,除非不包plugin的代碼編譯后代碼位置發(fā)生了變化,導(dǎo)致打不到斷點(diǎn)。
其實(shí)這事也怪自己,如果一開始直接用插件項(xiàng)目來測(cè),將其發(fā)布到本地maven,然后執(zhí)行去打斷點(diǎn),估計(jì)老早就成功了,硬是在build.gradle中寫零碎的代碼來測(cè)試,往事不提也罷。
一個(gè)坑
以上代碼執(zhí)行過程會(huì)先出現(xiàn)一個(gè)錯(cuò),如下:
| 1 | Error:The closure 'DebuggerPlugin$_apply_closure1$_closure2@20825b3e' is not valid as an action for argument 'com.android.build.gradle.internal.api.ApplicationVariantImpl_Decorated@1103b69d'. It should accept no parameters, or one compatible with type 'com.android.build.gradle.internal.api.ApplicationVariantImpl_Decorated'. It accepts (com.android.build.gradle.internal.api.ApplicationVariantImpl). |
這個(gè)錯(cuò)出現(xiàn)的時(shí)候,只需要將ApplicationVariantImpl variant改成def variant即可,然后繼續(xù)運(yùn)行,會(huì)出現(xiàn)另一個(gè)問題。
即出現(xiàn)了一個(gè)cannot cast object with class A to A的問題,如下
| 1 | Error:Cannot cast object 'ApplicationVariantData{debug}' with class 'com.android.build.gradle.internal.variant.ApplicationVariantData' to class 'com.android.build.gradle.internal.variant.ApplicationVariantData' |
可以看到雖然兩個(gè)對(duì)象obj1和obj2的類的名字相同,但是這兩個(gè)類是由不同的類加載器實(shí)例來加載的,因此不被虛擬機(jī)認(rèn)為是相同的,所以拋出了ClassCastException異常。
那么怎么解決呢,將項(xiàng)目中所有buildscript中的dependencies下引用的android gradle plugin 版本都改成同一個(gè),即
| 12345678 | buildscript { repositories {jcenter()} dependencies { classpath "com.android.tools.build:gradle:${global_gradle_plugin_version}"}} |
之后將~/.gradle/daemon/目錄下內(nèi)容全部刪除,然后看看是否解決了,如果沒有解決,則繼續(xù)刪除~/.gradle/daemon/,然后重啟電腦。TM的如果還沒好,那么請(qǐng)確定項(xiàng)目中所有引用的插件中的compile的android gradle plugin版本是否都一致,如果不一致,請(qǐng)保持一致,不然也有問題。
這問題就算完事了,大概可能和Gradle的守護(hù)進(jìn)程、插件引用的android gradle plugin版本不一致有那么一點(diǎn)關(guān)系。
斷點(diǎn)調(diào)試方式1
說完了以上坑,正式進(jìn)入斷點(diǎn)調(diào)試的環(huán)節(jié),方式一很簡單,直接利用gradle的參數(shù)讓其等待我們的調(diào)試進(jìn)程attach上去。比如我要執(zhí)行g(shù)radle clean這個(gè)task,則加上兩個(gè)額外參數(shù)即可
- 一個(gè)是開啟debug
一個(gè)是不使用守護(hù)進(jìn)程
具體例子如下:
1 gradle :app:clean -Dorg.gradle.debug=true --no-daemon 之后這個(gè)進(jìn)程就會(huì)一直等待,直到我們attach我們的調(diào)試進(jìn)程。如下圖所示:
然后參考這篇文章Intellij-IDEA遠(yuǎn)程調(diào)試,利用Android Studio或者Intellij IDEA的remote debug進(jìn)行調(diào)試,端口號(hào)填5005.
如圖
然后運(yùn)行remote
之后就會(huì)attach上去我們的進(jìn)程
然后看看效果
從此可以愉快的斷點(diǎn)調(diào)試了。
斷點(diǎn)調(diào)試方式2
和方式一差不多,只不過不是用gradle的參數(shù)來開啟debug,而是用環(huán)境變量
| 1 | export GRADLE_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005" |
之后就跟正常執(zhí)行任務(wù)一樣
| 1 | gradle clean |
剩下的操作和方式1一樣。
http://fucknmb.com/2017/07/05/%E5%8F%88%E6%8E%8C%E6%8F%A1%E4%BA%86%E4%B8%80%E9%A1%B9%E6%96%B0%E6%8A%80%E8%83%BD-%E6%96%AD%E7%82%B9%E8%B0%83%E8%AF%95Gradle%E6%8F%92%E4%BB%B6/總結(jié)
以上是生活随笔為你收集整理的又掌握了一项新技能 - 断点调试 Gradle 插件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Gradle Plugi
- 下一篇: Google Archive Patch