作为一名Android开发程序员,对于安卓的打包操作定不陌生,但却可能因为需要打多个渠道的包,然后需要对安装包进行加固、重新签名等一系列的操作而感到很烦恼,而且,由于打包电脑的性能和配置的影响,可能每一次发布新版本时都会花上很多的时间在这一系列繁琐的事情上,而苦恼!
因此,便有了我现在一直在使用的自动打包脚本。。。。
自动化打包的流程概述
一、打包
这里的打包指的是打一个release包,这一步可以使用Android Studio中的Gradle工具自带的功能完成,其实也就是运行一个打包脚本:./gradlew assembleRelease
这一行代码可以完成本次打包任务的所有渠道包的task。当然,这里的前提是在项目中已经配置好了多渠道包的相关配置,以及自动签名的相关配置,如果这两个配置还有不会的,可以到网上一搜便有。
二、提取打好的安装包
提取打好的安装包指的是把第一步执行的task所生成的apk文件取出来,放到指定的文件路径下,然后去进行下一步操作。当然,手动去提取安装包也是可以的。但是我们现在的目的是为了利用程序来帮我们完成这一步操作。
提取安装包,首先是需要清楚安装包所在的路径,然后我们才能拿到我们所需要的apk文件。所有生成的apk文件的路径是在app/build/outputs/apk
下面,如果是多渠道打包的话,会在apk文件夹下面生成对应的渠道包为文件名的文件夹,然后,可以在对应的文件夹下面找到对应的release/debug的相关文件和信息,当然也包括了apk文件。然后我们只需要利用一个for循环就可以把apk文件夹下面的所有符合我们需求的release版本的apk文件copy到我们指定的文件夹下面。
三、加固apk文件
现在很多的应用市场上传apk文件的时候都会要求开发者对apk文件进行加固,当然,为了保护apk文件不被他人破解和篡改信息,对apk加固也是一个很好的方法。当然,加固安装包的行为也只是防君子而不防小人,但是也至少能起到一定的作用,这里就不再赘述了。apk加固的软件有很多,这里我们使用的是360加固保。
以往我们加固apk文件的时候,是直接使用360加固的相关桌面软件来处理加固任务的,但是始终是需要人为的去上传所有需要加固的apk文件,然后等加固完成后,再去手动修改加固后的文件名,然后再进行下一步的操作,比如上传应用市场等。后来在360加固保的官网找到了利用shell来对文件加固的介绍,然后便开始了加固shell的编写和调试。
四、重命名加固文件
重命名加固后的文件是因为360加固保加固apk文件后,会在apk原有的apk文件名之后添加一系列的信息,这个是我们不需要的,所以需要对文件名进行处理。此处的重命名也就是把360加固保给文件名自动添加上去的内容给去掉。因为工作的需要,我们的任务还需要把修改后的文件压缩成一个zip文件。
具体操作和脚本描述如下
一、打包
和上面描述的打包一样,任务就是打包,只需要执行./gradlew assembleRelease
命令就可以了,但是为了代码段整洁性,在打包之前,我们一般都会想clean一下项目,然后再进行打包的任务。所以在这之前还需要执行./gradlew clean
命令,所以打包执行的命令应该是这样的一个顺序
## 打包前先clean一下整个项目,然后再打包
echo "开始clean项目"
./gradlew clean
echo "clean结束"
## 用gradle打包,release版本
./gradlew assembleRelease
基本上也就这两行代码就可以完成打包任务了,下一步我们便是需要提取apk文件了
二、提取apk文件
入上所述,我们只需要去app/build/outpus/apk
路径下去把符合我们要求的apk文件拿到,然后放到指定的文件夹下即可。此处,我们定义一个方法loopToCopyFile
来完成apk文件的提取
## 循环遍历当前文件夹下的文件,并复制到文件到目标文件夹
function loopToCopyFile(){
for element in `ls $1`
do
dirs_or_file=$1"/"${element}
if [[ -d ${dirs_or_file} ]]
then
dirName=${dirs_or_file##*/}
if [[ ${dirName} == "debug" || ${dirName} == "pre" ]]; then
echo "${dirName}文件夹中的apk非release版本,跳过"
else
loopToCopyFile ${dirs_or_file}
fi
else
filename=${dirs_or_file##*/}
echo "======================================================"
echo "当前被复制的文件名称:$filename"
if [[ ${filename} == "output.json" ]]; then
#statements
echo "非必要文件,跳过$filename"
else
cp_file_name=${targetPath}/${filename}
cp -af ${dirs_or_file} ${cp_file_name}
file_copy_count=`expr ${file_copy_count} + 1`
fi
fi
done
}
当然,则只是这一步中的核心处理逻辑,实际处理的时候,我们还需要把目标文件夹清空,只保留我们本次操作的文件,因此,附上清空文件夹的操作:clearDir
,当然,在清空文件夹之前,还需要判断目标文件夹时候存在,不存在,则需要创建,存在着清空文件夹。这一步的操作,也放在了下面的代码中。
## 清空文件夹
function clearDir(){
for file in `ls $1`
do
dirs_or_file=$1"/"${file}
if [[ -f ${dirs_or_file} ]]; then
#statements
rm -f ${dirs_or_file}
else
rm -fr ${dirs_or_file}
fi
done
}
## 判断目标文件是否存在,不存在则创建文件夹,否则,清空文件夹中的文件
if [[ ! -d ${targetPath} ]];then
echo "目标文件夹不存在,开始创建"
mkdir -p ${targetPath}
else
echo "目标文件夹存在,清空文件夹"
# rm -fr $targetPath
clearDir ${targetPath}
fi
三、加固apk文件
上面我们也提到了加固的软件是360加固保,因此,根据其官方文档介绍,shell命令加固文件的步骤如下:登录360加固助手
、配置签名文件
、签名
。因此,简易脚本如下:
echo "打开加固助手目录"
jiagu_dir=/Users/${USER}/Desktop/360加固/jiagu
cd $jiagu_dir
# 登录360加固
echo "登录360加固助手"
java -jar jiagu.jar -login [你的账号] [你的密码] >/dev/null 2>&1
# 配置签名文件
echo "配置签名文件"
java -jar jiagu.jar -importsign [签名文件路径] [storePassword] [alias] [alias password] >/dev/null 2>&1
# 循环签名
jiagu ${apks_dir}
# 等待当前脚本进程下的子进程结束
wait
上面已经完整的列出了360加固保在shell中加固apk文件的整体流程,其中jiagu
就是对文件加固的具体方法,具体方法如下所示:
# 循环加固apk文件并签名
function jiagu(){
for file in `ls $1`
do {
apk_file=$1"/"${file}
if [[ -f ${apk_file} ]]; then
echo "开始加固apk文件:${apk_file}"
java -jar jiagu.jar -jiagu ${apk_file} ${out_path} -autosign >/dev/null 2>&1
fi
} &
sleep 2
done
}
四、重命名和压缩文件
这一步的操作应该是分成2步,首先是对文件重命名。其中的主要方法和逻辑如下:
# 循环去重命名文件
function loopToRenameFile(){
for element in `ls $1`
do
dirs_or_file=$1"/"${element}
if [[ -d ${dirs_or_file} ]]
then
if [[ ${dirs_or_file} == ${targetPath} ]]; then
echo "目标文件夹,跳过"
else
loopToRenameFile ${dirs_or_file}
fi
else
filename=${dirs_or_file##*/}
echo "======================================================"
echo "当前文件名称:$filename"
if [[ ${filename##*.} == "zip" ]]; then
#statements
echo "非必要文件,跳过$filename"
else
nameLen=${#filename}
splitFileName ${filename}
jiagu=${need_delete_str}
lastLen=${#jiagu}
replace=${filename:(nameLen-lastLen-4):lastLen}
filename=${filename/$replace/''}
cp_file_name=${targetPath}/${filename}
mv ${dirs_or_file} ${cp_file_name}
## rename
file_copy_count=`expr ${file_copy_count} + 1`
echo "文件路径${cp_file_name}"
fi
fi
done
}
上面的代码中,有一个是处理文件名的方法splitFileName
,其主要是为了处理因为版本号不同导致的相关数据长度不同,而导致need_delete_str
会发生变化的问题,而不能已固定长度去截取需要删除的字符串的问题。其内部逻辑如下:
# 分割文件名,以便于获取文件名中需要删除的字段,这部分数据保存于need_delete_str中
function splitFileName() {
if [[ -z "${need_delete_str}" ]]; then
split_str=$1
array=(${split_str//_/ })
index=${#array[@]}
index=`expr ${index} - 3`
new_array=${array[@]:index:3}
new_end_str=""
for var in ${new_array[@]}
do
new_end_str="${new_end_str}_${var}"
done
end_split=(${new_end_str//./ })
need_delete_str=${end_split[0]}
fi
}
最后一步就是压缩文件了,这里我们就不写具体的路径和名称了,定一个压缩文件的前缀zip_prefix
,定义一个加固后的文件保存的文件夹jiagu_dir
,下面的zipFile
方法中会替换掉原有的信息,压缩完成后会打开文件夹,方便于操作。方法内容具体如下:
# 压缩文件
function zipFile(){
cd ${originalPath}
files=$(ls ${targetPath})
for filename in ${files}
do
OLD_IFS="$IFS" #保存旧的分隔符
IFS="_"
array=(${filename})
IFS="$OLD_IFS"
size=${#array[@]}
ver=${array[size-2]}
break
done
zip -r "zip_prefix_${ver}.zip" ./jiagu_dir/*.apk
echo "文件压缩完成,即将打开文件夹"
open .
}
当然,每一步都可以单独创建一个shell脚本文件,这样也可以单独运行相关的操作。如下,是我实际应用中的脚本文件:
#! /bin/bash
## 打包前先clean一下整个项目,然后再打包
echo "开始clean项目"
./gradlew clean
echo "clean结束"
## 用gradle打包,release版本
./gradlew assembleRelease
## 提取打好的release包
./extract_android_release_apk.sh
## 打开release版本的apk所在的文件夹
open /Users/${USER}/Desktop/zhiku_android_release
## 打开360加固助手软件
./jiagu.sh
## 加固后的apk重命名并创建压缩文件
./rename_jiagu_apk.sh
基本上也就这样了,当然,还有其他的一些操作,比如可以直接上传到应用市场、完成这些操作之后通过钉钉机器人去发群消息,这些都是可以的,后面我会写一些关于Jenkins打包的一些东西,具体的操作敬请期待。