Ubuntu搭建Jenkins+Android自动化打包

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

本文主要介绍如何在Ubuntu搭建Jenkins实现Android项目的自动化打包,一般部署在我们的服务器,这里我通过虚拟机安装Ubuntu来进行演示

目录

环境配置

下载并配置java环境

  1. 通过java官网下载对应jdk版本
  2. 打开终端,输入以下命令行进行解压
tar -zxvf jdk-8u181-linux-x64.tar.gz
  1. 将解压后的文件夹移动到/opt目录下
sudo mv jdk1.8.0_181 /opt/
  1. 修改环境变量
sudo vi ~/.bashrc

在末尾添加如下配置:

#set Java environment
export JAVA_HOME=/opt/jdk1.8.0_181
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
  1. 保存退出,使用source命令使其生效
source ~/.bashrc
  1. 验证java环境是否配置成功
java -vsersion

Git安装

sudo apt-get install git

安装配置nginx

为了使得外部能下载相关资源,安装并配置本地目录映射

sudo apt-get install nginx
sudo service nginx start
sudo vi /etc/nginx/nginx.conf

简单修改配置文件,添加如下内容

server {
        listen 81;
        server_name 192.168.80.140;
        client_max_body_size 4G;
        root /home/cc/pkg_bak;
        location / {
                autoindex on;
                autoindex_exact_size on;
                autoindex_localtime on;
        }
}

使配置生效

sudo service nginx reload 

Jenkins安装

可以根据Jenkins官网文档进行安装

wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt-get update
sudo apt-get install jenkins

修改Jenkins配置

sudo vi /etc/default/jenkins

修改端口号

# 默认是8080端口
HTTP_PORT=8081

启动Jenkins

sudo service jenkins start

启动完成,通过浏览器访问 http://192.168.80.140:8081 即可看到启动界面

启动jenkins.png

根据提示通过查看 /var/lib/jenkins/secrets/initialAdminPassword 获取到密码即可

然后根据提示安装需要的插件,创建用户,完成后出现下面的界面,Jenkins 搭建完成

搭建完成.png

配置Android项目编译环境

安装常用插件

路径:系统管理-插件管理-可选插件,在搜索框输入你需要安装的插件进行安装即可

常用插件有以下:

  • Git plugin
  • Git Parameter
  • GitLab Plugin
  • Gradle Plugin
  • Android Emulator Plugin
  • Android Lint Plugin
  • description setter plugin
  • Checkstyle Plug-in
  • FindBugs Plug-in
  • PMD Plug-in
  • SSH Agent
  • Role-based Authorization Strategy
  • OWASP Markup Formatter Plugin

配置Git

路径:系统管理-全局工具配置-Git

因为Ubuntu已经安装了Git,所以默认配置即可

配置Git.png

配置JDK

路径:系统管理-全局工具配置-JDK

下载需要一个Oracle的帐号,添加完账户就可以了

配置JDK.png

配置Gradle

路径:系统管理-全局工具配置-Gradle

配置Gradle.png

配置Android SDK

路径:系统管理-系统设置-Android

填写SDK的存放路径,同时勾选自动下载,警告可以忽略

配置AndroidSDK.png

这个时候有一个问题需要注意,必须在sdk的目录下 添加license文件,去你本地的sdk下拷贝一份进去

新建工程

新建工程.png

填写General

一般会勾选丢弃旧的构建,防止服务器累计过多次的编译

填写General.png

填写源码管理

使用Git来拉取代码

填写源码管理.png

构建配置

配置构建界面.png

上内容述执行的是:

  1. 重置,清空项目内容
  2. 将存在服务器的密钥信息、sdk目录等信息(local.properties),拷贝到项目中
  3. 使用工程下的gradlew来构建项目,保持gradle版本与本地一致,Tasks中输入项目要编译的任务

因为我的密钥读取是放到 local.properties 文件中的,所以可以做到服务器管控打包密钥,local.properties 内容如下

KEY_STORE=密钥路径
KEY_STORE_PASSWORD=密码
KEY_ALIAS=密钥别名
KEY_ALIAS_PASSWORD=密码
sdk.dir=sdk路径

构建后配置

需要收集相应的apk和mapping文件


配置构建后界面.png

最后点击保存,通过简单配置,到此已经可以实现项目的构建了

更多定制化配置

通过Git Parameter插件实现分支选择

填写GitParameter.png

集成360加固

从360官方下载相关文件,拷贝到/home/cc/backup/360jiagu目录,使用命令行的方式进行加固,详细可以查看官方说明文档,这里采用编写脚本文件实现自动加固,文件内容如下:

脚本jiagu_360.sh存放路径/home/cc/backup/360jiagu/jiagu

#!/bin/bash

