[TOC]html
常常在开发的时候,测试/产品/运营等人员会来要求安装一下软件,这时候不得不停下手中的事情来打包安装,但终归不是长久之计:java
做为一个 '懒人' ,这种重复性的工做肿么能每次都本身动手呢,另外最好再有个地方能提供稳定分支代码的安装包供人下载安装,免得有人说不会安装apk ==!... 话说前公司就提供有自动打包功能,之前不以为有什么,等到没有的时候才发觉它的好...无奈,只能本身动手搭一套;python
WORKSPACE
指代的位置;
基于: 系统: mac 10.12.4(Sierra) Jenkins: 2.46.1 Git: 2.10.0 Python: 3.xandroid
jenkins.war
单文件;// 方式1: 假如系统中安装有Tomcat,就把它当作普通的war包放置到 webapps/ 下运行便可;
// 方式2: (假设 jenkins.war 放置在 ~/Downloads/ 目录下)
cd ~/Downloads/
nohup java -jar jenkins.war & // 后台运行jenkins.war程序,默认使用8080端口
// 指定端口
--httpPort=8080 // 用来设置jenkins运行时的web端口,避免冲突
复制代码
localhost:8080
(端口号请按需修改),第一次会要求输入帐号密码, jenkins
提供了一个初始密码,能够根据页面提示在文件 initialAdminPassword
中获取:sudo cat /Users/***/initialAdminPassword // 提示路径可能不一样,根据页面提示修改
复制代码
Install suggested plugins
:
后续也可在 jenkins首页 -
Manage Jenkins
-Manage Plugins
中安装插件,主要是Gradle Plugin
Android Signing Plugin
Git Parameter Plug-In
GitHub Authentication plugin
Gitlab Authentication plugin
Git plugin
等git
New Item
,添加完成后会在右侧显示已添加的 job 列表:
开始打包发布Android应用前须要进行以下环境的设置:Android/Git/Gradle/Python等github
==! 不知道咋回事,没有识别到我配置在
~/.bash_profile
中的ANDROID_HOME环境变量,最后折腾了很久才发现要在jenkins中手动指定一个web
在 Manage Jenkins
- Configure System
- Global properties
勾选 Environment variables
,并添加一个:shell
Name : ANDROID_HOME
Value : /Users/***/Applications/AndroidSDK
复制代码
在 Manage Jenkins
- global tool configuration
中按需选择工具 , name
随意指定,其余的参考下图:json
// 配置JDK主目录
name: MAC_JDK
path: /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home
// 配置Git运行路径
name: Default
path: /usr/bin/git
// 配置Gradle主目录
name: gradle3.5
path: /Users/lynxz/.sdkman/candidates/gradle/current/bin
// 注意: 在 `gradle /current/bin/bin`中需存在 `gradle` 可执行文件;
// 备注: 我以前是使用 `sdkman` 来安装的 `gradle` ,因此路径比较奇怪
curl -s https://get.sdkman.io | bash
sdk install gradle 3.5
复制代码
new item
, 输入名称, 选择 Freestyle project
,点击 ok
按钮便可;Configure
进行配置;General
中按需输入 project name
和 Description
; 另外,这个tab页面中比较经常使用的还有参数化设置( This project is parameterized
), 后续会讲到;Source Code Management
中指定版本管理类型/仓库地址/认证信息等;
Build
中选择 Invoke Gradle Script
,在 Gradle Version
下拉列表中选择自定义的本机Gradle版本;并在 Tasks
中输入打包命令:// 默认未作多渠道多版本配置时,打包release类型的命令:
clean assembleRelease --stacktrace --debug
复制代码
若是有须要将 general
标签也中定义的变量注入到项目中让 gradle
脚本使用,则请勾选 Pass job parameters as Gradle properties
,则gradle脚本中用到的同名自定义变量就会使用jenkins中指定的值; python3.x
有时候须要在构建的时候进行一些定制化操做,好比指定编译的代码分支,增长打包版本说明等,又或者项目中使用了私有仓库,而仓库的登陆帐号名(如mavenUser
)以及密码(mavenPassword
)存储于 gradle.properties
(不一样步到gitlab仓库中),这时就须要添加参数,并将该参数注入到Android项目中了,以便gradle脚本能获取到正确的值,具体操做以下:
Configure
- General
面板中勾选 This project is parameterized
;Add Parameter
下拉列表中就能够选择对应的类型变量
注意: 若参数须要注入到Android项目构建脚本中,则须要勾选 configure
- Build
- Pass job parameters as Gradle properties
; 3. 好比选择添加一个 String Parameter
Choice Parameter
,用于指定要打包的版本:
app/build.gradle
中定义过的,用于后续的打包命令:
android{
buildTypes {
release {
signingConfig signingConfigs.release
}
//不能以"test"开头
tstEnv {
debuggable true
signingConfig signingConfigs.release
}
debug {
versionNameSuffix "-dev"
debuggable true
signingConfig signingConfigs.release
}
}
}
复制代码
上面指定的 choice parameter
类型参数 buildTypes
即可用在 Build
命令中:
还没去研究过jenkins签名插件,通常直接在Android项目中配置好脚本便可:
*.jks
放置于 app/
目录下;app/build.gradle
中配置签名参数,这样jenkins打包出来的apk就是签名过的:android{
signingConfigs {
release {
keyAlias '***'
keyPassword '***'
storeFile file('*.jks')
storePassword '***'
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
debug {
signingConfig signingConfigs.release
}
}
}
复制代码
P.S. 不过总以为这样直接公开签名文件到仓库中不太好,在打包服务器上进行控制会更合适点,毕竟知晓的人更少,这个后续再研究,先占个位;
user build vars plugin
,可在插件列表中直接获取安装 或者到 这里 下载插件包;job
- configure
- Build Environment
- Set jenkins user build variables
,勾选此项后才生效;echo "$BUILD_USER"
:插件可用的变量名 | 变量描述 |
---|---|
BUILD_USER | Full name (first name + last name) |
BUILD_USER_FIRST_NAME | First name |
BUILD_USER_LAST_NAME | Last name |
BUILD_USER_ID | Jenkins user ID |
BUILD_USER_EMAIL | Email address |
默认的job构建历史命名( 如 #35 Apr 27, 2017 11:15 AM
)不容易理解记忆,咱们能够自定义,加入构建者姓名,版本等信息; 定制包括"build name" 和 "build description" 两部分的定制,效果以下
manage jenkins
- manage plugins
- Advanced
在 upload plugin
中选择刚才下载的插件,提交后重启jenkins便可;Configure
- Build Environment
,就会多出一个 Set Build Name
复选项,勾选后便可定制;
安装插件 description setter plugin
(能够在jenkins的 manage plugins
中找到);
重启jenkins后,进入 job 的 Configure
- post-build Actions
,选择 Add post-build action
- set build description
便可定制;
为了显示蒲公英的二维码图片,须要先在 manage jenkins
- Configure global security
,找到 Markup Formatter
,将默认的 plain text
改成 safe html
;
在 job - configure
- post-build actions
- set build description
中就能够输入html标签了,好比我设置了:
// 这里的${pgyerNotes}是我在general中添加的参数
<p>${pgyerNotes}</p><br/><br/><a href='https://www.pgyer.com/Cb6T'>Download Directly</a>
复制代码
Configure
- Post-Build Actions
Add post-build action
列表中选择 Archive the artifacts
输入要存档的文件路径,可以使用通配符,好比我输入的是 app/build/outputs/apk/Sb*.apk
,就会在job项目首页看到存档记录,能够直接下载;
${WORKSPACE}
等变量,貌似就是直接以当前工做空间为根目录的;请首先到 蒲公英 上注册帐号,并认证,若不认证则上传失败; 蒲公英上传文件接口 蒲公英的key值可在 帐户设置
- API信息
中查看到 因为我是mac系统,所以在 Job - Configure
- Build
- Add build step
列表中选择 Execute shell
,运行shell脚本 P.S. 如果对shell不熟悉,可参考 教程 另外,因为我在项目中根据版本号(vesionName)重命名了生成的apk,所以须要在shell脚本中提取版本号以便得到apk全称,进而上传蒲公英
# build -> Add build step -> Execute shell
pgyerApiKey="******"
pgyerUKey=="******"
echo "获取apk版本号..."
# ${WORKSPACE} 是jenkins提供的环境变量,表示当前项目跟目录路径
# 下面的命令是获取 app/build.gradle 的第17行内容,而后按照双引号进行切换,提取第2部份内容,即上面图示中的 1.1.4
versionName=`sed -n '17p' ${WORKSPACE}/app/build.gradle | cut -d \" -f 2`
echo "获取apk所在路径..."
# _360 是项目中定义了多渠道,但因为以前在 Build - Task 中设置的打包命令,直接指定了渠道号,所以这里也直接固定写好就能够;
apkAbsPath="${WORKSPACE}/app/build/outputs/apk/SonicMoving_${buildTypes}_[_360]_v${versionName}.apk"
echo "上传apk到蒲公英进行发布..."
response=$(curl -F "file=@${apkAbsPath}" -F "uKey=${pgyerUKey}" -F "_api_key=${pgyerApiKey}" https://qiniu-storage.pgyer.com/apiv1/app/upload)
echo "上传结束"
# 本来上传结束后想要使用 jq 工具 (`brew install jq`) 对蒲公英上传时返回的response进行json处理的,结果在电脑的shell中测试可行,但写到这里就一直不成功,无奈,只好放弃
# 提取蒲公英返回的json数据中的 appShortcutUrl 字段值,可拼接成下载地址
#responseCode=$(echo -E "${response}" | jq .code)
#if [ $((responseCode)) == 0 ]
#then
# echo "上传结束,处理返回相应..."
# appShortcutUrl=$(echo -E "${response}" | jq ".data.appShortcutUrl" | cut -d \" -f 2)
# apkOnlineUrl="https://www.pgyer.com/${appShortcutUrl}"
#else
# echo "上传失败,返回码为: ${responseCode} ,具体请看日志"
#fi
复制代码
最先以前我也是尝试直接使用python插件的,操做以下:
Python Plugin
;Configure
- Build
中就会多一个选项 Execute python script
;import os
# 获取jenkins变量 'BUILD_NUMBER'
print("build_number is ==> ",os.getenv("BUILD_NUMBER"))
复制代码
可是因为我是mac,系统中默认的python是2.7.x,而我又装了其余版本的python,虽然在jenkins的全局变量中指定了python版本,但实际执行的时候却用的不是它,大体的错误以下:
python script
中的生成了一份位于
/var/.../*.py
的文件,而后使用系统默认的
python
版原本执行,而我 mac 默认的python是python2.7.*,致使里面写的不少基于python3.x的代码出错:
使用python多版本问题的经常使用方法 virtualenv
,最后演变成经过shell来启用版本隔离,而后手动调用python命令加载脚本: 在 Build
- add build step
- execute shell
中写入以下脚本:
# 若是当前无指定的环境目录存在,则建立,并指定python版本
if [ ! -d ".env" ]; then
virtualenv -p /usr/local/bin/python3 .env
fi
# 启动virtualenv
source .env/bin/activate
echo "当前操做的用户是 : $BUILD_USER "
#requestsLibName="requests"
#isInstallRequest=$(pip freeze | grep $requestsLibName)
#if [[ $isInstallRequest =~ "*requests*" ]];then
# pip install requests
#fi
# 安装所须要的第三方库,若已安装,则不会从新安装
pip install requests
# 运行指定路径下的python脚本
python3 ~/Desktop/upload.py
复制代码
上面shell脚本中的 upload.py
内容以下(可考虑将其放在Android项目中,上传gitlab):
#!/usr/local/bin/python3.5
# -*- coding: utf-8 -*-
''' jenkins 打包线上代码生成apk后发布到蒲公英 本脚本路径: ~/Desktop/upload.py '''
import os
import io
import re
import requests
import json
WORKSPACE = os.getenv("WORKSPACE") # 获取jenkins环境变量
userName = os.getenv("BUILD_USER") # 获取用户名
buildTypes = os.getenv("buildTypes") # 获取用户选择的编译版本
pgyerNotes = os.getenv("pgyerNotes") # 获取用户填写的版本说明
# 重置默认编码为utf8
import sys
default_encoding = 'utf-8'
if sys.getdefaultencoding() != default_encoding:
reload(sys)
sys.setdefaultencoding(default_encoding)
# 确认下当前python版本
print("当前编译器版本: %s " % sys.version)
print("python编译器详细信息: ", sys.version_info)
# 获取版本号
# guild.gralde文件所在路径
buildGradleFilePath = "%s/app/build.gradle" % (WORKSPACE) # 指定文件所在的路径
print("build.gradle路径是: ", buildGradleFilePath)
# 读取build.gradle并获取versionName值
with open(buildGradleFilePath, 'r', encoding='utf-8') as buildGradleFile:
line = buildGradleFile.readlines()[16:17][0] # 读取第17行数据, 切片从0开始;
print("line 17 is .... ", line)
versionName = re.split(r'\"', line)[1]
print("版本号为: %s" % versionName)
# "获取apk所在路径..."
apkAbsPath = "%s/app/build/outputs/apk/SonicMoving_%s_[_360]_v%s.apk" % (WORKSPACE, buildTypes, versionName)
print("准备上传apk到蒲公英进行发布,apk所在路径为: %s" % apkAbsPath)
# 上传结束后发出请求通知服务端,进而由服务端发送钉钉消息
def notify_upload_result(msg):
headers = {'user-agent': 'jenkins_upload_pgyer'}
params = {'userName': userName, 'msg': msg} # 字段中值为None的字段不会被添加到url中
response = requests.get('http://btcserver.site:8080/WebHookServer_war', params=params, headers=headers)
#response = requests.get('http://localhost:8081', params=params, headers=headers)
print("通知webhook服务器结果: ", response.text)
# 蒲公英帐号信息
pgyerApiKey = "******"
pgyerUKey = "******"
# response=$(curl -F "file=@${apkAbsPath}" -F "uKey=${pgyerUKey}" -F "_api_key=${pgyerApiKey}" -F "updateDescription=${pgyerNotes}" https://qiniu-storage.pgyer.com/apiv1/app/upload | jq .)
# post请求中所需携带的信息
data = {
'_api_key': pgyerApiKey,
'uKey': pgyerUKey,
'updateDescription': pgyerNotes
}
files = {'file': open(apkAbsPath, 'rb')}
uploadUrl = 'https://qiniu-storage.pgyer.com/apiv1/app/upload'
response = requests.post(uploadUrl, data=data, files=files)
print(response.status_code, response.text)
if response.status_code == 200:
print("上传成功,通知webhook服务器...")
notify_upload_result(response.text)
else:
print("上传失败,状态码为: %s" % (response.status_code))
复制代码
参考 打通Gitlab与钉钉之间的通信 这里有两种方式通知服务器后台:
须要在仓库中添加公钥;
//获取公钥
ssh-keygen -t rsa -f ~/.ssh/id_rsa.pub
复制代码
测试时用的是 coding.net
, 所以在 coding.net
对应项目的 设置
- 部署公钥
- 新建部署公钥
将刚才输出的公钥粘贴进去便可;
token-macro-plugin 到插件管理页面中搜索 Token Macro Plugin
安装便可;