Android Studio分模組自動化構建實戰,androidstudio
Android Studio分模組自動化構建實戰
@author ASCE1885的 Github 簡書 微博 CSDN
最近在使用Android Studio+Gradle做一個基礎架構SDK項目,該架構主要實現每個app都需要的基礎能力,例如網路請求,圖片緩衝,json解析,日誌記錄等等。
眾所周知,AndroidStudio中應該盡量使用Module來進行模組的劃分,既能達到模組解耦的目的,也能在必要的時候輕鬆實現分模組打包,特別是在SDK項目中。那麼什麼是分模組打包呢?就是我們可以根據第三方使用者的需求,自動化的提供SDK的全量版本,部分功能版本以及最小功能版本等等。
我們的項目結構如下所示,每個功能獨立成一個Module:
由於我們的模組都是純程式碼的,沒有包含資源檔,因此不是以aar包的形式而是使用jar包形式對外提供。順便提一句,產生的aar包預設路徑是:
build/output/aar/
而jar包可以到如下路徑尋找:
build/intermediates/bundles/debug/classes.jarbuild/intermediates/bundles/release/classes.jar
Jar包的合并
從項目工程中可以看到,我們的project包含多個module,每個基礎功能的module最終編譯產生的都是一個classes.jar。因此project最終會產生一堆的jar包,而到了對外發布時,我們要提供一個單獨的jar包出去,因此,就需要對jar包進行合并。很不幸,Android Studio沒有提供這樣的功能,因此只能靠自己寫指令碼調用jar命令來實現了,開啟命令列terminal,輸入jar,就可以列印出jar的用法,如下所示:
guhaoxindeMacBook-Pro:~ guhaoxin$ jar用法: jar {ctxui}[vfm0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ...選項包括: -c 建立新的歸檔檔案 -t 列出歸檔目錄 -x 從檔案中提取指定的 (或所有) 檔案 -u 更新現有的歸檔檔案 -v 在標準輸出中產生詳細輸出 -f 指定歸檔檔案名稱 -m 包含指定資訊清單檔中的清單資訊 -e 為捆綁到可執行 jar 檔案的獨立應用程式 指定應用程式進入點 -0 僅儲存; 不使用方式任何 ZIP 壓縮 -M 不建立條目的資訊清單檔 -i 為指定的 jar 檔案產生索引資訊 -C 更改為指定的目錄並包含其中的檔案如果有任何目錄檔案, 則對其進行遞迴處理。資訊清單檔名, 歸檔檔案名稱和進入點名稱的指定順序與 'm', 'f' 和 'e' 標記的指定順序相同。樣本 1: 將兩個類檔案歸檔到一個名為 classes.jar 的歸檔檔案中: jar cvf classes.jar Foo.class Bar.class 樣本 2: 使用現有的資訊清單檔 'mymanifest' 並 將 foo/ 目錄中的所有檔案歸檔到 'classes.jar' 中: jar cvfm classes.jar mymanifest -C foo/ .
使用jar命令,主要實現兩個功能:
- 將所有jar包的class檔案解壓到某個目錄中
- 將解壓後所有class檔案的重新壓縮為一個單獨的jar包
由於jar命令不能指定最終輸出的目錄,因此我們需要首先cd到用於存放解壓後class檔案的一個臨時目錄,然後依次對所有jar包進行解壓操作,解壓命令如下所示:
jar -xvf ../../hfasynchttp/build/intermediates/bundles/debug/classes.jar
當所有的jar包都解壓完畢後,接著執行壓縮命令,這樣就得到一個單獨的jar包了:
jar -cvfM AndroidHyperion_${version}_debug.jar .
分模組自動化構建
自動化構建包括本地構建和Jenkins構建兩部分,本地構建主要用於開發自己調試使用,Jenkins構建主要用於測試,產品等取包以及跑Monkey使用。
本地構建
本地構建指令檔位於工程根目錄下的build_local.sh,該指令碼的主要功能有:
- 調用gradlew命令執行gradle編譯,產生各個Module的jar包
- 解壓各個Module產生的jar包,並把解壓後的class檔案重新打包成單獨的一個jar包
- 分模組打包功能通過定義Boolean變數值進行控制
- 輸出目錄是output
build_local.sh檔案內容如下:
#!/bin/sh#使用Gradle編譯各個module./gradlew clean./gradlew build --stacktrace --debug#進入輸出目錄cd output#清空輸出目錄rm -rf *#建立輸出子目錄mkdir tempmkdir debugmkdir release#定義sdk版本號碼version="1.0.0"#定義模組是否打包標識is_include_hfasynchttp=trueis_include_bitmapfun=trueis_include_hfjson=trueis_include_hflogger=true#省略其他...#解壓所有debug版本的jar包到temp目錄中cd tempif $is_include_hfasynchttp; then jar -xvf ../../hfasynchttp/build/intermediates/bundles/debug/classes.jarfiif $is_include_bitmapfun; then jar -xvf ../../hfbitmapfun/build/intermediates/bundles/debug/classes.jarfiif $is_include_hfjson; then jar -xvf ../../hfjson/build/intermediates/bundles/debug/classes.jarfiif $is_include_hflogger; then jar -xvf ../../hflogger/build/intermediates/bundles/debug/classes.jarfi#壓縮所有debug版本的class檔案到一個獨立的jar包中jar -cvfM AndroidHyperion_${version}_debug.jar .#拷貝檔案mv AndroidHyperion_${version}_debug.jar ../debug#清空temp目錄rm -rf *#解壓所有release版本的jar包到temp目錄中if $is_include_hfasynchttp; then jar -xvf ../../hfasynchttp/build/intermediates/bundles/release/classes.jarfiif $is_include_bitmapfun; then jar -xvf ../../hfbitmapfun/build/intermediates/bundles/release/classes.jarfiif $is_include_hfjson; then jar -xvf ../../hfjson/build/intermediates/bundles/release/classes.jarfiif $is_include_hflogger; then jar -xvf ../../hflogger/build/intermediates/bundles/release/classes.jarfi#壓縮所有release版本的class檔案到一個jar包中jar -cvfM AndroidHyperion_${version}_release.jar .#拷貝檔案mv AndroidHyperion_${version}_release.jar ../release#刪除temp目錄cd ..rm -rf temp
Jenkins構建
Jenkins編譯指令檔位於工程根目錄下的build_jenkins.sh,該指令碼的主要功能有:
- 調用gradlew命令執行gradle編譯,產生各個Moudle的jar包
- 解壓各個Module產生的jar包,並把解壓後的class檔案重新打包成單獨的一個jar包
- 分模組打包功能通過Jenkins上面配置的參數化構建參數進行控制
- 輸出目錄是output
可以看到,和本地構建唯一的區別就是分模組的參數化構建參數是定義在Jenkins上的,而不是定義在本地指令碼中的,為了完整清晰起見,我們還是把完整的指令檔貼出來:
#!/bin/sh./gradlew clean./gradlew build --stacktrace --debug#進入輸出目錄cd output#清空輸出目錄rm -rf *#建立輸出子目錄mkdir tempmkdir debugmkdir releasecd temp#解壓所有debug版本的jar包if $is_include_hfasynchttp; then jar -xvf ../../hfasynchttp/build/intermediates/bundles/debug/classes.jarfiif $is_include_bitmapfun; then jar -xvf ../../hfbitmapfun/build/intermediates/bundles/debug/classes.jarfiif $is_include_hfjson; then jar -xvf ../../hfjson/build/intermediates/bundles/debug/classes.jarfiif $is_include_hflogger; then jar -xvf ../../hflogger/build/intermediates/bundles/debug/classes.jarfi#壓縮所有debug版本的class檔案到一個jar包中jar -cvfM AndroidHyperion_${version}_debug.jar .#移動產生的jar包到debug目錄mv AndroidHyperion_${version}_debug.jar ../debug#清空temp目錄rm -rf *#解壓所有release版本的jar包if $is_include_hfasynchttp; then jar -xvf ../../hfasynchttp/build/intermediates/bundles/release/classes.jarfiif $is_include_bitmapfun; then jar -xvf ../../hfbitmapfun/build/intermediates/bundles/release/classes.jarfiif $is_include_hfjson; then jar -xvf ../../hfjson/build/intermediates/bundles/release/classes.jarfiif $is_include_hflogger; then jar -xvf ../../hflogger/build/intermediates/bundles/release/classes.jarfi#壓縮所有release版本的class檔案到一個jar包中jar -cvfM AndroidHyperion_${version}_release.jar .#移動產生的jar包到release目錄mv AndroidHyperion_${version}_release.jar ../release#刪除temp目錄cd ..rm -rf temp
local和Jenkins參數化構建參數定義
| 類型 |
名稱 |
預設值 |
描述 |
| String |
version |
1.0.0 |
Hyperion sdk版本號碼 |
| Boolean |
is_include_hfasynchttp |
true |
是否打包hfasynchttp |
| Boolean |
is_include_bitmapfun |
true |
是否打包hfbitmapfun |
| Boolean |
is_include_hfjson |
true |
是否打包hfjson |
| Boolean |
is_include_hflogger |
true |
是否打包hflogger |