BASE_JAR=/home/cc/backup/360jiagu/jiagu/jiagu.jar
JIA_GU_NAME=账号
JIA_GU_PSD=密码

echo "------ jiagu running! ------"
java -jar ${BASE_JAR} -version
java -jar ${BASE_JAR} -login ${JIA_GU_NAME} ${JIA_GU_PSD}

LOCAL_PATH=$1
echo "local.properties:${LOCAL_PATH}"

KEY_STORE=`cat ${LOCAL_PATH} |grep KEY_STORE= | awk -F= '{print $2}'`
KEY_STORE_PASSWORD=`cat ${LOCAL_PATH} |grep KEY_STORE_PASSWORD= | awk -F= '{print $2}'`
KEY_ALIAS=`cat ${LOCAL_PATH} |grep KEY_ALIAS= | awk -F= '{print $2}'`
KEY_ALIAS_PASSWORD=`cat ${LOCAL_PATH} |grep KEY_ALIAS_PASSWORD= | awk -F= '{print $2}'`

java -jar ${BASE_JAR} -importsign ${KEY_STORE} ${KEY_STORE_PASSWORD} ${KEY_ALIAS} ${KEY_ALIAS_PASSWORD}

java -jar ${BASE_JAR} -showsign

BuildApkLine=$2
Build_JiaGu_Dir=$3
echo "BuildApkLine:${BuildApkLine}, Build_JiaGu_Dir=${Build_JiaGu_Dir}"

java -jar ${BASE_JAR} -jiagu $BuildApkLine $Build_JiaGu_Dir -autosign   

echo "------ jiagu finished! ------"

生成二维码,在构建历史展示更多信息

  1. 安装description setter plugin插件
  2. 在Ubuntu上安装qrencode, 用于生成二维码图片
sudo apt-get install qrencode
  1. 修改构建任务,在项目编译完加固完成后执行下面命令
BuildApkLine=`find ./jiagu -name *_jiagu_sign.apk`

# 备份到文件服务器
PkgBakDir="/home/cc/pkg_bak/${JOB_NAME}"
if [ ! -d "$PkgBakDir" ]; then
mkdir $PkgBakDir
fi

BuildDir="$PkgBakDir/${BUILD_NUMBER}"
if [ ! -d "$BuildDir" ]; then
mkdir $BuildDir
fi

