又掌握了一项新技能 - 断点调试 Gradle 插件
前言
最初開發Android應用程序的時候,肯定是在打log調試,然后慢慢地覺得打log效率太低下了,不能快速定位問題,于是走上了斷點調試之路。Gradle插件也一樣,從會寫插件那一刻起到現在,一直用的是打log調試功能,但是同樣的這種方式效率也太低下了,這之前,我也嘗試過尋找斷點調試的方式,但是一直沒有成功,昨天偶然之間調通了,于是記錄一發。
之前失敗的方式
之前測試斷點調試的功能的時候,一直在build.gradle中直接測代碼,測試的代碼也是在project.afterEvaluate之后,然后遍歷android..applicationVariants,獲取各個信息,就像這樣子
| 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()}}} |
于是這個斷點我打了一年硬是沒打住,恩,沒錯,這個東西我斷斷續續實驗了一年也沒有成功過,也有點無語,原因也不知道。昨日發現,必須得在外面包一層plugin才能打住斷點,就像這樣子
| 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()}}}}} |
具體原因也找不到,理論上來講,兩者沒有什么大的區別,除非不包plugin的代碼編譯后代碼位置發生了變化,導致打不到斷點。
其實這事也怪自己,如果一開始直接用插件項目來測,將其發布到本地maven,然后執行去打斷點,估計老早就成功了,硬是在build.gradle中寫零碎的代碼來測試,往事不提也罷。
一個坑
以上代碼執行過程會先出現一個錯,如下:
| 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). |
這個錯出現的時候,只需要將ApplicationVariantImpl variant改成def variant即可,然后繼續運行,會出現另一個問題。
即出現了一個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' |
可以看到雖然兩個對象obj1和obj2的類的名字相同,但是這兩個類是由不同的類加載器實例來加載的,因此不被虛擬機認為是相同的,所以拋出了ClassCastException異常。
那么怎么解決呢,將項目中所有buildscript中的dependencies下引用的android gradle plugin 版本都改成同一個,即
| 12345678 | buildscript { repositories {jcenter()} dependencies { classpath "com.android.tools.build:gradle:${global_gradle_plugin_version}"}} |
之后將~/.gradle/daemon/目錄下內容全部刪除,然后看看是否解決了,如果沒有解決,則繼續刪除~/.gradle/daemon/,然后重啟電腦。TM的如果還沒好,那么請確定項目中所有引用的插件中的compile的android gradle plugin版本是否都一致,如果不一致,請保持一致,不然也有問題。
這問題就算完事了,大概可能和Gradle的守護進程、插件引用的android gradle plugin版本不一致有那么一點關系。
斷點調試方式1
說完了以上坑,正式進入斷點調試的環節,方式一很簡單,直接利用gradle的參數讓其等待我們的調試進程attach上去。比如我要執行gradle clean這個task,則加上兩個額外參數即可
- 一個是開啟debug
一個是不使用守護進程
具體例子如下:
1 gradle :app:clean -Dorg.gradle.debug=true --no-daemon 之后這個進程就會一直等待,直到我們attach我們的調試進程。如下圖所示:
然后參考這篇文章Intellij-IDEA遠程調試,利用Android Studio或者Intellij IDEA的remote debug進行調試,端口號填5005.
如圖
然后運行remote
之后就會attach上去我們的進程
然后看看效果
從此可以愉快的斷點調試了。
斷點調試方式2
和方式一差不多,只不過不是用gradle的參數來開啟debug,而是用環境變量
| 1 | export GRADLE_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005" |
之后就跟正常執行任務一樣
| 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/總結
以上是生活随笔為你收集整理的又掌握了一项新技能 - 断点调试 Gradle 插件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Gradle Plugi
- 下一篇: Google Archive Patch