利用jekenis自动打包上传阿里云下载和通知钉钉机器人

利用jekenis自动打包、上传阿里云OSS生成二维码下载链接、通知钉钉机器人发送打包信息。

前面介绍了单项目打包,和多项目打包,IOS项目单独打包 IOS脚本批量打包
现在在单独打包的基础上增加一些功能:

打包完成过后,自动生成Plists文件上传到阿里云OSS, itms-services:// URL,这个 URL 是 iOS 应用程序安装包的协议格式,而不是 HTTP 或 HTTPS 协议格式的链接。
利用ossutil上传IPA包到阿里云OSS过后,然后利用qrserver服务生成QR二维码,同样子上传到阿里云。
使用markdown语法再转发生成的二维码链接直接下载。

一、mac安装jekenis

安装地址 https://www.jenkins.io/download/lts/macos/

brew install jenkins-lts 安装最近最新的一次版本

brew install jenkins-lts@YOUR_VERSION 安装对应的其他版本

如果遇到

1
2
3
4
5
6
7
8
9
10
Error1:brew install jenkins Error: The following directories are not writable by your user
在终端执行:
sudo chown -R whoami:admin /usr/local/bin
sudo chown -R whoami:admin /usr/local/share

Error2:遇到其他位置问题,重新安装一下最新的Homebrew
可参考地址 https://www.cnblogs.com/somepark/p/16813250.html

在Terminal 执行 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
这里最好选择第2个源,清华大学下载源。然后根据提示安装

以上安装完成 在重新brew install jenkins-lts执行下载安装 jenkins,如果失败,请选网络或者重试。

运行Jenkins

brew services start jenkins-lts 开启jenkins

brew services restart jenkins-lts 重启命令

二、ios项目xcodebuild打包

• 编译前清理工程:

xcodebuild clean -project ${projectName}.xcodeproj

• 获取项目工程名:

find . -name *.xcodeproj | awk -F "[/.]" '{print $(NF-1)} 中获取。

• 获取打包AdHoc、AppStore、Enterprise、Development 所需的plist目录,这个目录在打包脚本的目录里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 判读用户打包类型
packType=${PackageType}
echo "33[31m 打包参数值:${packType} n 33[0m"
if [ $packType == "AdHoc" ] ; then
exportOptionsPlistPath="${plistPath}/AdHocExportOptionsPlist.plist"
echo "当前选择构建AdHoc"
elif [ $packType == "AppStore" ] ; then
exportOptionsPlistPath="${plistPath}/AppStoreExportOptionsPlist.plist"
echo "当前选择构建AppStore"
elif [ $packType == "Enterprise" ] ; then
exportOptionsPlistPath="${plistPath}/EnterpriseExportOptionsPlist.plist"
echo "当前选择构建Enterprise"
elif [ $packType == "Development" ] ; then
exportOptionsPlistPath="${plistPath}/DevelopmentExportOptionsPlist.plist"
echo "当前选择构建Development"
else
echo "参数无效!!!"
exit 1
fi

• 执行xcodebuild打包IPA。

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
# Build 生成 APP
# 判断编译的项目类型是workspace还是project
if $is_workspace ; then
# 编译前清理工程
xcodebuild clean -workspace ${projectName}.xcworkspace \
-scheme ${schemeName} \
-configuration ${build_configuration}
xcodebuild archive -workspace ${projectName}.xcworkspace \
-scheme ${schemeName} \
-configuration ${build_configuration} \
-archivePath ${buildDir} \
-destination 'generic/platform=iOS' \
-quiet
else
# 编译前清理工程
xcodebuild clean -project ${projectName}.xcodeproj \
-scheme ${schemeName} \
-configuration ${build_configuration}
xcodebuild archive -project ${projectName}.xcodeproj \
-scheme ${schemeName} \
-configuration ${build_configuration} \
-archivePath ${buildDir} \
-destination 'generic/platform=iOS' \
-quiet
# 生成 ipa
xcodebuild -exportArchive \
-archivePath ${buildDir} \
-exportOptionsPlist ${exportOptionsPlistPath} \
-exportPath ${ipaPath} \
-allowProvisioningUpdates ${YES} \
-allowProvisioningDeviceRegistration ${YES} \

