Jenkins部署Android项目并上传fir平台及显示二维码下载

需求来源:项目提测后,修改完bug总是需要自己手动打包,然后上传到fir平台上再通知测试下载安装,浪费了时间和人力,因此我们可以把Android项目部署到Jenkins平台上,每次修改完bug后只需要在gitlib上提交下代码,然后通知测试即可。

Jenkins安装

下载地址:https://jenkins.io/zh/
安装文档:https://jenkins.io/zh/doc/pipeline/tour/getting-started/
按照默认的推荐完成安装即可。

Android环境

这些就不多说了,本地的话应该都有了,如果部署到远程服务器上的话得安装一下。

安装Jenkins插件

Manage Jenkins >> Manage Plugins

  • 搜索安装Git插件(远程仓库)
  • 搜索安装Git Parameter插件(配置选择构建分支)
  • 搜索安装Gradle插件(Android构建工具)
  • 搜索安装description setter plugin插件(添加构建后的描述)
  • 下载安装fir插件(自动上传apk到fir平台)

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

上传插件

配置环境参数
  • Manage Jenkins >> Configure System
    配置sdk和ndk环境变量

    配置ANDROID_HOMEANDROID_NDK_HOME环境变量,即sdk和ndk的安装路径,然后保存。
  • Manage Jenkins >> Global Tool Configuration
    配置jdk,git和gradle环境

    配置jdkgitgradle的安装路径,git的安装路径在Windows上填git.exe的路径,比如:git\bin\git.exelinux上填git/bin/git,然后保存。
  • Manage Jenkins >> Configure Global Security
    选择safe html

    选择Safe Html(描述等可使用html标签),然后保存。
创建项目
创建项目

创建一个自由风格的项目,然后OK,进入项目配置页面。


config

config

config

config

config

config

config

config
基本的配置就是这些了,大家可以根据自己的需求来进行配置。
下面,我们来进行打包:
开始构建

打包成功

扫描二维码或点击下载链接,就会直接跳转到fir的下载地址了,这个下载地址是携带release_id的,每次构建后的下载地址都是唯一的,而不是fir的短链接,使用短链接的话直接自己生成一个二维码放在项目描述里面就行了,不用这么麻烦。
jenkins.sh

#!/bin/bash
# Jenkins打包时会执行此脚本,将buildId生成在一个本地文件中
fileName="jenkins_build_id.properties"
touch ${fileName}
echo "文件创建成功"
true > ${fileName}
echo "BUILD_ID=$1" >> ${fileName}

使用脚本将构建id写入项目文件里(windows也可使用python),打包前可以执行脚本做不少事呢可真是。
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构建完成后自动执行,也就是不通过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
#是否可配置运行环境
CAN_CHANGE_NET=true
#运行环境
BASE_URL=http://android.test.api/

在Jenkins中配置的选择参数会替换这里面的值,所以可以配置一些需要的变量参数在项目里使用。

介绍完了,当然Jenkins的功能不止这些,有兴趣的自己摸索。后面还部署了一个Android原生和Flutter的混合项目,踩坑太多都是泪,最后终于搭建成功。有问题的同学可以评论,看到了我会回复的。
那个,参考链接具体是哪些都忘了,部署的时间有点长了,现在百度搜一下一大堆,找不到原来借鉴的了,在此感谢广大的开发者及开源分享精神。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容