使用JavaWeb實現Android自動化構建打包加固多渠道-GUI篇(上)
一、前言:
Android打包是一件比較繁瑣又耗時的操作,相信很多朋友都想自己搞一個屬於自己的自動化構建程式,本文則是對這一程式的實現提供一個思路方法,沒有采用 Jenkins持續整合 這種方式來實現,但大概思路都大同小異。
關於本文需要了解的一些東西:
1. 實現思路為:使用JavaGUI做一個zip打包工具,將自定義配置資訊寫入專案並打包成zip格式,最終將檔案拖拽上傳至伺服器,伺服器進行一系列的操作:解壓,讀取配置,打包,加固,多渠道,最後下發至瀏覽器端進行自動下載,由於公司電腦是WindowsServer2012,所以內部實現是基於Windows命令的
2.Android專案構建配置都各有不同,所以本文主要提供一個實現思路
3.專案分為GUI端和Web端,均為Java實現,大部分操作都是流/IO,字串操作,簡單易懂
4.使用GUI端需要的配置:JDK環境變數
5.使用Web端需要的配置:IntelliJ IDEA、Tomcat伺服器、JDK環境變數、Gradle環境變數、360加固寶PC端、AndroidSDK、Android端所使用到的所有簽名檔案
6.開發工具,環境變數配置等本文就不多羅嗦了,畢竟不是使用說明書,但是會講一下Tomcat與IDEA配置所產生的1099埠衝突的坑,還有Gradle多配置
7.專案地址:
GUI端:[AutoBuildForAndroid-GUI](
Web端:[AutoBuildForAndroid-WEB](https://github.com/SmartKidsLOL/AutoBuildForAndroid-Web
二、GUI端的實現效果圖
三、實現思路
如圖所示,GUI端很簡單,使用也很簡單,介面也很醜(請不要在意這些細節…),因為公司的專案是加入了Tinker熱修復,考慮到對其他專案的適用性,所以目前只做了2個自定義配置,如圖所示,1是選擇打包方式是以普通Release或者Tinker熱修復包,2是輸入專案需要用到的打包簽名檔名。點選開始打包後便將這2個配置以Key-Value方式存入Properties檔案,以便伺服器以流的方式取出來存入。寫入配置後使用Zipentry壓縮流方式將專案資料夾壓縮為Zip格式輸出到指定目錄。
專案以Mvp簡單架構實現的,打包時會簡單校驗一下是否為Android專案資料夾。
注:自動化打包思路都是以修改並自定義配置Gradle檔案,但是前提是公司的業務及專案都可以用同樣的Gradle配置,比如三方依賴,ndk配置等主要配置都相同,但只有簽名,ApplicationID這些可變配置根據不同專案而不同,這種情況下可以將這些可變的變數配置寫入到GUI介面中,對同類型的專案進行不同的變數配置即可,最後直接將這些配置寫入到Gradle中,上傳到伺服器進行一系列操作即可。
所以根據實際情況,我並沒有將配置寫入Gradle檔案,而是另存為Properties檔案,這種方式也是想以不動不同專案的gradle配置前提,完成自動化打包。
四、使用方式
在你想要進行自動化打包的專案里加入以下2點:
1.在你的Android專案根目錄下建立 keystore.propertie 檔案,加入以下內容:
KEY_PATH=D\:/tools/your.jks // 改成你的簽名檔案地址
KEY_PASS=yourTest
ALIAS_NAME=yourTest
ALIAS_PASS=yourTest
2.開啟app下的gradle中加入以下程式碼:
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(rootProject.file("keystore.properties")))
android {
...
signingConfigs {
release {
try {
storeFile file(keystoreProperties['KEY_PATH'])
storePassword keystoreProperties['KEY_PASS']
keyAlias keystoreProperties['ALIAS_NAME']
keyPassword keystoreProperties['ALIAS_PASS']
} catch (Exception ex) {
throw new InvalidUserDataException(ex.toString())
}
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
...
}
}
...
}
上述程式碼和Java中使用流讀取Properties檔案無異。
Tips:如果你專案使用了Tinker,則可以自己指定基準包生成目錄,方便自定義伺服器端進行路徑配置,附上一份個人的Tinker配置Gradle檔案,最後在app下的gradle中進行apply引入,如果有需要,則可以參考
apply plugin: 'tinkerpatch-support'
/**
* TODO: 請按自己的需求修改為適應自己工程的引數
*/
def infoPath = file("${rootDir}/infoBak")
def baseInfo = "$rootProject.ext.baseInfoName"
def variantName = "$rootProject.ext.variantName"
/**
* 對於外掛各引數的詳細解析請參考
* http://tinkerpatch.com/Docs/SDK
*/
tinkerpatchSupport {
/** 可以在debug的時候關閉 tinkerPatch **/
/** 當disable tinker的時候需要新增multiDexKeepProguard和proguardFiles,
這些配置檔案本身由tinkerPatch的外掛自動新增,當你disable後需要手動新增
你可以copy本示例中的proguardRules.pro和tinkerMultidexKeep.pro,
需要你手動修改'tinker.sample.android.app'本示例的包名為你自己的包名, com.xxx字首的包名不用修改
**/
tinkerEnable = true
reflectApplication = true
/**
* 是否開啟加固模式,只能在APK將要進行加固時使用,否則會patch失敗。
* 如果只在某個渠道使用了加固,可使用多flavors配置
**/
protectedApp = true
/**
* 實驗功能
* 補丁是否支援新增 Activity (新增Activity的exported屬性必須為false)
**/
supportComponent = true
autoBackupApkPath = "${infoPath}"
appKey = "$rootProject.ext.appKey"
/** 注意: 若釋出新的全量包, appVersion一定要更新 **/
appVersion = "$rootProject.ext.versionName"
def pathPrefix = "${infoPath}/${baseInfo}/${variantName}/"
def name = "${project.name}-${variantName}"
baseApkFile = "${pathPrefix}/${name}.apk"
baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
baseResourceRFile = "${pathPrefix}/${name}-R.txt"
}
/**
* 用於使用者在程式碼中判斷tinkerPatch是否被使能
*/
android {
defaultConfig {
buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}"
}
}
/**
* 一般來說,我們無需對下面的引數做任何的修改
* 對於各引數的詳細介紹請參考:
* https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
*/
tinkerPatch {
ignoreWarning = false
useSign = true
dex {
dexMode = "jar"
pattern = ["classes*.dex"]
loader = []
}
lib {
pattern = ["lib/*/*.so"]
}
res {
pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
ignoreChange = []
largeModSize = 100
}
packageConfig {
}
sevenZip {
zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
// path = "/usr/local/bin/7za"
}
buildConfig {
keepDexApply = false
}
}
最後在專案根目錄下的Gradle中配置:
ext {
// tinker配置
versionName = "你的app versionName 如:1.0.0"
appKey = "你的Tinker Key"
variantName = "release"
baseInfoName = "最後一次構建的Release基準包資料夾名"
}
當打包時,所構建的基準包會生成在專案根目錄下的 infoBak 資料夾中,所以還需自己另行儲存最後一次基準包。並且此資料夾不會自動清除,編譯多次後會佔用非常大空間。。 所以如果不想每次手動刪除 infoBak 目錄的話,有2種方法,
1.在自定義的 tinkerPatchGradle中加入對Debug模式的判斷,如果是Debug則不開啟Tinker功能
2.在專案根目錄下的Gradle檔案中加入以下程式碼:
...
task clean(type: Delete) {
delete rootProject.buildDir
delete rootProject.file("infoBak") // 這行是要自己加入的
}
...
五、總結
經過GUI打包後,打出的zip包可以直接拖拽進瀏覽器開啟的伺服器地址,此外專案中會加入 AndroidToZip.properties 檔案,開啟檔案可以看到
build_pak_type=1
sign_file_name=yourKey
build_pak_type: 0代表是普通Release包,1代表的是Tinker基準包,伺服器會根據此值來獲取不同目錄下的 app-release.apk 檔案進行打包處理。
sign_file_name: yourKey就是你輸入的簽名檔案字首名,伺服器會根據此值來判斷使用哪一個簽名檔案進行打包處理。
至此,GUI端功能已實現,請耐心繼續看下一篇伺服器端的實現。