ApkName=${BuildApkLine##*/}

LastestApkName="dev_lastest.apk"

cp $BuildApkLine $BuildDir

if [ -f "$PkgBakDir/$LastestApkName" ]; then
rm $PkgBakDir/$LastestApkName
fi

ln -s "$BuildDir/$ApkName" "$PkgBakDir/$LastestApkName"

QrcodeValue="http://192.168.80.140:81/${JOB_NAME}/${BUILD_NUMBER}/$ApkName"
echo "QrcodeValue is $QrcodeValue" 

LastQrcodeValue="http://192.168.80.140:81/${JOB_NAME}/$LastestApkName"
echo "LastQrcodeValue is $LastQrcodeValue" 

# 将debug apk的下载地址 生成二维码,以供下载
qrencode -o qrcode.png $QrcodeValue

# 将debug apk的下载地址 生成二维码,以供下载
qrencode -o last_qrcode.png $LastQrcodeValue

# 输出debug apk的下载地址,机械号,版本名称
echo "BuildUrl: $QrcodeValue,$VersionCode,$VersionName,$dev_branch,$Tasks"
  1. 构建后操作,添加Set build description


    构建后操作.png

这里解释一下这两个参数:

  • Regular expression:BuildUrl: (.),(.),(.),(.)
    通过正则匹配获取到上面BuildUrl的4个参数,分别为apk地址、机械号、版本名称、分支名称
  • Description,描述,这里以html格式输出其中 \1,\2..分别对应上面匹配的4个参数
  1. 完成后的结果如下:


    效果图.png

集成fir自动上传

打包完成后实现自动上传到fir,可参考 fir官方文档,这里我们通过编写Python脚本实现自动上传功能,脚本代码如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import requests
import json
import sys

# 需要的参数
REQUEST_PARAM = {
    'api_token': '这里填写自己的token信息',
    'type': 'android',
    'applicationId': 'com.xxx.xxx',
    'appName': '应用名称',
    'versionName': '1.0.1.0',
    'versionCode': '10',
    'changelog_path': 'changelog文件地址',
    'apk_path': 'apk地址'
}


# 初始化传入的参数
def init_param():
    print('获取到传递过来的参数:', str(sys.argv))
    REQUEST_PARAM['type'] = sys.argv[1]
    REQUEST_PARAM['applicationId'] = sys.argv[2]
    REQUEST_PARAM['appName'] = sys.argv[3]
    REQUEST_PARAM['versionName'] = sys.argv[4]
    REQUEST_PARAM['versionCode'] = sys.argv[5]
    REQUEST_PARAM['changelog_path'] = sys.argv[6]
    REQUEST_PARAM['apk_path'] = sys.argv[7]


# 获取上传凭证
def get_cert():
    print('发起获取上传凭证请求')
    param = {'type': REQUEST_PARAM['type'],
             'bundle_id': REQUEST_PARAM['applicationId'],
             'api_token': REQUEST_PARAM['api_token']}
    print('获取上传凭证请求参数:', param)
    req = requests.post(url='http://api.fir.im/apps', data=param)
    cert_response = req.content
    print('获取上传凭证响应:', str(cert_response))
    return cert_response


# 上传到fir
def upload_fir(binary, apk_path):
    binary_key = binary['key']
    binary_token = binary['token']
    binary_upload_url = binary['upload_url']

    print('开始上传Apk')
    changelog_str = open(REQUEST_PARAM['changelog_path']).read()
    file = {'file': open(apk_path, 'rb')}
    param = {
        "key": binary_key,
        "token": binary_token,
        "x:name": REQUEST_PARAM['appName'],
        'x:version': REQUEST_PARAM['versionName'],
        'x:build': REQUEST_PARAM['versionCode'],
        "x:changelog": changelog_str
    }
    req = requests.post(binary_upload_url, files=file, data=param)
    print('上传结果:', req.content)


if __name__ == '__main__':
    init_param()
    response = get_cert()
    # 得到获取上传凭证回调信息
    cert_json = json.loads(response)
    cert_binary = cert_json['cert']['binary']
    # 上传fir
    upload_fir(cert_binary, REQUEST_PARAM['apk_path'])

脚本代码注释也比较详细,不再展开说明,最后通过在上面加固完成后的shell脚本后面追加以下内容来实现自动上传

# 编写日志内容
ChangeLog=changelog.txt
echo "Uploaded by fir cli" >> $ChangeLog
echo "构建编号:${BUILD_NUMBER}" >> $ChangeLog
echo "修改记录:"  >> $ChangeLog
echo "${SCM_CHANGELOG}"  >> $ChangeLog

cat $ChangeLog

python /home/cc/backup/fir/uploadFir.py android $ApplicationId $AppName $VersionCode $VersionName $ChangeLog $BuildApkLine

常见问题

Jenkins启动可能出现的问题

Job for jenkins.service failed because the control process exited with error code. See “systemctl status jenkins.service” and “journalctl -xe” for details.

根据提示输入sudo systemctl status jenkins.service

● jenkins.service - LSB: Start Jenkins at boot time
   Loaded: loaded (/etc/init.d/jenkins; generated)
   Active: failed (Result: exit-code) since Thu 2018-10-18 11:19:37 CST; 21s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 3896 ExecStart=/etc/init.d/jenkins start (code=exited, status=1/FAILURE)

10月 18 11:19:37 cc-virtual-machine systemd[1]: Starting LSB: Start Jenkins at boot time...
10月 18 11:19:37 cc-virtual-machine jenkins[3896]: ERROR: No Java executable found in current PATH: /bin:/usr/bin:
10月 18 11:19:37 cc-virtual-machine jenkins[3896]: If you actually have java installed on the system make sure the
10月 18 11:19:37 cc-virtual-machine systemd[1]: jenkins.service: Control process exited, code=exited status=1
10月 18 11:19:37 cc-virtual-machine systemd[1]: jenkins.service: Failed with result 'exit-code'.
10月 18 11:19:37 cc-virtual-machine systemd[1]: Failed to start LSB: Start Jenkins at boot time.

从错误日志可以看出找不到java路径,解决方法:创建一条软链接

sudo ln -s /opt/jdk1.8.0_191/bin/java /usr/bin/java

Jenkins权限问题

Jenkins在执行shell脚本的时候可能出现权限问题,我们可以把jenkins账户加入到root组

  1. 将jenkins账户加入到root组
sudo gpasswd -a root jenkins
  1. 修改 /etc/default/jenkins 内容
# user and group to be invoked as (default to jenkins)
JENKINS_USER=root
JENKINS_GROUP=root
  1. 重启jenkins
sudo service jenkins restart
  1. 查看是否已经加入到root组
cat /etc/group |grep jenkins
jenkins:x:127:root

文件权限问题

错误信息

/home/cc/backup/360jiagu/jiagu/jiagu_360.sh ./local.properties app/build/bakApk/resguard/ry_taxi_passenger20_1.0.2.0.apk ./jiagu
/tmp/jenkins9129980792461988922.sh: 20: /tmp/jenkins9129980792461988922.sh: /home/cc/backup/360jiagu/jiagu/jiagu_360.sh: Permission denied

修改该文件权限即可

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

推荐阅读更多精彩内容