maven(android-maven-plugin3.8.0)打包apk无法启动,apklib依赖包的资源索引出错(R文件与主模块冲突)问题解析
近期在用maven,遇到了一個問題,用maven打出的apk有問題無法啟動,但是用idea打包的就是正常的。
日志中顯示的問題是,一個apklib形式的依賴包中的一個資源出現了問題。反編譯對比maven包和idea包,找到了問題所在。
假設: 主模塊包名為com.android.main
? ? ? ? ? ? apklib依賴包包名為com.android.apklib
? ? ? ? ? ??出問題的資源(layout)名為MyView
問題: apk打包后apklib依賴包的資源文件會與主模塊的資源整合到一起,依賴包引用資源實際上是在主模塊的R文件中查找對應資源。
1)maven包中: 在com.android.main下的R文件中MyView的值為0x7f050001;而在com.android.apklib下的R文件中MyView的值為0x7f070001,而且程序內使用該資源時的索引也是0x7f070001。這樣程序運行到這段代碼時,會去主模塊的R文件中找0x7f070001,然而主模塊中0x7f070001對應的資源并不是一個layout,所以就會出錯。
2)idea包中:倆個R文件中MyView的值相同,所以能夠正確的找到資源,程序不會出錯。
這樣就知道了問題,但是問題是如何出現的?
經過對maven打印日志查看,整理了一個打包的過程如下:
1)將所有依賴包拷貝到項目 /target/unpacked-libs 下,整合資源文件,然后生成主模塊和各依賴包的R.java等文件
2)編譯class文件,包括剛才生成的對應包的R文件。注意:編譯com.android.apklib下的java文件時,代碼中對應資源的索引與(1)生成的com.android.apklib包下的R文件一致
3)生成dex
4)生成apk
(maven打包可以用"mvn clean package"即可。不過也可以像上面那樣細分成四步"mvn clean android:generate-sources compile android:dex android:apk")
這樣我們就注意到,雖然運行時依賴包會在主模塊R文件中查找資源,但是編譯時還是會根據自己包下的R文件來編譯。
用maven只處理資源(mvn clean android:generate-sources),以便查看生成的R.java文件,發現問題產生的原因:
生成的R.java文件,主模塊與依賴包是有沖突的,同一個資源對應不同的索引。這樣編譯的時候依賴包代碼中的資源索引就是有問題的,就會導致問題的出現。那么說明maven在生成R.java文件時是有問題的。
繼續查看maven打印日志,找到了生成R,java文件對應的日志部分,是執行了aapt的命令。如下:
aapt.exe package -f --no-crunch -I D:\AndroidSDK\sdk\platforms\android-16\android.jar -M D:\項目目錄\AndroidManifest.xml -S D:\項目目錄\res -S D:\項目目錄\target\unpacked-libs/依賴包名/res -A D:\項目目錄\target\generated-sources\combined-assets\assets -m -J D:\項目目錄\target\generated-sources\r --output-text-symbols D:\項目目錄\target --auto-add-overlay aapt.exe package --non-constant-id -m -J D:\項目目錄\target\generated-sources\r --custom-package 主模塊包名 -M D:\項目目錄\target\unpacked-libs\依賴包名\AndroidManifest.xml -S D:\項目目錄\target\unpacked-libs\依賴包名\res --auto-add-overlay -A D:\項目目錄\target\unpacked-libs\依賴包名\combined-assets -I D:\AndroidSDK\sdk\platforms\android-16\android.jar;?
 ?
第一個命令就是生成主模塊R文件的,第二個命令則生成依賴包R文件。
(這里簡單介紹一下命令的主要組成:“-m -J D:\項目目錄\target\generated-sources\r”是R.java文件生成的路徑;“-M D:\項目目錄\AndroidManifest.xml”是獲取包名;“-A D:\項目目錄\target\generated-sources\combined-assets\assets”是assets目錄;“-S D:\項目目錄\res”是res目錄,有依賴包的話有多個,并注意順序;“--non-constant-id”生成的R.java文件中字段不是final類型;“--auto-add-overlay”資源文件自動覆蓋)
查看發現主模塊的R文件一切正常,那么就是第二條命令出的問題。由于自己之前沒有研究過打包,對aapt命令很不熟悉,所以一時也不知道該怎么修改。經過在網上查找,慢慢熟悉這條命令每部分的作用。第二條命令僅僅是生成依賴包的R文件,并未與主模塊進行關聯,這樣其實是單獨生成的,所以會起沖突。修改很簡單,如下:
aapt.exe package --non-constant-id -m -J D:\項目目錄\target\generated-sources\r --custom-package 主模塊包名 -M D:\項目目錄\target\unpacked-libs\依賴包名\AndroidManifest.xml -S D:\項目目錄\res -S D:\項目目錄\target\unpacked-libs\依賴包名\res --auto-add-overlay -A D:\項目目錄\target\unpacked-libs\依賴包名\combined-assets -I D:\AndroidSDK\sdk\platforms\android-16\android.jar;?
 ?
多加了主模塊的res進去,這樣其實生成的依賴包R文件與主模塊的是一摸一樣的,里面包含了所有資源,并不僅僅是依賴包的資源。這樣再編譯就不會有沖突的現象。
但是這僅僅是在命令層面解決問題,maven打包使用的是android-maven-plugin(com.jayway.maven.plugins.android.generation2),上面的命令都是由這個插件來執行的。不過還好這個插件是開源的,在github上可以找到。在github上找到這個開源項目,找到對應部分的代碼后發現構建的命令是正確的,原來已經有高手在5月中旬解決這個問題了。。。
原來是我的插件版本落后了,去中心倉庫查看發現android-maven-plugin最新版本是3.9.0-rc.3,這個版本已經解決該bug了。更新一下打包測試,一切正常。
雖然最后只是更新一下版本就解決了,但是也學到了不少東西,熟悉了打包流程,另外有興趣的話可以看看github上對應部分的代碼,
?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的maven(android-maven-plugin3.8.0)打包apk无法启动,apklib依赖包的资源索引出错(R文件与主模块冲突)问题解析的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Android Lint 去除重复资源
- 下一篇: Android 点击应用外的Url拉起应