三、ipa包上传阿里云OSS

• 上传工具安装:

在执行前需要安装ossutil客户端工具,可参考官方文档进行安装,如果上传的文件已存在于oss存储空间中,则会覆盖原有文件,需谨慎操作,需要赋予该脚本执行权限,可以使用chmod +x script.sh命令进行授权。

安装ossutil

1
sudo -v ; curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash

• 查找ossutil安装在本地的目录,后面使用这个目录就不需要设置成全局变量。

1
which ossutil

• 验证是否已成功安装ossutil,如果屏幕中输出ossutil所有支持的命令,表明已成功安装ossutil。

1
ossutil

• 开始上传IPA包到阿里云OSS。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 执行上传ipa文件操作并记录日志
echo "开始上传ipa文件到阿里云OSS..."
echo "AccessKeyId: $ACCESS_KEY_ID"
echo "AccessKeySecret: $ACCESS_KEY_SECRET"
echo "Bucket Name: $BUCKET_NAME"
echo "Region ID: $REGION_ID"
echo "Remote Path: $REMOTE_PATH"
echo "File Name: $FILE_NAME"

/usr/local/bin/ossutil -i $ACCESS_KEY_ID -k $ACCESS_KEY_SECRET \
-e $REGION_ID.aliyuncs.com \
cp $IPA_FILE oss://$BUCKET_NAME/$REMOTE_PATH$FILE_NAME \
>> upload.log 2>&1

四、生成下载所需要的Plist文件

• 先执行生成Plist。

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
# 生成plist文件并记录日志
echo "开始生成plist文件..."
echo "ipa Download URL: $DOWNLOAD_URL"
echo "Plist Download URL: $PLIST_URL"
echo "APP Install URL: ${APP_INSTALL_URL}"
echo "Bundle Identifier: $bundleIdentifier"
echo "Bundle Version: $version"
echo "Display Name: $displayName"
echo ""

echo '<?xml version="1.0" encoding="UTF-8"?>'> $PLIST_NAME
echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >> $PLIST_NAME
echo '<plist version="1.0">' >> $PLIST_NAME
echo '<dict>' >> $PLIST_NAME
echo ' <key>items</key>' >> $PLIST_NAME
echo ' <array>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>assets</key>' >> $PLIST_NAME
echo ' <array>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>kind</key>' >> $PLIST_NAME
echo ' <string>software-package</string>' >> $PLIST_NAME
echo ' <key>url</key>' >> $PLIST_NAME
echo " <string>$DOWNLOAD_URL</string>" >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>kind</key>' >> $PLIST_NAME
echo ' <string>full-size-image</string>' >> $PLIST_NAME
echo ' <key>needs-shine</key>' >> $PLIST_NAME
echo ' <true/>' >> $PLIST_NAME
echo ' <key>url</key>' >> $PLIST_NAME
echo ' <string></string>' >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>kind</key>' >> $PLIST_NAME
echo ' <string>display-image</string>' >> $PLIST_NAME
echo ' <key>needs-shine</key>' >> $PLIST_NAME
echo ' <true/>' >> $PLIST_NAME
echo ' <key>url</key>' >> $PLIST_NAME
echo ' <string></string>' >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' </array>' >> $PLIST_NAME
echo ' <key>metadata</key>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>bundle-identifier</key>' >> $PLIST_NAME
echo " <string>$bundleIdentifier</string>" >> $PLIST_NAME
echo ' <key>bundle-version</key>' >> $PLIST_NAME
echo " <string>$version</string>" >> $PLIST_NAME
echo ' <key>kind</key>' >> $PLIST_NAME
echo ' <string>software</string>' >> $PLIST_NAME
echo ' <key>title</key>' >> $PLIST_NAME
echo " <string>$displayName</string>" >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' </array>' >> $PLIST_NAME
echo '</dict>' >> $PLIST_NAME
echo '</plist>' >> $PLIST_NAME
echo ""

• 将 Plist 文件保存到指定目录

1
2
3
4
mv ${PLIST_NAME} ${ipaPath}
# 定义变量(plist实际路径)
PLIST_FILE="${ipaPath}/${schemeName}.plist"
echo "Local File: $PLIST_FILE"

