需求來(lái)源:項(xiàng)目提測(cè)后胡野,修改完bug總是需要自己手動(dòng)打包蛮浑,然后上傳到fir平臺(tái)上再通知測(cè)試下載安裝矿酵,浪費(fèi)了時(shí)間和人力婴梧,因此我們可以把Android項(xiàng)目部署到Jenkins平臺(tái)上,每次修改完bug后只需要在gitlib上提交下代碼辨绊,然后通知測(cè)試即可奶栖。
Jenkins安裝
下載地址:https://jenkins.io/zh/
安裝文檔:https://jenkins.io/zh/doc/pipeline/tour/getting-started/
按照默認(rèn)的推薦完成安裝即可。
Android環(huán)境
這些就不多說了门坷,本地的話應(yīng)該都有了宣鄙,如果部署到遠(yuǎn)程服務(wù)器上的話得安裝一下。
安裝Jenkins插件
Manage Jenkins >> Manage Plugins
- 搜索安裝Git插件(遠(yuǎn)程倉(cāng)庫(kù))
- 搜索安裝Git Parameter插件(配置選擇構(gòu)建分支)
- 搜索安裝Gradle插件(Android構(gòu)建工具)
- 搜索安裝description setter plugin插件(添加構(gòu)建后的描述)
- 下載安裝fir插件(自動(dòng)上傳apk到fir平臺(tái))
也可以直接在https://plugins.jenkins.io/上搜索下載插件默蚌,然后在Jenkins插件管理上傳hpi文件冻晤。
配置環(huán)境參數(shù)
-
Manage Jenkins >> Configure System
配置ANDROID_HOME和ANDROID_NDK_HOME環(huán)境變量,即sdk和ndk的安裝路徑绸吸,然后保存鼻弧。 -
Manage Jenkins >> Global Tool Configuration
配置jdk,git锦茁,gradle的安裝路徑攘轩,git的安裝路徑在Windows上填git.exe的路徑,比如:git\bin\git.exe码俩,linux上填git/bin/git度帮,然后保存。 -
Manage Jenkins >> Configure Global Security
選擇Safe Html(描述等可使用html標(biāo)簽)稿存,然后保存笨篷。
創(chuàng)建項(xiàng)目
創(chuàng)建一個(gè)自由風(fēng)格的項(xiàng)目,然后OK瓣履,進(jìn)入項(xiàng)目配置頁(yè)面率翅。
下面,我們來(lái)進(jìn)行打包:
掃描二維碼或點(diǎn)擊下載鏈接痰洒,就會(huì)直接跳轉(zhuǎn)到fir的下載地址了瓢棒,這個(gè)下載地址是攜帶release_id的,每次構(gòu)建后的下載地址都是唯一的丘喻,而不是fir的短鏈接脯宿,使用短鏈接的話直接自己生成一個(gè)二維碼放在項(xiàng)目描述里面就行了,不用這么麻煩泉粉。
jenkins.sh
#!/bin/bash
# Jenkins打包時(shí)會(huì)執(zhí)行此腳本连霉,將buildId生成在一個(gè)本地文件中
fileName="jenkins_build_id.properties"
touch ${fileName}
echo "文件創(chuàng)建成功"
true > ${fileName}
echo "BUILD_ID=$1" >> ${fileName}
使用腳本將構(gòu)建id寫入項(xiàng)目文件里(windows也可使用python)榴芳,打包前可以執(zhí)行腳本做不少事呢可真是。
jenkins-build.gradle
import groovy.json.JsonSlurper
/**
* 獲取Jenkins打包ID
* @return
*/
String getJenkinsBuild() {
def buildFile = project.rootProject.file("jenkins_build_id.properties")
if (buildFile.exists()) {
def buildFileProperties = new Properties()
def fis = new FileInputStream(buildFile)
buildFileProperties.load(fis)
def id = buildFileProperties['BUILD_ID']
fis.close()
return id
} else {
return null
}
}
/**
* 刪除Jenkins打包生成的文件
*/
void deletedJenkinsBuildFile() {
def filePath = project.rootProject.file("jenkins_build_id.properties").absolutePath
def buildFile = new File(filePath)
if (buildFile.exists()) {
buildFile.delete()
}
}
/**
* 上傳打包完成后的apk到fir平臺(tái)上,并上傳BUILD_ID和下載地址到服務(wù)器上
*/
task uploadApk2Fir() {
doLast {
//根據(jù)自己的apk路徑填寫
def sb = new StringBuilder()
sb.append(project.buildDir)
.append(File.separator)
.append("outputs")
.append(File.separator)
.append("apk")
.append(File.separator)
.append("release")
.append(File.separator)
.append("AndResGuard_app-release")
.append(File.separator)
.append("app-release_7zip_aligned_signed.apk")
def filePath = sb.toString()
println "apk路徑:$filePath"
def apkFile = new File(filePath)
def buildId = getJenkinsBuild()
if (buildId == null || !apkFile.exists()) {
println "未找到打包id或apk"
return
}
println "即將上傳 $apkFile 到fir"
//fir平臺(tái)的應(yīng)用ID跺撼,可在應(yīng)用詳情里查看
def FIR_APP_ID = "xxxxxxxxxxxxxxxxx"
//fir平臺(tái)的應(yīng)用API TOKEN
def FIR_API_TOKEN = "xxxxxxxxxxxxxxxxx"
def packageName = "com.android.test"
def appInfo = ("curl -X POST -d type=android&bundle_id=$packageName&api_token=$FIR_API_TOKEN http://api.fir.im/apps").execute().text
def appInfoBean = new JsonSlurper().parseText(appInfo)
def token = appInfoBean["cert"]["binary"]["token"]
def key = appInfoBean["cert"]["binary"]["key"]
def url = appInfoBean["cert"]["binary"]["upload_url"]
def log = "BUILD_ID:${buildId},Upload-By-Jenkins!!!"
def versionName = project.versionName.toString()
def versionCode = project.versionCode.toInteger()
def upExecute = new StringBuilder()
.append("curl -X POST --form file=@$apkFile")
.append(" -F token=$token")
.append(" -F key=$key")
.append(" -F x:name=test")
.append(" -F x:version=$versionName")
.append(" -F x:build=$buildId")
.append(" -F x:changelog=$log")
.append(" $url").toString()
def uploadInfo = (upExecute).execute().text
def uploadResultBean = new JsonSlurper().parseText(uploadInfo)
def isCompleted = uploadResultBean["is_completed"]
if (isCompleted) {
println "上傳 $apkFile 完成"
def apkInfoText = ("curl -X GET -d api_token=$FIR_API_TOKEN http://api.fir.im/apps/$FIR_APP_ID").execute().text
def apkInfoBean = new JsonSlurper().parseText(apkInfoText)
def masterReleaseId = apkInfoBean["master_release_id"]
println "獲取到最新releaseId為$masterReleaseId"
//上傳成功后可獲取到apk的release_id,將build_id和release_id一起存入到數(shù)據(jù)庫(kù)表中
def params = "buildId=$buildId&releaseId=$masterReleaseId&versionCode=$versionCode&versionName=$versionName&type=test"
URL upUrl = new URL("http://test.api/test_jenkins.php?$params")
HttpURLConnection conn = (HttpURLConnection) upUrl.openConnection()
conn.setRequestMethod("GET")
conn.connect()
def responseCode = conn.getResponseCode()
if (responseCode == HttpURLConnection.HTTP_OK) {
println "更新上傳信息完成"
} else {
println "更新上傳信息失敗"
}
} else {
println "上傳 $apkFile 失敗"
}
deletedJenkinsBuildFile()
}
}
上傳apk的task任務(wù)窟感,也可以根據(jù)這個(gè)來(lái)修改一下將uploadApk2Fir加入到android構(gòu)建完成后自動(dòng)執(zhí)行,也就是不通過Jenkins打包歉井,手動(dòng)打包后上傳apk到fir平臺(tái)上面柿祈。
gradle.properties
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
android.useAndroidX=true
android.enableJetifier=true
android.useDeprecatedNdk=true
#項(xiàng)目的配置參數(shù)
#項(xiàng)目版本號(hào)
versionCode=100
#項(xiàng)目版本名稱
versionName=6.0.2
#最低SDK版本
minSdkVersion=16
#目標(biāo)SDK版本
targetSdkVersion=28
#編譯運(yùn)行版本
compileSdkVersion=28
#是否可配置運(yùn)行環(huán)境
CAN_CHANGE_NET=true
#運(yùn)行環(huán)境
BASE_URL=http://android.test.api/
在Jenkins中配置的選擇參數(shù)會(huì)替換這里面的值,所以可以配置一些需要的變量參數(shù)在項(xiàng)目里使用哩至。
介紹完了躏嚎,當(dāng)然Jenkins的功能不止這些,有興趣的自己摸索菩貌。后面還部署了一個(gè)Android原生和Flutter的混合項(xiàng)目卢佣,踩坑太多都是淚,最后終于搭建成功箭阶。有問題的同學(xué)可以評(píng)論虚茶,看到了我會(huì)回復(fù)的。
那個(gè)尾膊,參考鏈接具體是哪些都忘了媳危,部署的時(shí)間有點(diǎn)長(zhǎng)了,現(xiàn)在百度搜一下一大堆冈敛,找不到原來(lái)借鑒的了待笑,在此感謝廣大的開發(fā)者及開源分享精神。