-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathsigner.sh
executable file
·298 lines (256 loc) · 10.5 KB
/
signer.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
configPath=signerConfig.ini # 配置文件的名称
androidCommandPath="" # Android sdk
findPath="." # 要搜索的目录,默认为当前目录
storeFile="" # 签名文件的路径
storePassword="" # 签名文件的密码
keyAlias="" # key的别名
keyPassword="" # key的密码
auto="no" # 是否自动搜索
repeatSigner="false" # 是否重复签名,,已完成签名的apk名字上会加个“signer”,true:会再签名,false:不会再签名
searchKey="*.apk"
configSearchPath="" # 指定搜索的目录,不指定默认问当前目录
configOutPath="" # 指定签名完的apk输出目录,不指定默认为当前目录下的out目录
sourceApkPath=""
tatalTimes=0 # 总的签名次数
errorTimes=0 # 失败的签名次数
findApkLastResult="" # 获取查找结果的最后一个apk
findApkArray=() #查找到的所有apk的数组
isShowLog="true" # 是否显示log
log()
{
msg=$1
if [[ "$isShowLog" != "false" ]]; then
echo -e "$msg"
fi
}
# 获取配置文件的内容
function getConfigFileInfo()
{
storeFile=`cat $configPath | grep storeFile | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
storePassword=`cat $configPath | grep storePassword | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
keyAlias=`cat $configPath | grep keyAlias | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
keyPassword=`cat $configPath | grep keyPassword | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
androidCommandPath=`cat $configPath | grep buildTools | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
auto=`cat $configPath | grep auto | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
repeatSigner=`cat $configPath | grep repeatSigner | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
searchKey=`cat $configPath | grep searchKey | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
configSearchPath=`cat $configPath | grep searchPath | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
configOutPath=`cat $configPath | grep outPath | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
sourceApkPath=`cat $configPath | grep sourceApkPath | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g`
# 检查命令行目录是否存在
if [[ ! -d "${androidCommandPath}" ]]; then
echo -e "\n错误!配置的build-tools路径找不到,请检查${configPath}文件中buildTools的设置\n"
exit 0
fi
# 检查zipalign命令是否存在
zipalign="${androidCommandPath}/zipalign"
if [[ ! -f "$zipalign" ]]; then
echo -e "\n错误!${zipalign} 命令找不到\n"
exit 0
fi
# 检查apksigner命令是否存在
apksigner="${androidCommandPath}/apksigner"
if [[ ! -f "$apksigner" ]]; then
echo -e "\n错误!${apksigner} 命令找不到,apksigner命令在build-tools 25.0.0才出现\n"
exit 0
fi
if [[ -z "$storeFile" ]]; then
echo "请输入签名文件地址:"
read -e storeFile
fi
if [[ -z "$storePassword" ]]; then
echo "请输入签名密码:"
read -s storePassword
fi
if [[ -z "$keyAlias" ]]; then
echo "请输入key的别名:"
read keyAlias
fi
if [[ -z "$keyPassword" ]]; then
echo "请输入key的密码:"
read -s keyPassword
fi
if [[ "$repeatSigner" != "true" ]]; then
repeatSigner="false"
fi
if [[ -z "$searchKey" ]]; then
searchKey="*.apk"
fi
}
# 获取手动输入的信息
function getInputConfigInfo()
{
read -e -p "第1步(共5部)请输入签名文件地址:" storeFile
read -p "第2步(共5部)请输入签名密码:" -s storePassword
echo ""
read -p "第3部(共5部)请输入key的别名:" keyAlias
read -p "第4部(共5部)请输入key的密码:" -s keyPassword
echo ""
read -e -p "第5步(共5部)请输入build-tools路径:" androidCommandPath
}
# 选择获取配置信息的方式
function processConfigInfo()
{
if [[ -f "$configPath" ]]; then
getConfigFileInfo
else
echo -e "\n当前目录下找不到配置文件${configPath},需要手动输入账号和密码,\n强烈建议在当前目录下创建${configPath}配置文件\n"
getInputConfigInfo
repeatSigner="true" # 如果手动指定apk路径,则重复签名
fi
}
# 根据指定的目录搜索apk
function findApk()
{
searchDir=$1
searchMatchWords=$2
findApkArray=($(find $searchDir -name $searchMatchWords))
length=${#findApkArray[*]}
if [ $length -gt 0 ]; then # 数组元素是否 >= 0
findApkLastResult=${findApkArray[$length-1]}
else
findApkLastResult=""
fi
}
# V2签名apk
function signAndroidApk()
{
sourceApk=$1
outputPath=$2
if [ ! -f "$sourceApk" ];then
echo "注意啦!第${tatalTimes}个输入的apk不存在${sourceApk}"
let errorTimes++
else
apkPath=${sourceApk%/*}
apkName=${sourceApk##*/}
# 创建输出的目录
if [[ -z "$outputPath" ]]; then # outputPath的值为空
outputPath=${apkPath}/out
if [ ! -d "$outputPath" ]; then
mkdir -p $outputPath
echo 没有指定输出路径,则输出到apk所在目录的out目录:$outputPath
fi
elif [[ ! -d "$outputPath" ]]; then # outputPath目录不存在
echo 由于${outputPath}路径不存在,则创建该路径。
mkdir -p $outputPath
# 创建目录失败
if [[ ! -d "$outputPath" ]]; then
echo 创建${outputPath}目录失败,则输出到apk所在目录的out目录
outputPath=${apkPath}/out
if [ ! -d "$outputPath" ]; then
mkdir -p $outputPath
fi
fi
fi
# 检查命令行目录是否存在
if [[ ! -d "${androidCommandPath}" ]]; then
echo -e "\n错误!配置的build-tools路径找不到,请检查${configPath}文件中buildTools的设置\n"
exit 0
fi
zipalignApk="$outputPath/zipalign-$apkName"
signerApk="$outputPath/signer-$apkName"
# 开始4K对齐
#zipalign=$androidCommandPath/zipalign
$androidCommandPath/zipalign -f 4 $sourceApk $zipalignApk
if [[ ! -f "$zipalignApk" || ! -s "${zipalignApk}" ]];then # 对齐完的apk不是一个文件,或者大小为0kb
echo "注意啦!第${tatalTimes}个apk 4K对齐失败${zipalignApk}"
let errorTimes++
rm -f $zipalignApk
else
# 4K对齐成功,开始V2签名
#apksigner=$androidCommandPath/apksigner
$androidCommandPath/apksigner sign --ks $storeFile --ks-pass pass:$storePassword --ks-key-alias $keyAlias --key-pass pass:$keyPassword --out $signerApk $zipalignApk
# 签名完,删除对齐过程中生成的apk
rm -f $zipalignApk
if [ -f "$zipalignApk" ];then
echo -e "\n注意!对齐生成的apk删除失败,请手动删除:${zipalignApk}\n"
fi
if [ ! -f "$signerApk" ]; then
echo -e "\n注意啦!第${tatalTimes}个apk签名失败,没有生成签名的apk\n\n"
let errorTimes++
elif [ ! -s "$signerApk" ];then # 生成的apk大小为0kb
echo -e "\n注意啦!第${tatalTimes}个apk签名失败,因为生成签名的apk大小为0KB\n\n"
let errorTimes++
rm -f $signerApk
else
echo V2签名成功:$signerApk
fi
fi
fi
}
# 根据配置内容选择要获取apk
function getApk()
{
# 如果配置的目录不为空,并且该目录存在
if [[ -n "$configSearchPath" && -d "$configSearchPath" ]]; then
findPath=$configSearchPath
else
echo -e "\n由于searchPath=${configSearchPath}目录不存在或者没有配置searchPath的值,则默认在当前目录搜索apk"
findPath="."
fi
if [[ "$auto" == "true" ]]; then
# 1、自动搜索apk
echo -e "\n${configPath}中设置auto=true,开始自动搜索${findPath}目录"
findApk $findPath $searchKey
elif [[ "$auto" == "false" ]]; then
# 2、手动指定apk路径
echo "\n${configPath}中设置auto=false,需要手动输入apk路径"
echo "如果想自动搜索目录下的apk,请在${configPath}中配置auto=true\n"
findApkArray[0]=$sourceApkPath #手动指定apk
else
# auto!=false或者auto!=true,就会执行这里
echo -e "\n---------------提示----------------"
echo -e "${configPath}配置中auto=${auto},需要选择要执行的的方式,
\n如果配置auto=true则自动搜索,auto=false则手动输入。"
echo -e "---------------提示----------------\n"
# 选择方式
echo ""
read -n1 -p "是否自动搜索指定目录(默认搜索当前目录)下的apk,否则要手动指定apk路径, [Y/N]?" answer
case $answer in
Y | y)
# 3、自动搜索apk
echo -e "\n开始自动搜索${findPath}目录下的apk"
findApk $findPath $searchKey
;;
N | n)
# 4、手动指定apk路径
echo -e "\n"
read -p "请输入要签名apk的路径:" -e inputApkPath
findApkArray[0]=$inputApkPath
;;
*)
echo -e "\n"
echo "选择错误:$answer"
;;
esac
fi
}
# 循环执行签名apk
function processApk()
{
for apk in ${findApkArray[@]}
do
let tatalTimes++
echo -e "\n\n准备开始签名第${tatalTimes}个Apk =$apk"
# 已签名的apk是否再次签名
if [[ "$apkName" == signer-*.apk && "$repeatSigner" == "false" ]]; then
echo -e "注意啦!第${tatalTimes}个Apk已签名,不需要再签名了:$sourceApk
\n如果想重复签名请将repeatSigner=true"
let errorTimes++
else
signAndroidApk $apk $configOutPath
fi
done
#不需要循环数组,直接使用数组中最后一个结果进行签名
#let tatalTimes++
#signAndroidApk $findApkLastResult
success=`expr ${tatalTimes} - ${errorTimes}` # 计算成功的次数
echo -e "\n一共找到${tatalTimes}个apk,成功签名${success}个,失败${errorTimes}个!\n"
}
# 程序运行入口
# 1、获取配置文件的内容
processConfigInfo
# 2、搜索apk(根据配置内容选择要获取apk的方式)
getApk
# 3、开始处理apk签名
processApk