小文字 吃饭,睡觉,溜狗头

Android发版、备份自动化之路

img

前言

  • 自动化脚本在项目开发和管理中非常重要,不但可以简化工作也更加安全,不会像人工操作遗漏步骤
  • 在日常管理项目和版本迭代中,为了方便,根据公司项目的现状,笔者陆续建立和完善了相应的打包备份脚本,经过历次迭代,效果还不错;

通过脚本解决了什么问题?

  • 首先自然是打包,生成发行用的apk文件;
  • 签名验证,确认生成的包是符合发行的签名;
  • 资源压缩,如css,js文件;
  • 记录发版日志,比如当前打包的git摘要,时间,作者,版本信息;
  • 自动安装,根据有无设备连接,自动安装至设备;

逐一实现目标

过去打包,很多时候用的ant,自gradle在android领域内兴起的这两年,脚本也慢慢都转向了支持gradle;

    ./gradlew clean assemble"$flavor"Release

这里根据输入的flavor进行release;

得到签名文件后,可以对其做签名验证

    signature=`unzip -p build/outputs/apk/android-$flavor-armeabi-release.apk META-INF/CERT.RSA | keytool -printcert | grep MD5`
    checkfail "Release failed: flavor=$flavor"

解压安装包,读取签名摘要,和正式签名文件的MD5值作比较;

接下来将验证通过的apk和mapping信息备份;

echoInfo "Copy file to backup"
folderName="v$version"
mkdir release/$folderName
cp -rf build/outputs/apk/android-$flavor-armeabi-release.apk release/$folderName/
cp -rf build/outputs/mapping release/$folderName/
echoShipLog $flavor $version

最后可以适当清理一下打包过程中产生的垃圾文件,部署apk至android设备

cleanTemp(){
	echoInfo "Cleaning temporary files..."
	git checkout assets/md/* tools/geek.keystore tools/geek.properties
}

launchApp(){
	adb shell am start -n $LAUNCH_PAGE -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
}

效果

各个目标点都实现后,整体串联起来;加上细节判断,下面完整的脚本代码;

#!/usr/bin/env bash

#############
# constant
#############

LAUNCH_PAGE="com.jikexueyuan.geekacademy/com.jikexueyuan.geekacademy.ui.activity.ActivitySplash"
CERTIFICATE_MD5="你的签名MD5摘要信息"
LOG_FILE="release/shipLog.md"
DEVICE="none"

RED_COLOR='\033[1;31m'
GREEN_COLOR='\033[1;32m'
RES='\033[0m'

#############
# functions
#############

launchApp(){
adb shell am start -n $LAUNCH_PAGE -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
}

checkfail(){
if [ ! $? -eq 0 ];then
echoWarn "$1"
exit 1
fi
}
echoWarn(){
echo -e "${RED_COLOR}$1${RES}"
}
echoInfo(){
echo -e "${GREEN_COLOR}$1${RES}"
}

checkDevices(){
firstDevice="`adb devices | sed -n 2p`"
for d in ${firstDevice} ; do
echoInfo "Found device: $d"
DEVICE="$d"
return
done

}

#Usage help
echoHelp(){
echoInfo "##This script is used to ship release apk with specify workflow"
echo "Usage:"
echoInfo "-v version_number"
echo -e "\\tRelease default flavor(Jikexueyuan)and backup with version_number"
echoInfo "-f flavorName"
echo -e "\\tRelease the supplied flavor by -f"
echoInfo "-h"
echo -e "\\tShow the help information"
echoInfo "-c"
echo -e "\\tClear all script generated temp files"
echoInfo "Example"
echo -e "\\tdeploy -v 4.0.0 -f Jikexueyuan -c"
echo -e "\\tdeploy -v 4.0.0 -c"
}

prepareForShip(){
if [ -f tools/release.keystore ]; then
echoInfo "Prepare release keystore..."
cd tools/
cp release.keystore geek.keystore
cp release.properties geek.properties
cd ..
fi

./tools/compressScript
./tools/updateApi

checkDevices
if [ $DEVICE != "none" ]; then
adb uninstall com.jikexueyuan.geekacademy
fi
}

backup(){
echoInfo "Backup released flavor..."
apk="build/outputs/apk/android-*-release.apk"
./tools/backup $apk $version
}

assembleFlavor() {
flavor=$1
version=$2
echoInfo "Start releasing, flavor=$flavor..."

checkDevices
if [ $DEVICE != "none" ]; then
./gradlew clean assemble"$flavor"Release install"$flavor"Release
else
./gradlew clean assemble"$flavor"Release
fi
checkfail "assemble failed for flavor:$1"

flavor=`echo $flavor | tr '[:upper:]' '[:lower:]'`
echoInfo "Check signature of $flavor..."
signature=`unzip -p build/outputs/apk/android-$flavor-armeabi-release.apk META-INF/CERT.RSA | keytool -printcert | grep MD5`
checkfail "Release failed: flavor=$flavor"

if [[ $signature == *"$CERTIFICATE_MD5"* ]];then
echoInfo "Signature verified";
if [ $version != "undefined" ]; then
echoInfo "Copy file to backup"
folderName="v$version"
mkdir release/$folderName
cp -rf build/outputs/apk/android-$flavor-armeabi-release.apk release/$folderName/
cp -rf build/outputs/mapping release/$folderName/

echoShipLog $flavor $version
fi
else
echoWarn "Signed with debug key"
fi
}

echoShipLog(){
echoInfo "Shipping completed, write log to $LOG_FILE"
timestamp=`date +%Y-%m-%d/%r`
revision=`git rev-parse --short HEAD`
branch=`git br |grep "*"`
author=`whoami`
echo "##$timestamp" >> $LOG_FILE
echo "flavor=$1" >> $LOG_FILE
echo "version=$2" >> $LOG_FILE
echo "revision=$revision" >> $LOG_FILE
echo "branch=$branch" >> $LOG_FILE
echo "author=$author" >> $LOG_FILE
}

shipNow(){
set -e
flavor=$2
version=$1

prepareForShip
assembleFlavor $flavor $version

checkDevices
if [ $DEVICE != "none" ]; then
launchApp
fi
}

cleanTemp(){
echoInfo "Cleaning temporary files..."
git checkout assets/md/* tools/geek.keystore tools/geek.properties
}

###################
# Release
###################

flavorName="Jikexueyuan"
version="undefined"
clean=0

while getopts "v:f:hc" arg
do
case
$arg in
v)
version="$OPTARG"
;;
f)
flavorName="$OPTARG"
;;
h)
echoHelp
exit 1
;;
c)
clean=1
;;
?)
echoWarn "Unknown arguments"
echoHelp
exit 1
;;
esac
done

echoInfo "version=$version,flavor=$flavorName"
shipNow $version $flavorName

if [ $clean -eq 1 ]; then
cleanTemp
fi