Jenkins部署Android項目并上傳fir平臺及顯示二維碼下載

需求來源:項目提測后,修改完bug總是需要自己手動打包,然后上傳到fir平臺上再通知測試下載安裝,浪費了時間和人力,因此我們可以把Android項目部署到Jenkins平臺上,每次修改完bug后只需要在gitlib上提交下代碼,然后通知測試即可。

Jenkins安裝

下載地址:https://jenkins.io/zh/
安裝文檔:https://jenkins.io/zh/doc/pipeline/tour/getting-started/
按照默認的推薦完成安裝即可。

Android環(huán)境

這些就不多說了,本地的話應該都有了,如果部署到遠程服務器上的話得安裝一下。

安裝Jenkins插件

Manage Jenkins >> Manage Plugins

  • 搜索安裝Git插件(遠程倉庫)
  • 搜索安裝Git Parameter插件(配置選擇構建分支)
  • 搜索安裝Gradle插件(Android構建工具)
  • 搜索安裝description setter plugin插件(添加構建后的描述)
  • 下載安裝fir插件(自動上傳apk到fir平臺)

也可以直接在https://plugins.jenkins.io/上搜索下載插件,然后在Jenkins插件管理上傳hpi文件。

上傳插件

配置環(huán)境參數
  • Manage Jenkins >> Configure System
    配置sdk和ndk環(huán)境變量

    配置ANDROID_HOMEANDROID_NDK_HOME環(huán)境變量,即sdk和ndk的安裝路徑,然后保存。
  • Manage Jenkins >> Global Tool Configuration
    配置jdk,git和gradle環(huán)境

    配置jdk,gitgradle的安裝路徑,git的安裝路徑在Windows上填git.exe的路徑,比如:git\bin\git.exe,linux上填git/bin/git,然后保存。
  • Manage Jenkins >> Configure Global Security
    選擇safe html

    選擇Safe Html(描述等可使用html標簽),然后保存。
創(chuàng)建項目
創(chuàng)建項目

創(chuàng)建一個自由風格的項目,然后OK,進入項目配置頁面。


config

config

config

config

config

config

config

config
基本的配置就是這些了,大家可以根據自己的需求來進行配置。
下面,我們來進行打包:
開始構建

打包成功

掃描二維碼或點擊下載鏈接,就會直接跳轉到fir的下載地址了,這個下載地址是攜帶release_id的,每次構建后的下載地址都是唯一的,而不是fir的短鏈接,使用短鏈接的話直接自己生成一個二維碼放在項目描述里面就行了,不用這么麻煩。
jenkins.sh

#!/bin/bash
# Jenkins打包時會執(zhí)行此腳本,將buildId生成在一個本地文件中
fileName="jenkins_build_id.properties"
touch ${fileName}
echo "文件創(chuàng)建成功"
true > ${fileName}
echo "BUILD_ID=$1" >> ${fileName}

使用腳本將構建id寫入項目文件里(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平臺上,并上傳BUILD_ID和下載地址到服務器上
 */
task uploadApk2Fir() {
    doLast {
    //根據自己的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平臺的應用ID,可在應用詳情里查看
        def FIR_APP_ID = "xxxxxxxxxxxxxxxxx"
        //fir平臺的應用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一起存入到數據庫表中
            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任務,也可以根據這個來修改一下將uploadApk2Fir加入到android構建完成后自動執(zhí)行,也就是不通過Jenkins打包,手動打包后上傳apk到fir平臺上面。
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
#項目的配置參數
#項目版本號
versionCode=100
#項目版本名稱
versionName=6.0.2
#最低SDK版本
minSdkVersion=16
#目標SDK版本
targetSdkVersion=28
#編譯運行版本
compileSdkVersion=28
#是否可配置運行環(huán)境
CAN_CHANGE_NET=true
#運行環(huán)境
BASE_URL=http://android.test.api/

在Jenkins中配置的選擇參數會替換這里面的值,所以可以配置一些需要的變量參數在項目里使用。

介紹完了,當然Jenkins的功能不止這些,有興趣的自己摸索。后面還部署了一個Android原生和Flutter的混合項目,踩坑太多都是淚,最后終于搭建成功。有問題的同學可以評論,看到了我會回復的。
那個,參考鏈接具體是哪些都忘了,部署的時間有點長了,現在百度搜一下一大堆,找不到原來借鑒的了,在此感謝廣大的開發(fā)者及開源分享精神。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容