• 上传在本地目录中的Plist文件到阿里云OSS。

1
2
3
4
5
/usr/local/bin/ossutil -i $ACCESS_KEY_ID -k $ACCESS_KEY_SECRET \
-e $REGION_ID.aliyuncs.com \
cp $PLIST_FILE oss://$BUCKET_NAME/$REMOTE_PATH$PLIST_NAME \
>> upload.log 2>&1
echo "plist文件上传完成!请到阿里云控制台确认。"

五、生成二维码并上传

• 使用在线api-qrserver生成二维码:

1
2
3
4
5
6
7
8
# 下载二维码并保存到本地
QR_CODE_API="https://api.qrserver.com/v1/create-qr-code/?size=80x80&data=$(urlencode "$APP_INSTALL_URL")"
#远程qr图片名字(添加时间戳)
QR_NAME="${last_part}_qr_$(date +%Y%m%d%H%M%S).png"
#保存在本地qr地址
QR_LOCAL_PATH=${IPA_DIR}/${QR_NAME}
##生成二维码图片
curl -o ${QR_LOCAL_PATH} ${QR_CODE_API}

• url生成二维码时需要encode编码:

1
2
3
4
# 定义 urlencode 函数,用于对 URL 进行编码
urlencode() {
echo "$1" | sed 's/%/%25/g; s/\&/%26/g; s/ /%20/g; s/"/%22/g; s/#/%23/g; s/\//%2F/g; s/:/%3A/g; s/\?/%3F/g; s/@/%40/g; s/\+/%2B/g; s/\=/%3D/g'
}

• url二维码链接名称附加时间字符串:

原因是相同的名字,在使用dingtalk的时候,用markdown语法时,不明原因,然后会出现图片缓存,使用不同的二维码图片名字就不会出现二维码发送显示不出来的问题。

• 使用ossutil上传到阿里云OSS上:

1
2
3
4
5
6
7
8
9
10
11
#远程qr地址
REMOTE_QR_URL="https://archive-app.oss-cn-shanghai.aliyuncs.com/${REMOTE_PATH}${QR_NAME}"
# 上传链接地址二维码到阿里云记录日志
echo "上传二维码图片链接到阿里云..."
echo "Local QR Path : $QR_LOCAL_PATH"
echo "Remote QR URL: $REMOTE_QR_URL"
echo ""
/usr/local/bin/ossutil -i $ACCESS_KEY_ID -k $ACCESS_KEY_SECRET \
-e $REGION_ID.aliyuncs.com \
cp $QR_LOCAL_PATH oss://$BUCKET_NAME/$REMOTE_PATH$QR_NAME \
>> upload.log 2>&1

这儿上传的图片地址都是生成过后的本地地址找到该图片资源然后上传到阿里云服务器。

五、通知钉钉发送打包消息

• 使用markdown语法组装打包信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 打包编译方式
MESSAGE="#### 打包应用信息\n
- app类型:IOS平台
- 应用名称:${displayName}
- 项目名:${schemeName}
- 打包类型:$( [ "$PackageMethod" == "Debug" ] && echo "测试" || echo "正式" )
- 版本:${version}
- bundle identifier:${bundleIdentifier}
- IPA包地址:${DOWNLOAD_URL}
- Plist地址:${PLIST_URL}
- 二维码:
![下载链接二维码](${REMOTE_QR_URL})
安装链接:[点击下载]($APP_INSTALL_URL)"

• 生成带二维码和安装链接的Markdown消息体:

1
JSON_MESSAGE=$(printf '{"msgtype":"markdown","markdown":{"title":"应用打包已完成!","text":"%s"}}' "$MESSAGE")

• 使用oapi.dingtalk.com像钉钉发送消息:

1
2
3
curl 'https://oapi.dingtalk.com/robot/send?access_token='$TOKEN \
-H 'Content-Type: application/json' \
-d "${JSON_MESSAGE}" \

到这儿就所有的shell脚本逻辑完成,这样子就可以自动化打包了。

以下是所有的详细脚本:

里面的Access Token、ACCESS_KEY_ID、ACCESS_KEY_SECRET等不要使用,并且都是为了更加真实然后你替换成你自己的,这些信息都是后面被修改过的。

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
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
#!/bin/bash

