問題背景
項目編譯過程中,使用了類似Android Gradle Plugin的gradle插件進(jìn)行編譯,在最終打包apk時疤剑,會動態(tài)修改manifest文件绑榴。
近期發(fā)現(xiàn)線上用戶有反應(yīng)升級到以下開發(fā)環(huán)境后,打包apk后manifest文件中沒有應(yīng)有的任何配置靶擦。
Android Gradle Plugin:4.1.0
Gradle:6.5
Android Studio:4.1
確認(rèn)調(diào)查方向
首先要確認(rèn)清楚到底是上述3個哪個的升級導(dǎo)致的問題。
在本地進(jìn)行環(huán)境升級過程驗證了以下結(jié)論:
Android Gradle Plugin:4.1.0
強(qiáng)制要求 Android Studio:4.1
+ Gradle:6.5
。然而 以下環(huán)境下打包過程是正常的:
Android Gradle Plugin:4.0.2
Gradle:6.5
Android Studio:4.1
Android Gradle Plugin:4.0.2
是 4.1
的前一個版本藏古,至此可以確認(rèn)是 Android Gradle Plugin:4.1.0
的升級導(dǎo)致的不兼容問題。
明確了調(diào)查的方向忍燥,接下來就可以有的放矢了拧晕。
調(diào)查分析
我們的gradle插件,是通過以下代碼獲取到manifest文件后做處理的:
new File(output.processManifestProvider.get().manifestOutputDirectory.get().getAsFile(), "AndroidManifest.xml")
其實并非如此簡單梅垄,只是這一句是最關(guān)鍵的厂捞。在gradle插件中增加了一些關(guān)鍵打印語句后,編譯過程中得到了以下錯誤提示:
Could not get unknown property 'manifestOutputDirectory' for task ':app:processDebugManifest' of type com.android.build.gradle.tasks.ProcessMultiApkApplicationManifest
百度了一下队丝,沒有任何相關(guān)記錄靡馁,畢竟距離 Android Gradle Plugin:4.1.0
正式發(fā)布才過去2個月,只好自給自足机久。
很明顯是讀取manifest文件位置的屬性失效了臭墨,那最直接的方法就是看源碼。找到 Android Gradle Plugin:4.1.0
的jar包看看就行膘盖。
又是百度一下胧弛,很可惜,沒有下載地址衔憨。
上JCenter找叶圃,結(jié)果JCenter倉庫只更新到2.x版本。
也對践图,好像是從 Android Studio 3.0
開始掺冠,google就將 Android Gradle Plugin
轉(zhuǎn)移至 google()
倉庫了,那只能去 google()
倉庫找了,一時半會也不知道具體地址德崭,以前的編譯過程中也沒留意看studio的編譯日志輸出斥黑,當(dāng)然如果是一個全新工程環(huán)境,編譯一下眉厨,肯定能找到倉庫地址的锌奴,不過我懶得搞。
先到AS的緩存路徑下碰碰運(yùn)氣吧憾股,不過碰運(yùn)氣也得先有個方向鹿蜀,別忘了Android Gradle Plugin
的classpath配置:
classpath 'com.android.tools.build:gradle:4.1.0'
果不其然,在以下路徑找到了:
/Users/jackie/.gradle/caches/modules-2/files-2.1/com.android.tools.build/gradle
加載過的各種版本都有服球,直接拿到 4.1.0
的jar包看源碼茴恰,在 ProcessMultiApkApplicationManifest.class
中找到了以下代碼:
File mergedManifestOutputFile = new File(((Directory)getMultiApkManifestOutputDirectory().get()).getAsFile(),
FileUtils.join(new String[] { dirName,
"AndroidManifest.xml" }));
同時還有一個抽象方法:
public abstract DirectoryProperty getMultiApkManifestOutputDirectory();
看來屬性已經(jīng)變成了 multiApkManifestOutputDirectory
。
如果不確定斩熊,我們再看看 4.0.2
的源碼往枣,在 ProcessApplicationManifest.class
中找到了以下代碼:
File manifestOutputFile = new File(((Directory)getManifestOutputDirectory().get()).getAsFile(), FileUtils.join(new String[] { apkData.getDirName(), "AndroidManifest.xml" }));
很明顯,在 4.0.2
版本時粉渠,獲取manifest文件路徑的屬性確實是 manifestOutputDirectory
分冈,而task本質(zhì)上是一個 ProcessApplicationManifest
實例,但從 4.1.0
版本開始霸株, task變?yōu)?ProcessMultiApkApplicationManifest
的實例雕沉,屬性變?yōu)?multiApkMnifestOutputDirectory
了。
好了淳衙,剩下的就是做一下版本兼容了蘑秽,大功告成饺著。
new File(output.processManifestProvider.get().multiApkManifestOutputDirectory.get().getAsFile(), "AndroidManifest.xml")
總結(jié)
大部分基于gradle的編譯腳本箫攀,其工作原理都一樣,就是在編寫自定義的task幼衰、在某個預(yù)設(shè)的task之前或之后做自定義的特殊處理等等靴跛,更高級一點的gradle插件也不例外。
而 Android Gradle Plugin
同樣也只是一個Google官方開發(fā)的gradle插件渡嚣,每次升級版本都會伴隨著一些“task名變更”梢睛、“task處理內(nèi)容變更”、“task執(zhí)行順序變更”等等的更新识椰,這些更新很可能就會影響到我們這些基于其“預(yù)置task”做特殊處理的gradle插件绝葡,所以大部分版本兼容問題都應(yīng)該從這個方向出發(fā)調(diào)查。
另外腹鹉,有時候Gradle的升級也會帶來一些兼容問題藏畅。