旨在规范打包流程,简化打包步骤,降低打包出错风险;
实现的功能
- 选择分支构建
- 安装包自动加固
- 加固包自动分发
- 下载链接、二维码展示
- 成品归档
- 应用仓库选择
- 自动修改版本号
- 多渠道打包
未来要做的
功能逻辑全部移植到Gradle中,在Gradle中完成有以下好处:
- Jenkins就只充当工具,不包含逻辑,降低Jenkins维护成本;
- 维护升级只需要在Gradle中就可以;
- 使用命令一样能用这些功能;
- Gradle的Task管理这些功能,更加清晰;
看下结果

image.png

image.png
目前的技术方案步骤
1. 搭建Jenkins环境,这个自己查一下就可以,很多;
2. 安装所需要的插件
- Git Parameter 用于拉取Git分支,打包时选择分支,过滤分支;
3. 创建Jenkins项目,配置权限,自己搜索下
4. 安装SDK
- 安装SDK Manager
- 然后配置利用SDK Manager中的android来进行ADT安装 可参考:https://www.cnblogs.com/milton/p/4395304.html
5. 参数化构建
参数化构建中的参数名称,也就是Name字段,在构建过程中都会变成全局变量,可以直接使用的;
-
配置Git 分支选择
image.png -
设置构建环境
image.png - 设置打包文件名称格式${},可以直接引用变量;
image.png
-
设置打包描述
image.png -
设置是否加固
image.png -
设置应用仓库
image.png -
设置源码仓库
image.png -
设置构建任务名称和启用参数化构建
image.png - 添加构建命令 Excute Shell
Gradle的检查更新
source /etc/profile
bash /data/xxxx/judgemd.sh
judgemd.sh 文件内容
Md5file=/data/xxxx/md5tag.txt
Conffile=/data/xxx/gradle/wrapper/gradle-wrapper.properties
test -f $Conffile || exit
test -f $Md5file || exit
Src=`cat $Md5file`
Res=`grep distributionUrl $Conffile | awk -F'/' '{print$NF}' | awk -F';' '{print$1}' | md5sum| awk '{print$1}'`
if [ "$Src" != "$Res" ] ; then
rm -rf /usr/local/gradle/*
rm -rf /root/.gradle/*
rm -rf /usr/local/gradle-*
source $Conffile
\wget $distributionUrl -P /usr/local/
File=`echo $distributionUrl | awk -F'/' '{print$NF}' | awk -F';' '{print$1}' `
\unzip /usr/local/$File -d /usr/local/ || exit
ZipName=`unzip -v /usr/local/$File | head -20 | tail -1 | awk '{print$NF}' | awk -F'/' '{print$1}'`
\mv /usr/local/$ZipName/* /usr/local/gradle/
echo $Res > $Md5file ;
fi
执行构建任务,-P可以向Gradle的Project中注入参数,在Gradle中project.getProperty(name)
cd ${WORKSPACE}
/usr/local/gradle/bin/gradle clean -no-daemon assemble${JENKINS_BUILD_TYPE} -PJENKINS_APK_FILE_NAME=${JENKINS_APK_FILE_NAME}
执行加固任务,就是执行Gradle中的加固命令,Gradle的配置放在了后面
apkPath=${WORKSPACE}/alpha/build/outputs/apk/${JENKINS_BUILD_TYPE}/${JENKINS_APK_FILE_NAME}
if ${JIAGU_APK}; then
/usr/local/gradle/bin/gradle jiaguLinux -PAPK_PATH=${apkPath}
fi
上传应用仓库,${apkName%.apk*}_jiagu.apk
表示替换.apk字符串为_jiagu.apk
apkName=${JENKINS_APK_FILE_NAME}
if ${JIAGU_APK}; then
apkName=${apkName%.apk*}_jiagu.apk
fi
pgy_api_key="xxxx"
if ${PGY_ACCOUNT}=="PGY_INNER"; then
pgy_api_key="xxxx"
fi
apkPath=${WORKSPACE}/alpha/build/outputs/apk/${JENKINS_BUILD_TYPE}/${apkName}
curl -F "file=@${apkPath}" -F "buildUpdateDescription=${JENKINS_BUILD_UPDATE_DESCRIPTION}" -F "_api_key=${pgy_api_key}" https://www.pgyer.com/apiv2/app/upload
-
归档构建产生的所有apk
image.png -
设置构建描述,显示二维码和下载链接
image.png
// 正则匹配console中的日志,取出buildKey和二维码地址的key,每个(.*)表示一个变量,\1或\2来引用第几个变量
.*"buildKey":"(.*)","buildType":"2",.*qrcodeHistory\\/(.*)"}}
${JENKINS_BUILD_UPDATE_DESCRIPTION}<br><img src="https://www.pgyer.com/app/qrcodeHistory/\2" width="118" height="118"/> <a href="https://www.pgyer.com/\1">下载安装包</a>
360加固配置,官网有文档
ext.jiaguDir = ""
//删除缓存
task cleanJiagu(type: Delete) {
delete "jiagu/linux/.cache", "jiagu/linux/output", "jiagu/linux/jiagu.db"
delete "jiagu/mac/.cache", "jiagu/mac/output", "jiagu/mac/jiagu.db"
delete "jiagu/windows/.cache", "jiagu/windows/output", "jiagu/windows/jiagu.db"
}
//mac加固
task jiaguMac(dependsOn: cleanJiagu) {
group "jiaguapk"
doLast {
if (project.hasProperty("APK_PATH") && APK_PATH != null && APK_PATH != "") {
rootProject.ext.jiaguDir = "jiagu/mac"
jiagu()
}
}
}
//Linux加固
task jiaguLinux(dependsOn: cleanJiagu) {
group "jiaguapk"
doLast {
if (project.hasProperty("APK_PATH") && APK_PATH != null && APK_PATH != "") {
rootProject.ext.jiaguDir = "jiagu/linux"
jiagu()
}
}
}
//windows加固
task jiaguWindows(dependsOn: cleanJiagu) {
group "jiaguapk"
doLast {
if (project.hasProperty("APK_PATH") && APK_PATH != null && APK_PATH != "") {
rootProject.ext.jiaguDir = "jiagu/windows"
jiagu()
}
}
}
def jiagu() {
println "360加固 begin"
//读取签名文件
Properties properties = new Properties()
InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream()
properties.load(inputStream)
def keyAlias = properties.getProperty('alphaKeyAlias')
def keyPassword = properties.getProperty('alphaKeyPassword')
def storeFile = file(properties.getProperty('alphaStoreFile'))
def storePassword = properties.getProperty('alphaStorePassword')
def sourceApk = file(APK_PATH)
println "appFilePath=" + sourceApk
if (!sourceApk.exists()) {
println "apk not exist"
return
}
def cmdBase = 'java -jar ' + project.rootProject.file(rootProject.ext.jiaguDir + "/jiagu.jar").absolutePath
def cmdLogin = cmdBase + " -login 账号 密码"
def cmdImportSign = cmdBase + ' -importsign ' + project.rootProject.file("keystore.jks") + ' ' + storePassword + ' ' + keyAlias + ' ' + keyPassword
def cmdShowSign = cmdBase + ' -showsign'
def cmdConfig = cmdBase + ' -config -x86'
def cmdShowConfig = cmdBase + ' -showconfig'
def cmdVersion = cmdBase + ' -version'
def cmdJiaGu = cmdBase + ' -jiagu ' + sourceApk + ' ' + sourceApk.getParent() + ' -autosign'//多渠道 + ' -automulpkg'
execute360JiaGuCmd(cmdLogin)
execute360JiaGuCmd(cmdImportSign)
execute360JiaGuCmd(cmdShowSign)
execute360JiaGuCmd(cmdConfig)
execute360JiaGuCmd(cmdShowConfig)
execute360JiaGuCmd(cmdVersion)
execute360JiaGuCmd(cmdJiaGu)
//替换文件
def listFiles = sourceApk.parentFile.listFiles()
if (listFiles.length > 1) {
for (int i = 0; i < listFiles.length; i++) {
if (listFiles[i].absolutePath.contains("_jiagu")) {
println '重命名文件---->' + listFiles[i].absolutePath
def targetApk = sourceApk.absolutePath.replaceAll("\\.apk", "_jiagu.apk")
println '目标文件---->' + targetApk
listFiles[i].renameTo(targetApk)
// println '删除文件---->' + listFiles[i].absolutePath
// listFiles[i].delete()
break
}
}
}
println "360加固 end"
}
def execute360JiaGuCmd(cmd) {
def p = cmd.execute(null, project.rootProject.file(rootProject.ext.jiaguDir + "/java/bin"))
println "执行命令:" + cmd
println p.text
p.waitFor() // 用以等待外部进程调用结束
println "执行结果:" + p.exitValue()
}