# Script.sh
# Package
#
# Created by wws on 2023/02/25.
# Copyright © 2023 年 wws. All rights reserved.

#电脑配置的密码
mac_password="11234"

# 指定要打包编译的方式 : Release,Debug...
if [ $PackageMethod == "Debug" ]; then
build_configuration="Debug"
echo "打包方式:Debug"
else
build_configuration="Release"
echo "打包方式:Release"
fi

# 是否编译工作空间 (例:若是用Cocopods管理的.xcworkspace项目,赋值true;用Xcode默认创建的.xcodeproj,赋值false)
is_workspace="true"
# 进入项目工程目录
cd $WORKSPACE
# 获取项目名称
projectName=`find . -name *.xcodeproj | awk -F "[/.]" '{print $(NF-1)}'`
# Scheme Name
schemeName=${projectName}
# user Name
macName=$USER
# 打包所有生成路径
ipaPath="/Users/${macName}/Desktop/${schemeName}"
# 临时生成APP路径
buildDir="${ipaPath}/${schemeName}.xcarchive"
# 桌面脚本目录
plistPath="/Users/${macName}/Desktop/IOSPackageScript"

# 导出ipa所需要的plist文件路径 (默认为AdHocExportOptionsPlist.plist)
exportOptionsPlistPath="${plistPath}/AdHocExportOptionsPlist.plist"

echo "数据信息"
echo "pro path: $WORKSPACE"
echo "macName: $macName"
echo "projectName: $projectName"
echo "schemeName: $schemeName"
echo "build_configuration: $build_configuration"
echo "buildDir: $buildDir"

echo "ipaPath: $ipaPath"
echo "plistPath: $plistPath"
echo "exportOptionsPlistPath: $exportOptionsPlistPath"

# 开始时间
beginTime=`date +%s`

# 蒲公英分发参数 不分发可忽略 默认不分发 下面的两个KEY是默认测试的网址对应KEY
isUploadPgyer="0"
USERKEY="xxx"
APIKEY="xxx"

uploadFir="0"
# fir分发参数 不分发可忽略 默认分发
isUploadFir=${uploadFir}
echo "33[31m 上传参数值:${isUploadFir} n 33[0m"
FirApiToken="931bytiuv19uy68fd4108jfb946e2hp910adb97"

# AdHoc,AppStore,Enterprise三种打包方式的区别: http://blog.csdn.net/lwjok2007/article/details/46379945
echo "\033[36;1m打包方式 \033[0m"
echo "\033[33;1m1. AdHoc \033[0m"
echo "\033[33;1m2. AppStore \033[0m"
echo "\033[33;1m3. Enterprise \033[0m"
echo "\033[33;1m4. Development \033[0m"

# 判读用户打包类型
packType=${PackageType}
echo "33[31m 打包参数值:${packType} n 33[0m"
if [ $packType == "AdHoc" ] ; then
exportOptionsPlistPath="${plistPath}/AdHocExportOptionsPlist.plist"
echo "当前选择构建AdHoc"
elif [ $packType == "AppStore" ] ; then
exportOptionsPlistPath="${plistPath}/AppStoreExportOptionsPlist.plist"
echo "当前选择构建AppStore"
elif [ $packType == "Enterprise" ] ; then
exportOptionsPlistPath="${plistPath}/EnterpriseExportOptionsPlist.plist"
echo "当前选择构建Enterprise"
elif [ $packType == "Development" ] ; then
exportOptionsPlistPath="${plistPath}/DevelopmentExportOptionsPlist.plist"
echo "当前选择构建Development"
else
echo "参数无效!!!"
exit 1
fi

echo "\033[32m************************* 开始构建项目 ************************* \033[0m"

#0.安装证书
security unlock-keychain -p $mac_password ~/Library/Keychains/login.keychain
security set-key-partition-list -S apple-tool:,apple: -s -k $mac_password ~/Library/Keychains/login.keychain-db

# 指定输出文件目录不存在则创建
if [ -d "$ipaPath" ]; then
# 如果目录已经存在,则清空目录内的所有文件
rm -rf "${ipaPath:?}/"*
else
# 如果目录不存在,则创建目录
mkdir -p "$ipaPath"
fi
echo "目录:${ipaPath}"

