基于jenkins进行定制化开发
Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudson(Hudson是商用的),主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。Jenkins用Java语言编写,可在Tomcat等流行的Servlet容器中运行,也可独立运行。通常与版本管理工具(SCM)、构建工具结合使用。常用的版本控制工具有SVN、GIT,构建工具有Maven、Ant、Gradle。
目录
- 环境配置
- 创建构建任务
- 生成APK
- 生成二维码
- 集成360加固
- 集成蒲公英、Fir平台插件
- 生成App Bundle
- Jenkins动态化参数介绍
- 一键生成加固多渠道包脚本
- 校验APK签名脚本
- 插件
1. 环境配置
进入jenkins主界面,系统管理->全局工具配置 进行配置,包括 JDK,Git,Gradle,Maven等,如下,关于jdk的配置的设置。
(图1)
如上图,给定一个别名,通过下拉框选择相应的Jdk版本,也可以通过FTP工具上传已经下载到本地的Jdk包。
如下,git配置需要指定一个本地已经下载好的路径。这种需要通过Ftp或者脚本提前下载指定版本的git工具。
(图2)
Gradle,Maven配置与jdk和git的配置雷同,不做介绍。
2. 如何创建一个构建任务
生成apk需要新建一个构建任务,这里构建一个自由风格的软件项目,输入任务名称后就会自动创建一个构建项。
(图 3)
构建项包括 General,gitBucket,JobNotifications,源码管理,构建触发器,构建环境,构建,构建后操作。
(图4)
General:可以设置一些项目介绍
gitBucket:未用到
JobNotifications:使用 UDP、TCP 或 HTTP 协议向定义的端点发送有关作业状态的通知,设置同时并发构建数量
源码管理:配置关联不同的源码仓库,git,svn,scms等
构建触发器:可以hook一些事件进行自动构建,比如定时构建,提交构建,轮询scm构建等
构建环境:允许在构建之前进行一些操作,比如更新lfs,清除上一次构建缓存等
构建:指定构建脚本
构建后操作:主要配置构建后可以触发的操作,如发布单元测试报告,发送邮件通知,发布工件到蒲公英,fir等
3. 生成apk
基于步骤1,步骤2,只需要进行简单的配置即可打包apk,如图5
(图5)
配置tasks clean debugDebug
4. 生成二维码
为了方便apk的下载安装,将apk包的路径生成可直接下载的二维码图片。主要使用一个二维码生成的jar包。
主要实现步骤:
通过 jq工具,解析gradle生成apk时的output-metadata.json,获取apk名称,进行输出,找到输出的apk之后根据条件执行不同的逻辑,比如加固。使用cp 命令将apk副本拷贝到指定目录,然后通过QRcode.jar对目录中的apk路径生成二维码。在构建后操作 build description 插件指定二维码路径,就可以在指定位置显示二维码。(可以使用html调整二维码大小)
output-metadata.json{"version":3,"artifactType":{"type":"APK","kind":"Directory"},"applicationId":"com.codeview.takumi","variantName":"debug","elements":[{"type":"SINGLE","filters":[],"attributes":[],"versionCode":1,"versionName":"1.0.0","outputFile":"app-debug.apk"}],"elementType":"File"}使用方法需要用到 java -jar 命令
java-jar/data/service/tomcat/QRcode.jar url=http://apk.android.reworldgame.com/apk/$JOB_NAME.apk image=$JOB_NAME.jpg save=/data/www/image # 使用二维码生成jar 生成二维码格式: java -jar 二维码生成jar路径 url=apk路径 image=xx.jpg save=二维码地址
tips: 生成二维码的jar,在java 8平台编译,如果在java11 上不能运行。需要进行调整
5. 集成360加固
根据安全方面的考虑,对在国内应用市场上线的apk,上架app市场前,做加固处理。选择360加固,由于 360加固 助手提供命令行方式加固。
#加固apk脚本 [参数1:加固apk 参数2:加固apk输出路径 参数3: 海外国内来区分使用的签名文件]
if[$jiagu= true];then dos2unix/data/360/360jg.sh#忽略空格差异,造成无法执行脚本bash-ex/data/360/360jg.sh ${WORKSPACE}/app/build/outputs/apk/${VARIABLE}/*.apk ${WORKSPACE}/app/build/outputs/apk/ china 完整shell脚本#!/bin/bashBASE=/data/360/jiagu/jiagu.jar BASE2=/data/360/jiagu/#360加固账号NAME=360账户 PASSWORD=360密码 APK=$1DEST=$2flavor=$3#chinaFlag="/apk/china/"#根据输出路径判断是国内分支还是海外分支#if[[$APK =~$chinaFlag]]#then#flavor="china"#else#flavor="overseas"#fi#签名文件根据输入flavor来区分echo"flavor = "$flavorif["$flavor"="china"];then KEY_PATH=#密钥路径KEY_PASSWORD=#密钥密码ALIAS=key0#别名ALIAS_PASSWORD=#别名密码elif["$flavor"="SouthEastAsia"];then KEY_PATH=#密钥路径KEY_PASSWORD=#密钥密码ALIAS=#别名ALIAS_PASSWORD=密码#别名密码elseKEY_PATH=/data/360/sign/reworldoversea.jks#密钥路径KEY_PASSWORD=#密钥密码ALIAS=#别名ALIAS_PASSWORD=#别名密码fiecho"------ 打包签名详情! ------"echo"使用的签名文件路径 ="$KEY_PATHecho"Apk包路径 ="$APKecho"加固包输出路径 ="$DESTiecho"------ running! ------"cd$BASE2#java -jar ${BASE} -versionjava-jar ${BASE}-login ${NAME}${PASSWORD}java-jar ${BASE}-importsign ${KEY_PATH}${KEY_PASSWORD}${ALIAS}${ALIAS_PASSWORD}java-jar ${BASE}-showsign#java -jar ${BASE} -importmulpkg ${BASE2}/空渠道.txt #根据自身情况使用#java -jar ${BASE} -importmulpkg ${BASE2}/空渠道.txt #根据自身情况使用java-jar ${BASE}-showmulpkg java-jar ${BASE}-showconfig java-jar ${BASE}-jiagu ${APK}${DEST}-autosign#java -jar ${BASE} -pkgparam ${BASE2}/哈哈.txtecho"--------finish------------"tips:
${WORKSPACE} 占位符方式,可以获取jenkins默认本地变量和通过参数化构建设置的自定义变量
6. 集成蒲公英,fir平台插件
发布到蒲公英和fir内测平台,通过以上两个平台提供的快速发布插件,可快速集成,这里提供一种回显蒲公英平台生成二维码到jenkins的方案
发布到蒲公英平台之后,返回的json串格式,如下:
{"code":0,"message":"","data":{"appKey":"c2c6568526071a91d8ce0dfb596b894f","userKey":"2b50d762a0957feaf481346938eba78e","appType":"2","appIsLastest":"1","appFileSize":"259772621","appName":"Reworld","appVersion":"1.0.0","appVersionNo":"1","appBuildVersion":"1","appIdentifier":"com.codereview.reworldsea","appIcon":"5ff42e3dc70e4deffb8c0f48a3703dc2","appDescription":"","appUpdateDescription":"","appScreenshots":"","appShortcutUrl":"DrpS","appCreated":"2021-11-25 14:29:00","appUpdated":"2021-11-25 14:29:00","appQRCodeURL":"https:\/\/www.pgyer.com\/app\/qrcodeHistory\/8273db84803bcb78f617c58c7d60f623ae20a25839d7efe9b90ea4788bba07f7"}}shell脚本
在将apk发布到蒲公英之后,对返回的结果json串中appQRCodeURL的值进行解析。
# 脚本文件 pgyUpdate.sh#!/bin/bash#MAIN_MODULE AndroidStudio project directory under the main moduleMAIN_MODULE="."#The test address separately#MAIN_MODULE="./app"# pgy API accountPGYER_USER_KEY="蒲公英userkey"PGYER_API_KEY="蒲公英api key"#APK path#APK_PATH="${MAIN_MODULE}/build/outputs/apk"#Receive the external transfer apk pathAPK_PATH=$1echo"=============================================="#echo "current path: `pwd`"echo"APK_PATH=${APK_PATH}"APK_LIST=`ls-t ${APK_PATH}`echo"${APK_LIST}"#ind the latest apk packageforAPK_FILE in ${APK_LIST};doAPK_NAME=${APK_FILE}echo"apk file name=$APK_NAMEFile=$APK_FILE"done#-------------------------------------------------if[-n"$APK_NAME"];then# Determine whether is emptyecho"upload$APK_FILEpgy"#upload pgy updateDescription(version descript)RESULT=$(curl-F"file=@${APK_PATH}/${APK_NAME}"-F"uKey=${PGYER_USER_KEY}"-F"_api_key=${PGYER_API_KEY}"https://qiniu-storage.pgyer.com/apiv1/app/upload)echo$RESULT> pgy.json#-------------------send mail-------------------------# echo "send mail to" test@qq.com# echo "${RESULT}" | mail -s "${APK_NAME} already unload pgy" test@qq.com# #http://www.pgyer.com/apiv1/app/uploadfi构建块中添加执行发布到分发平台的shell脚本即可
#发布到蒲公英
if[$pgy= true];then cd/data/pgyupdate./pgyUpdate.sh ${WORKSPACE}/app/build/outputs/apk/${VARIABLE}/fifir类似,不赘述
7. 生成App Bundle
AAB格式为上架google play需要,与生成apk区别点在于构建方式不同。构建之后的处理与apk类似。
构建块中添加执行发布到分发平台的shell脚本即可
if["bundle"="$packageType"];then cd/data/www/aab/# typeset -l lowerBuildChannel=${Build_channel}# typeset -l lowerBuildType=${Build_type}lowerBuildChannel=${Build_channel,}lowerBuildType=${Build_type,,}aabDir=${WORKSPACE}/app/build/outputs/bundle/${lowerBuildChannel}${Build_type}aabName=${aabDir}/app-${lowerBuildChannel}-${lowerBuildType,}.aabecho$aabNamecp${aabDir}/*.aab/data/www/apk/$JOB_NAME.aab java-jar/data/service/tomcat/QRcode.jar url=http://apk.android.reworldgame.com/apk/$JOB_NAME.aab image=$JOB_NAME.jpg save=/data/www/imageexitfi8. jenkins动态化参数介绍
参数构建是实现jenkins动态构建的基础。
8.1 字符参数
(图6)
如上图,在需要用到的地方使用${App_VERSION_CODE},既可以取出来2406值来使用
8.2选项参数
(图7)
8.3布尔参数
(图8)
8.4动态选择参数
(图9)
8.5 最终构建任务样式
- 一键生成加固多渠道包脚本
脚本逻辑介绍:
对等待加固的apk,使用360加固包提供的脚本jar文件进行加固,然后针对生成的加固包执行wallet.jar 多渠道脚本,基于加固包生成多个渠道的apk文件,提供给对应渠道进行上架。
@echooffecho========== push apk to here ============ ::需要加固的apk路径set/p APK= >nulsetAPK_VERSION=1setAPK_FLAVOR=1setremain=%APK%setindex=0 :loopfor/f"tokens=1* delims=_"%%a in("%remain%")do(if%index%==1(setAPK_FLAVOR=%%a)if%index%==2(setAPK_VERSION=%%a)set/a index=index+1 rem 将截取剩下的部分赋给变量remain,其实这里可以使用延迟变量开关setremain=%%b)::如果还有剩余,则继续分割ifdefined remain goto :loopsetAPK_FLAVOR=%APK_FLAVOR:~0,7%echo%APK%echoAPK_VERSION=%APK_VERSION% APK_FLAVOR=%APK_FLAVOR% ::加固配置setSRT="C:\360\jiagu"setNAME=360账户setPASSWORD=360账户密码 cd%SRT%echocurrent path ==============%cd%if%APK_FLAVOR%==oversea(echo=========== oversea =============setBASE=C:\360\haiwai\jiagu\jiagu.jar ::密钥路径setKEY_PATH=./jsk/reworldoversea.jks ::密钥setKEY_PASSWORD=密码 ::别名setALIAS=别名 ::别名密码setALIAS_PASSWORD=别名密码 ::输出加固包路径setDEST=./海外/%APK_VERSION%echo本次使用印度签名)elseif%APK_FLAVOR%==southEa(echo=========== SouthEastAsia =============setBASE=C:\360\southEastAsia\jiagu\jiagu.jar ::密钥路径setKEY_PATH=./jsk/xxx.jks ::密钥密码setKEY_PASSWORD=密码 ::别名setALIAS=别名 ::别名密码setALIAS_PASSWORD=别名密码 ::输出加固包路径setDEST=./东南亚/%APK_VERSION%echo本次使用东南亚签名)else(echo=========== china =============setBASE=./jiagu.jar ::密钥路径setKEY_PATH=./jsk/test.jks ::密钥密码setKEY_PASSWORD=密码 ::别名setALIAS=别名 ::别名密码setALIAS_PASSWORD=别名密码 ::输出加固包路径setDEST=./国内/%APK_VERSION%echo本次使用china签名)echo%BASE% jiagu apk output path ======:%DEST% md"%DEST%"echo"------ jaigu running! ------"java-jar%BASE%-version java-jar%BASE%-login%NAME%%PASSWORD% java-jar%BASE%-importsign%KEY_PATH%%KEY_PASSWORD%%ALIAS%%ALIAS_PASSWORD% java-jar%BASE%-showsign java-jar%BASE%-showmulpkg java-jar%BASE%-showconfig java-jar%BASE%-jiagu%APK%%DEST%-autosignecho"------ jaigu finished! ------"echo"------ start rename ------"cd%DEST%echocurrent path ==============%cd%for%%i in(./*.apk)do(echo%%i|findstr"jiagu">nul &&(echofind jiagu apkecho%%i|findstr"sign">nul &&(echofind signed apkcopy"%%i""reworld.apk"goto loop2))):loop2echo"------ end rename ------"echo"------ start walle ------"cd%SRT%echocurrent path ==============%cd%setCHANNEL_PATH=%DEST%/%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2% java-jar./walle-cli-all.jar batch-f./walle临时渠道.txt"%~f1"%DEST%/reworld.apk%CHANNEL_PATH% ::统计目录下文件个数 cd%CHANNEL_PATH%echocurrent path ==============%cd%setcount=0for%%i in(./*.apk)doset/a count+=1echo------channel file count:%count%------echo"------ end walle ------"Pause10. 校验apk签名脚本
脚本介绍:
针对加固之后apk签名与正确签名进行比对,避免海外,国内市场apk签名错用。
@echooffecho========== push apk to here ============ ::需要加固的apk路径set/p APK= >nulecho========== apk path is%APK% ============echo========== push flavor to here ============echo1:chinaecho2:overseaecho3:southAsiaset/p APK_FLAVOR_TYPE= >nulif%APK_FLAVOR_TYPE%==1(setAPK_FLAVOR=chinasetAPK_DEFINE_SHA1=bd67d0933ec6a40fb)elseif%APK_FLAVOR_TYPE%==2(setAPK_FLAVOR=overseasetAPK_DEFINE_SHA1=5e33c207b8621a5a8bc458eb)elseif%APK_FLAVOR_TYPE%==3(setAPK_FLAVOR=southAsiasetAPK_DEFINE_SHA1=478550704adff0a1a89)else(setAPK_FLAVOR=unKnowsetAPK_DEFINE_SHA1=unSet)echo============ choice flavor is%APK_FLAVOR% ============setSIGNER_INFO_PATH=temp_singer.txtsetLINE_SHA1_FLAG=SHA-1 java-jar.\apksigner.jar verify--print-certs%APK% >%SIGNER_INFO_PATH% call :read_apk_signer_sha1%SIGNER_INFO_PATH% :read_apk_signer_sha1for/f"tokens=1,2 delims=:"%%a IN(%1)do(echo%%a%%becho%%a|findstr%LINE_SHA1_FLAG% >nul &&setAPK_SHA1=%%b):del_leftif"%APK_SHA1:~0,1%"==" "setAPK_SHA1=%APK_SHA1:~1%&&goto del_leftecho============%APK_DEFINE_SHA1% ============echo============%APK_SHA1% ============if%APK_SHA1% equ%APK_DEFINE_SHA1%(echo============ SHA1 is right ============)else(echo============ SHA1 is wrong ============)pause11. 插件
1.jenkins 下载地址
2. 动态选择插件