#解锁 钥匙串
security unlock-keychain -p $mac_password ~/Library/Keychains/login.keychain
security set-key-partition-list -S apple-tool:,apple: -s -k $mac_password ~/Library/Keychains/login.keychain-db

# Build 生成 APPs
# 判断编译的项目类型是workspace还是project
if $is_workspace ; then
# 编译前清理工程
xcodebuild clean -workspace ${projectName}.xcworkspace \
-scheme ${schemeName} \
-configuration ${build_configuration}

xcodebuild archive -workspace ${projectName}.xcworkspace \
-scheme ${schemeName} \
-configuration ${build_configuration} \
-archivePath ${buildDir} \
-destination 'generic/platform=iOS' \
-quiet
else
# 编译前清理工程
xcodebuild clean -project ${projectName}.xcodeproj \
-scheme ${schemeName} \
-configuration ${build_configuration}


xcodebuild archive -project ${projectName}.xcodeproj \
-scheme ${schemeName} \
-configuration ${build_configuration} \
-archivePath ${buildDir} \
-destination 'generic/platform=iOS' \
-quiet
fi
# 检查是否构建成功
# 检查 ${buildDir} 目录是否存在有效的 .xcarchive 文件
if [ -d "${buildDir}" ] && [ -n "$(ls -A ${buildDir}/Products/Applications)" ]; then
echo "\033[32;1m项目构建成功\033[0m"
else
echo "\033[31;1m项目构建失败\033[0m"
exit 1
fi

echo "33[31m appName:$projectName n 33[0m"

# 生成 ipa
#xcodebuild -exportArchive -archivePath ${buildDir} -exportOptionsPlist ${exportOptionsPlistPath} -exportPath ${ipaPath} -allowProvisioningUpdates ${YES} -allowProvisioningDeviceRegistration ${YES} -exportFileName "${schemeName}.ipa"

# 生成 ipa
xcodebuild -exportArchive \
-archivePath ${buildDir} \
-exportOptionsPlist ${exportOptionsPlistPath} \
-exportPath ${ipaPath} \
-allowProvisioningUpdates ${YES} \
-allowProvisioningDeviceRegistration ${YES} \

if ls $ipaPath/*.ipa >/dev/null 2>&1; then
echo "33[31m n 生成 IPA 成功 nnnnn33[0m"
else
echo "33[31m n 生成 IPA 失败 nnnnn33[0m"
fi

## 遍历指定目录下的所有 IPA 文件
for ipas in "${ipaPath}"/*.ipa; do
if [ -f "$ipas" ]; then
# 如果当前路径存在 IPA 文件,则判断文件名是否等于 schemeName,如果不是则重命名该文件
ipaName=$(basename "$ipas")
if [ "${ipaName%.*}" != "$schemeName" ]; then
ipaExt="${ipaName##*.}"
newIpaName="${schemeName}.${ipaExt}"
mv "$ipas" "${ipaPath}/${newIpaName}"
echo "已将 ${ipaName} 重命名为 ${newIpaName}"
fi
fi
done

rm -rf ${buildDir}

#IPA文件的临时路径)
TEPE_IPA_FILE="${ipaPath}/${schemeName}.ipa"

echo "正在查寻包体信息: $TEPE_IPA_FILE"
# 获取 IPA 文件所在目录
IPA_DIR="$(dirname "$TEPE_IPA_FILE")"
# 解压 IPA 文件
unzip -o "$TEPE_IPA_FILE" -d "$IPA_DIR" > /dev/null 2>&1
# 获取 CFBundleShortVersionString
version=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$IPA_DIR/Payload/"*.app/Info.plist)
# 获取 CFBundleIdentifier
bundleIdentifier=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$IPA_DIR/Payload/"*.app/Info.plist)
# 获取 CFBundleDisplayName
displayName=$(/usr/libexec/PlistBuddy -c "Print :CFBundleDisplayName" "$IPA_DIR/Payload/"*.app/Info.plist)
# 提取最后一部分
last_part=$(echo $bundleIdentifier | awk -F "." '{print $NF}')

# 打印结果
echo "Version: $version"
echo "Bundle Identifier: $bundleIdentifier"
echo "Display Name: $displayName"

# 删除解压后的文件夹
rm -rf "${IPA_DIR}/Payload"
# 获取工程中的 Target 名称,用于作为 IPA 文件名称的一部分
ipaActName=${schemeName}
# 遍历指定目录下的所有 IPA 文件
for ipa in "${ipaPath}"/*.ipa; do
if [ -f "$ipa" ]; then
# 判断文件名是否含有中文字符
filename=$(basename "$ipa")
case "$filename" in
*[![:ascii:]]*) has_chinese=1
;;
*) has_chinese=0
;;
esac
# 提取 IPA 文件扩展名
ipaExt="${filename##*.}"
if [ $has_chinese -eq 1 ]; then
# 如果文件名含有中文字符,则使用 IPA 包 Bundle Identifier 的最后一段 和version命名
ipaActName="${last_part}_${build_configuration}_${version}"
else
# 如果文件名不含有中文字符,则直接使用 Target 名称和 Build Configuration 和 version命名
ipaActName="${ipaActName}_${build_configuration}_${version}"
fi
# 构造新的 IPA 文件名,并将原始文件重命名
newIpaName="${ipaActName}.${ipaExt}"
mv "$ipa" "${ipaPath}/${newIpaName}"
echo "已将 ${filename} 重命名为 ${newIpaName}"
fi
done

echo "ipaActName包的实际名字: $ipaActName"

# 上传fir
if [ $isUploadFir == "1" ]; then
echo "正在上传fir..."
fir p "${ipaPath}/${displayName}/${ipaActName}.ipa" -T ${FirApiToken}
fi

# 6.上传蒲公英分发平台
if [ $isUploadPgyer == "1" ]; then
echo "正在上传蒲公英..."
curl -F "file=@$ipaPath/${displayName}/${ipaActName}.ipa" -F "uKey=$USERKEY" -F "_api_key=$APIKEY" http://www.pgyer.com/apiv1/app/upload

fi

# 结束时间
endTime=`date +%s`
echo -e "打包时间$[ endTime - beginTime ]秒"

# 设置AccessKeyId和AccessKeySecret
ACCESS_KEY_ID="LTAI58LFpuu795aRBK7g24qkwtBh"
ACCESS_KEY_SECRET="vlKD890ge3u94UBV9gloc60Dopu652vFPtE09"
# 设置阿里云存储空间名称(bucketName)
BUCKET_NAME="archive-app"
# 设置阿里云地域(Region ID)
REGION_ID="oss-cn-shanghai"
# 设置阿里云目标路径(需先手动创建)
REMOTE_PATH="ios/"
# 设置本地文件名
FILE_NAME="${ipaActName}.ipa"
# 设置生成的plist文件名称
PLIST_NAME="${ipaActName}.plist"
# 设置安装包的下载链接,需要先将阿里云存储空间中对应文件的外网访问地址填入这里
DOWNLOAD_URL="https://archive-app.oss-cn-shanghai.aliyuncs.com/${REMOTE_PATH}${ipaActName}.ipa"
# Plist安装包的下载链接,
PLIST_URL="https://archive-app.oss-cn-shanghai.aliyuncs.com/${REMOTE_PATH}${PLIST_NAME}"
# app安装地址链接,
APP_INSTALL_URL="itms-services://?action=download-manifest&url=https://archive-app.oss-cn-shanghai.aliyuncs.com/${REMOTE_PATH}${PLIST_NAME}"
# IPA文件的实际路径)
LOCAL_IPA_FILE="${ipaPath}/${ipaActName}.ipa"

echo "本地包的实际路径位置: $TEPE_IPA_FILE"
# 执行上传ipa文件操作并记录日志
echo "开始上传ipa文件到阿里云OSS..."
echo "AccessKeyId: $ACCESS_KEY_ID"
echo "AccessKeySecret: $ACCESS_KEY_SECRET"
echo "Bucket Name: $BUCKET_NAME"
echo "Region ID: $REGION_ID"
echo "Remote Path: $REMOTE_PATH"
echo "File Name: $FILE_NAME"
echo ""
/usr/local/bin/ossutil -i $ACCESS_KEY_ID -k $ACCESS_KEY_SECRET \
-e $REGION_ID.aliyuncs.com \
cp $LOCAL_IPA_FILE oss://$BUCKET_NAME/$REMOTE_PATH$FILE_NAME \
>> upload.log 2>&1

echo "ipa文件上传完成!请到阿里云控制台确认。"

# 执行上传plist文件操作并记录日志
echo "开始上传plist文件..."
echo "AccessKeyId: $ACCESS_KEY_ID"
echo "AccessKeySecret: $ACCESS_KEY_SECRET"
echo "Bucket Name: $BUCKET_NAME"
echo "Region ID: $REGION_ID"
echo "Remote Path: $REMOTE_PATH"
echo "File Name: $PLIST_NAME"

# 生成plist文件并记录日志
echo "开始生成plist文件..."
echo "ipa Download URL: $DOWNLOAD_URL"
echo "Plist Download URL: $PLIST_URL"
echo "APP Install URL: ${APP_INSTALL_URL}"
echo "Bundle Identifier: $bundleIdentifier"
echo "Bundle Version: $version"
echo "Display Name: $displayName"
echo ""

echo '<?xml version="1.0" encoding="UTF-8"?>'> $PLIST_NAME
echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >> $PLIST_NAME
echo '<plist version="1.0">' >> $PLIST_NAME
echo '<dict>' >> $PLIST_NAME
echo ' <key>items</key>' >> $PLIST_NAME
echo ' <array>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>assets</key>' >> $PLIST_NAME
echo ' <array>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>kind</key>' >> $PLIST_NAME
echo ' <string>software-package</string>' >> $PLIST_NAME
echo ' <key>url</key>' >> $PLIST_NAME
echo " <string>$DOWNLOAD_URL</string>" >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>kind</key>' >> $PLIST_NAME
echo ' <string>full-size-image</string>' >> $PLIST_NAME
echo ' <key>needs-shine</key>' >> $PLIST_NAME
echo ' <true/>' >> $PLIST_NAME
echo ' <key>url</key>' >> $PLIST_NAME
echo ' <string></string>' >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>kind</key>' >> $PLIST_NAME
echo ' <string>display-image</string>' >> $PLIST_NAME
echo ' <key>needs-shine</key>' >> $PLIST_NAME
echo ' <true/>' >> $PLIST_NAME
echo ' <key>url</key>' >> $PLIST_NAME
echo ' <string></string>' >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' </array>' >> $PLIST_NAME
echo ' <key>metadata</key>' >> $PLIST_NAME
echo ' <dict>' >> $PLIST_NAME
echo ' <key>bundle-identifier</key>' >> $PLIST_NAME
echo " <string>$bundleIdentifier</string>" >> $PLIST_NAME
echo ' <key>bundle-version</key>' >> $PLIST_NAME
echo " <string>$version</string>" >> $PLIST_NAME
echo ' <key>kind</key>' >> $PLIST_NAME
echo ' <string>software</string>' >> $PLIST_NAME
echo ' <key>title</key>' >> $PLIST_NAME
echo " <string>$displayName</string>" >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' </dict>' >> $PLIST_NAME
echo ' </array>' >> $PLIST_NAME
echo '</dict>' >> $PLIST_NAME
echo '</plist>' >> $PLIST_NAME
echo ""

# 将 Plist 文件保存到指定目录
mv ${PLIST_NAME} ${ipaPath}
# 定义变量(plist实际路径)
PLIST_FILE="${ipaPath}/${ipaActName}.plist"
echo "Local File: $PLIST_FILE"

/usr/local/bin/ossutil -i $ACCESS_KEY_ID -k $ACCESS_KEY_SECRET \
-e $REGION_ID.aliyuncs.com \
cp $PLIST_FILE oss://$BUCKET_NAME/$REMOTE_PATH$PLIST_NAME \
>> upload.log 2>&1
echo "plist文件上传完成!请到阿里云控制台确认。"

# 定义 urlencode 函数,用于对 URL 进行编码
urlencode() {
echo "$1" | sed 's/%/%25/g; s/\&/%26/g; s/ /%20/g; s/"/%22/g; s/#/%23/g; s/\//%2F/g; s/:/%3A/g; s/\?/%3F/g; s/@/%40/g; s/\+/%2B/g; s/\=/%3D/g'
}
echo "下载二维码并保存到本地..."
# 下载二维码并保存到本地
QR_CODE_API="https://api.qrserver.com/v1/create-qr-code/?size=80x80&data=$(urlencode "$APP_INSTALL_URL")"
QR_NAME="${last_part}_qr_$(date +%Y%m%d%H%M%S).png"
#保存在本地qr地址
QR_LOCAL_PATH=${IPA_DIR}/${QR_NAME}
##生成二维码图片
curl -o ${QR_LOCAL_PATH} ${QR_CODE_API}
#远程qr地址
REMOTE_QR_URL="https://archive-app.oss-cn-shanghai.aliyuncs.com/${REMOTE_PATH}${QR_NAME}"
# 上传链接地址二维码到阿里云记录日志
echo "上传二维码图片链接到阿里云..."
echo "Local QR Path : $QR_LOCAL_PATH"
echo "Remote QR URL: $REMOTE_QR_URL"
echo ""
/usr/local/bin/ossutil -i $ACCESS_KEY_ID -k $ACCESS_KEY_SECRET \
-e $REGION_ID.aliyuncs.com \
cp $QR_LOCAL_PATH oss://$BUCKET_NAME/$REMOTE_PATH$QR_NAME \
>> upload.log 2>&1

echo "开始发送钉钉通知消息..."
# 钉钉机器人
ROBOT="0490bac64-08b1-490-be72-d185uy978342"
# 定义钉钉机器人的 Access Token
TOKEN="f77134d816899nh5ce7d5aa2628900fad3433510785668999dc1aaed89561df24"
echo "robot : $ROBOT"
echo "robot access token: $TOKEN"


# 打包编译方式
MESSAGE="#### 打包应用信息\n
- app类型:IOS平台
- 应用名称:${displayName}
- 项目名:${schemeName}
- 打包类型:$( [ "$PackageMethod" == "Debug" ] && echo "测试" || echo "正式" )
- 版本:${version}
- bundle identifier:${bundleIdentifier}
- IPA包地址:${DOWNLOAD_URL}
- Plist地址:${PLIST_URL}
- 二维码:
![下载链接二维码](${REMOTE_QR_URL})
安装链接:[点击下载]($APP_INSTALL_URL)"

## 生成带二维码和安装链接的Markdown消息体
JSON_MESSAGE=$(printf '{"msgtype":"markdown","markdown":{"title":"应用打包已完成!","text":"%s"}}' "$MESSAGE")

curl 'https://oapi.dingtalk.com/robot/send?access_token='$TOKEN \
-H 'Content-Type: application/json' \
-d "${JSON_MESSAGE}" \

使用时在jekenis需要两个参数:

p9h6cs1.png

• 判读用户 AdHoc AppStore Enterprise Development

如果打包出现证书匹配问题,如果选择的auto 脚本里需要配置,上面脚本已经配置。

-allowProvisioningUpdates ${YES}

-allowProvisioningDeviceRegistration ${YES}

使用archive失败。

如果打包报其他错误,请先在Xcode项目上保证能archive,先解决掉代码上的错误才能保证脚本打包。

请先配置好项目Auto自动证书,和手动打包的证书,并且在打包的Mac系统上有这些证书存在。

如果还包括,检查你的项目使用Xcode是否能archive成功,然后看看是否缺失lib和或者其他sdk库。

使用是请确保电脑设置的密码正确。

#电脑配置的密码 mac_password=”1111”,修改成你自己的。

使用将IOSPackageScript文件夹放在桌面根目录即可。

里面如何项目打包出来的不是英文的名字会自动修改为bundle identifier最后面分隔符的”.”最后部分英文作为包的名字。

确保项目主目录层级下有 .xcworkspace 或者 .xcodeproj文件,不支持在子层级或者多层子级目录下。

是否编译工作空间 (例:若是用Cocopods管理的.xcworkspace项目,赋值true;用Xcode默认创建的.xcodeproj,赋值false)

is_workspace=”true”

打包完成过后就会出现在钉钉消息里

p9h6ozd.png