Jenkins移动端自动构建

记录一下jenkins自动构建android与ios安装包。

安装

Jenkins

1
2
3
4
5
6
7
brew install jenkins-lts
brew services start jenkins-lts
#Generating for QR code
brew install qrencode
#brew install md5sha1sum
#brew services list
#jenkins-lts started test /Users/test/Library/LaunchAgents/homebrew.mxcl.jenkins-lts.plist

注意:2.263.4为正确运行的版本,如果通过uninstall后,可以在安装后手动替换掉war文件:

1
cp -a /Developer/jenkins-war-2.263.4.war /usr/local/opt/jenkins-lts/libexec/jenkins.war

新版本的workspace默认为${ITEM_ROOT}/workspace,位于job目录下。需要修改~/.jenkins/config.xml文件的内容:

1
<workspaceDir>${JENKINS_HOME}/workspace/${ITEM_FULL_NAME}</workspaceDir>

修改配置:
/usr/local/Cellar/jenkins-lts/2.289.1/homebrew.mxcl.jenkins-lts.plist:

1
2
3
4
5
...
<string>--httpListenAddress=0.0.0.0</string>
<string>--httpPort=8080</string>
<string>--prefix=/ci</string>
...

系统配置

没有采用jenkins插件方式安装,而是通过命令行shell脚本直接运行,所以需要事先在这台电脑上安装配置好相关的环境,并确保手动构建、打包功能正常,手动发布到appstore能成功。

android gradle配置:

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
ext {
defaultIsJenkins = "false"
isJenkins = project.hasProperty('IS_JENKINS') ? IS_JENKINS : defaultIsJenkins
}
def loadSigningConfig() {
if ("true".equals(isJenkins)) {
// Create a variable called keystorePropertiesFile, and initialize it to your
// keystore.properties file, in the rootProject folder.
def keystorePropertiesFile = rootProject.file("/Users/test/.jenkins/scripts/signingConfigs.properties")
// Initialize a new Properties() object called keystoreProperties.
def keystoreProperties = new Properties()
// Load your keystore.properties file into the keystoreProperties object.
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android.signingConfigs.config.keyAlias = keystoreProperties['keyAlias']
android.signingConfigs.config.keyPassword = keystoreProperties['keyPassword']
android.signingConfigs.config.storeFile = file(keystoreProperties['storeFile'])
android.signingConfigs.config.storePassword = keystoreProperties['storePassword']
}
}

android {
...

signingConfigs {
config {
}
}
loadSigningConfig()

defaultConfig {
...
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
...
}
...

buildTypes {
release {
...
if ("true".equals(isJenkins)) {
signingConfig signingConfigs.config
}
}
debug {
if ("true".equals(isJenkins)) {
signingConfig signingConfigs.config
}
}
}

applicationVariants.all { variant ->
variant.outputs.all { output ->
if ("true".equals(isJenkins)) {
outputFileName = new File("xwallet-"+rootProject.ext.versionName+"."+rootProject.ext.versionCode + "-"+BUILD_TYPE+".apk")
}
...
}
}

nginx配置

安装:

1
2
brew install nginx
brew services start nginx

/usr/local/etc/nginx/nginx.conf:

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
server {
listen 443;
server_name appbuild.xxx.com;
server_tokens off;
client_max_body_size 0;

charset utf-8;

ssl on;
ssl_certificate /etc/ssl/abc.hk/abc.crt;
ssl_certificate_key /etc/ssl/abc.hk/abc.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDH:AESGCM:HIGH:!RC4:!DH:!MD5:!aNULL:!eNULL;

## Individual nginx logs for this GitLab vhost
access_log /Users/jenkins/works/logs/www_access.log;
error_log /Users/jenkins/works/logs/www_error.log;

location ^~ /ci/appDownloads {
alias /Users/jenkins/works/;
autoindex on;
}

location ^~ /eclipse {
alias /Users/jenkins/works/eclipseupdate/;
autoindex on;
}

location / {
return 301 /ci;
}

#location / {
# #deny all;
# proxy_pass http://127.0.0.1:8080;
#}

location /ci {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_pass http://127.0.0.1:8080;
}
}

jenkins配置

安装Build Name and Description Setter插件,并Set Build Name的Build Name为:

1
#${BUILD_NUMBER}_${PLATFORM}_${BUILD_TYPE}_${ENV}_${GIT_BRANCH}

先安装Environment Injector Plugin插件,位置位于”Excute Shell”之后,配置Properties File Path为:

1
/tmp/${JOB_NAME}-${ENV}-${BUILD_NUMBER}.properties

Build->Execute shell:

1
2
3
4
5
6
if [[ "$GIT_BRANCH" == "" || "$BUILD_TYPE" == "" || "$PLATFORM" == "" || "$ENV" == "" ]]; then
echo "Parameters must not be empty!"
exit -1
else
bash ${JENKINS_HOME}/scripts/buildApp.sh
fi

参考脚本:

自动上传到app store请参考:https://testerhome.com/topics/10507

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
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
#!/bin/bash

######Only work for macos######

source /Users/jenkins/.zshrc

#BUILD_TYPE=$1
#PLATFORM=$2
#WORKSPACE=$3
#ENV=$4
#GIT_BRANCH=$5

#The signer tool for signing a apk ile
APKSIGNER=/Users/jenkins/Library/Android/sdk/build-tools/28.0.3/apksigner
ZIPALIGN=/Users/jenkins/Library/Android/sdk/build-tools/28.0.3/zipalign

#ios altool path, only for uploading ipa to app store
#ALTOOLPATH=/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool
ALTOOLPATH=/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework/Versions/A/Support/altool

#Script home
SCRIPTS_HOME=/Users/jenkins/.jenkins/scripts
#Base path for geneating files
SAVE_BASE_PATH=/Users/jenkins/works

JIAGU_JAVA=${SCRIPTS_HOME}/merchantjiagu/java/bin/java
JIAGU_JAR=${SCRIPTS_HOME}/merchantjiagu/jiagu.jar
BUNDLETOOL=${SCRIPTS_HOME}/bundletool-all-1.15.6.jar
#The qrcode tool for generating a qrcode from url
QRENCODE=/usr/local/bin/qrencode

#A key for uploading apk to google play
PROXY_HOST=scloud.aaa.com
PROXY_PORT=1082
APK_UPLOAD=${SCRIPTS_HOME}/apk_upload/bin/apk_upload
APKUP_KEY=${SCRIPTS_HOME}/xpaymerchantapp-dfec2cb36528.json
APKUP_APPID=111.222.merchant
# googleServicesJson=${SCRIPTS_HOME}/google-services.json

#The temporary variable between this script and email jelly file
TMP_PROPERTIES_FILE=/tmp/${JOB_NAME}-${ENV}-${BUILD_NUMBER}.properties
#App name
echo "APPNAME = ${APP_NAME}"
APP_NAME=merchantApp
K8S_FILE_NAME=xpay-merchant-app

#The environment variables of git folder
EVN_FOLDER=/tmp/xpay-merchant-app-config/k8s-${ENV}-config
#The base release name of git
RELEASE_NAME=${GIT_BRANCH//origin\//}
#RELEASE_NAME=${GIT_BRANCH//refs\/heads\//}
#The app host url
APP_HOST_URL=${JENKINS_URL//ci\//}
#The download base url
APP_BASE_URL=${JENKINS_URL}appDownloads
#the external base url, only for reinforcing apk
#EXTERNAL_BASE_URL=http://218.17.1.146:45682/ci/appDownloads
#The substring path
SUB_PATH=${JOB_NAME}/${ENV}/${RELEASE_NAME}
#The final app url
APP_URL=${APP_BASE_URL}/${SUB_PATH}/${BUILD_NUMBER}
#The history path
HISTORY_URL=${APP_BASE_URL}/${JOB_NAME}/${ENV}
#The final external url, only for reinforcing apk
#EXTERNAL_URL=${EXTERNAL_BASE_URL}/${SUB_PATH}/${BUILD_NUMBER}
#The path for geneated files, only for copying geneated files to antoher directory
APP_SAVE_PATH=${SAVE_BASE_PATH}/${SUB_PATH}/${BUILD_NUMBER}
#Developement plist
DEV_PLIST=${SCRIPTS_HOME}/developement.plist
#Release plist
RELEASE_PLIST=${SCRIPTS_HOME}/ExportOptions.plist
#the plist file which for itms-services
PLIST_TEMPLATE=${SCRIPTS_HOME}/mechantApp.template
#App Released history list
#For Android: ${SCRIPTS_HOME}/apphistory.android
#For IOS: ${SCRIPTS_HOME}/apphistory.ios
APP_HISTORY_LIST=${SCRIPTS_HOME}/mechantApphistory
#verification for building
signingConfigs=${SCRIPTS_HOME}/xpaySigningConfigs.properties
appId=$(cat ${signingConfigs} |grep appId|awk -F '=' '{print $2}')
appPassword=$(cat ${signingConfigs} |grep appPassword|awk -F '=' '{print $2}')
#apphostToken=$(cat ${signingConfigs} |grep apphostToken|awk -F '=' '{print $2}')
#secretId=$(cat ${signingConfigs} |grep secretId|awk -F '=' '{print $2}')
#secretKey=$(cat ${signingConfigs} |grep secretKey|awk -F '=' '{print $2}')
storePassword=$(cat ${signingConfigs} |grep storePassword|awk -F '=' '{print $2}')
keyAlias=$(cat ${signingConfigs} |grep keyAlias|awk -F '=' '{print $2}')
keyPassword=$(cat ${signingConfigs} |grep keyPassword|awk -F '=' '{print $2}')
storeFile=$(cat ${signingConfigs} |grep storeFile|awk -F '=' '{print $2}')
jiaguuser=$(cat ${signingConfigs} |grep jiaguuser|awk -F '=' '{print $2}')
jiagupwd=$(cat ${signingConfigs} |grep jiagupwd|awk -F '=' '{print $2}')

#Make sure APP_SAVE_PATH existed
mkdir -p $APP_SAVE_PATH
#passing variable to email jelly file
echo "appUrl=$APP_URL" >> $TMP_PROPERTIES_FILE
echo "historyUrl=$HISTORY_URL" >> $TMP_PROPERTIES_FILE
echo "appHostUrl=$APP_HOST_URL" >> $TMP_PROPERTIES_FILE

#Uploading app to APP_HOST which is a APP publish website
function uploadApp() {
platformParam=$1
filePath=$2
appJenkinsUrl=$3
iosIpaUrl=$4
universalApkPath=$5
universalAppJenkinsUrl=$6
#echo "Uploading app for $platformParam..."

echo "filePath=$filePath"
echo "appJenkinsUrl=$appJenkinsUrl"
#abb to apk: only for android
if [[ "$iosIpaUrl" == "" && "$APK_TYPE" == "aab" && "$AAB_TO_APK" == "Y" ]]; then
echo "universalApkPath=$universalApkPath"
echo "${platformParam}_universalUrl=$universalAppJenkinsUrl"
echo "${platformParam}_universalUrl=$universalAppJenkinsUrl" >> $TMP_PROPERTIES_FILE
${QRENCODE} -o $APP_SAVE_PATH/${platformParam}_qrcode.png -s 8 -m 1 "$universalAppJenkinsUrl"
else
${QRENCODE} -o $APP_SAVE_PATH/${platformParam}_qrcode.png -s 8 -m 1 "$appJenkinsUrl"
fi

qrcodeGetUrl="${APP_URL}/${platformParam}_qrcode.png"
echo "${platformParam}_downloadUrl=$qrcodeGetUrl" >> $TMP_PROPERTIES_FILE
#echo "$appJenkinsUrl" | grep "itms-services" > /dev/null
if [[ "$iosIpaUrl" != "" ]]; then
#ios
directUrl=$iosIpaUrl
else
#android
directUrl=$appJenkinsUrl
fi
echo "directUrl=$directUrl"
echo "${platformParam}_directUrl=$directUrl" >> $TMP_PROPERTIES_FILE
return 0
}

#Building android app
function buildAndroid() {
#for android
#Checking if the version existed
#android/gradle.properties
#appVersionCode=300
#appVersionName=5.0
android_history_list="${APP_HISTORY_LIST}.android"
echo "android_history_list=$android_history_list"
if [[ -f "${android_history_list}" && "$UPLOAD_GOOGLEPLAY" == "Y" ]]; then
currAppVersionCode=$(cat android/gradle.properties|grep "appVersionCode"|awk -F '=' '{print $2}')
currAppVersionName=$(cat android/gradle.properties|grep "appVersionName"|awk -F '=' '{print $2}')
historyAppVersionCode=$(cat ${android_history_list}|grep "appVersionCode"|awk -F '=' '{print $2}')
historyAppVersionName=$(cat ${android_history_list}|grep "appVersionName"|awk -F '=' '{print $2}')
echo "currAppVersionCode=$currAppVersionCode"
echo "currAppVersionName=$currAppVersionName"
echo "historyAppVersionCode=$historyAppVersionCode"
echo "historyAppVersionName=$historyAppVersionName"
#if [ `echo "$currAppVersionCode <= $historyAppVersionCode" | bc` -eq 1 -a `echo "$currAppVersionName <= $historyAppVersionName" | bc` -eq 1 ]; then
if [[ `echo "$currAppVersionCode <= $historyAppVersionCode" | bc` == 1 || `echo "$currAppVersionName <= $historyAppVersionName" | bc` == 1 ]]; then
echo "Android: The current version you build is less than or equal to the version of histroy, please increase the number of version."
exit -1
fi
fi

BUILD_PLATFORM="android"
rm -fr $APP_SAVE_PATH/Android.bundle.zip $APP_SAVE_PATH/*.aab $APP_SAVE_PATH/android_qrcode.png
cd ${WORKSPACE}
# sed -i "" "s;^ *export const ENV *= *'.*';export const ENV = '${ENV}';g" ${WORKSPACE}/component/Common/Environment.js
# if [[ "$ENV" == "prod" ]]; then
# /bin/cp -a $googleServicesJson android/app/
# fi

echo "Building android: nvm use 16.15.1 npm install --legacy-peer-deps"
nvm use 16.15.1
npm install --legacy-peer-deps > /dev/null
echo "Building android: npm run build-android"
npm run build-android > /dev/null
buildResult=$?
cd android
if [[ "$ONLY_HOTUPDATE" == "N" ]]; then
buildLog=$APP_SAVE_PATH/build-android.log
if [[ "$APK_TYPE" == "apk" ]]; then
echo "Building android: ./gradlew clean assemble$BUILD_TYPE"
output=app/build/outputs/apk/release/
rm -fr $output/*.apk
echo "./gradlew clean assemble$BUILD_TYPE --stacktrace -PIS_JENKINS=true -PBUILD_TYPE=${BUILD_TYPE} > /dev/null 2> $buildLog"
./gradlew clean assemble$BUILD_TYPE --stacktrace -PIS_JENKINS=true -PBUILD_TYPE=${BUILD_TYPE} > /dev/null 2> $buildLog
else
##aab
echo "Building android: ./gradlew clean bundle"
output=app/build/outputs/bundle/release/
rm -fr $output/*.aab
echo "./gradlew clean bundle --stacktrace -PIS_JENKINS=true -PBUILD_TYPE=${BUILD_TYPE} > /dev/null 2> $buildLog"
./gradlew clean bundle --stacktrace -PIS_JENKINS=true -PBUILD_TYPE=${BUILD_TYPE} > /dev/null 2> $buildLog
fi
buildResult=$?

fi

if [[ $buildResult == 0 ]]; then
# hot update package
currPwd=`pwd`
cd ${WORKSPACE}/android/app/src/main/assets
zip -rq ${APP_SAVE_PATH}/Android.bundle.zip *
cd $currPwd
apkFile=`ls $output|grep ${APK_TYPE}`
# APK only exist when non-hotfix
if [[ $? == 0 && -f $output/$apkFile ]]; then
filePath=$output/$apkFile
universalApkFile=universal.apk
singedApkFile=${APP_NAME}-${RELEASE_NAME}.${APK_TYPE}
#singedApkPath=$APP_SAVE_PATH/${apkFile}
singedApkPath=$APP_SAVE_PATH/${singedApkFile}
appJenkinsUrl="${APP_URL}/$singedApkFile"
universalApkPath=$APP_SAVE_PATH/${universalApkFile}
universalAppJenkinsUrl="${APP_URL}/$universalApkFile"


#abb to apk
if [[ "$APK_TYPE" == "aab" && "$AAB_TO_APK" == "Y" ]]; then
apksName=${APP_NAME}-${RELEASE_NAME}.apks
java -jar $BUNDLETOOL build-apks \
--mode=universal \
--bundle=$filePath \
--output=$APP_SAVE_PATH/$apksName \
--ks=$storeFile \
--ks-pass=pass:$storePassword \
--ks-key-alias=$keyAlias \
--key-pass=pass:$keyPassword

java -jar $BUNDLETOOL extract-apks \
--device-spec=/Users/jenkins/.jenkins/scripts/device-spec.json \
--apks=$APP_SAVE_PATH/$apksName \
--output-dir=$APP_SAVE_PATH/
fi


if [[ "$SKIP_REINFORCE" == "N" ]]; then
echo "Reinforcing the ${APK_TYPE}..."
proxy_off
#login
${JIAGU_JAVA} -jar ${JIAGU_JAR} -login ${jiaguuser} ${jiagupwd}
echo "${JIAGU_JAVA} -jar ${JIAGU_JAR} -jiagu ${APK_TYPE} ${filePath} ${APP_SAVE_PATH}/ -auto-sign"
${JIAGU_JAVA} -jar ${JIAGU_JAR} -jiagu ${APK_TYPE} ${filePath} ${APP_SAVE_PATH}/ -auto-sign
proxy_on
if [[ $? == 0 ]]; then
echo "Reinforcing the ${APK_TYPE} successfully..."
jiaguApk=`ls ${APP_SAVE_PATH} | grep jiagu_sign` > /dev/null
if [[ "$jiaguApk" != "" ]]; then
mv ${APP_SAVE_PATH}/${jiaguApk} $singedApkPath
else
echo "Not found the reinfored ${APK_TYPE}."
exit -1
fi
else
echo "Reinforcing the apk failed..."
exit -1
fi
else
cp -a $filePath $singedApkPath
fi

if [[ "$UPLOAD_GOOGLEPLAY" == "Y" ]]; then
echo "Uploading file to google play, it may make a few minutes, please wait..."
#https://github.com/eventOneHQ/apkup/blob/master/src/cli/upload.ts
#Track can be 'internal', 'alpha', 'beta', 'production' or 'rollout'. Default: 'internal'
# nvm use v10.16.0
# #npm i -g apkup
# apkup --key "${APKUP_KEY}" --apk "${singedApkPath}" \
# --release-notes "en-US=Bug fixes and minor enhancements" \
# --release-notes "zh-HK=錯誤修正及少量更新" \
# --track "${TRACK}"
# nvm use v16.15.1
#https://github.com/stasheq/google-play-apk-upload
bash ${APK_UPLOAD} ${APKUP_APPID} "${singedApkPath}" ${APKUP_KEY} ${PROXY_HOST} ${PROXY_PORT}
if [[ $? != 0 ]]; then
echo "Uploading apk to google play failed!"
exit -1
fi
echo "Uploading apk to google play successfully!"
#Recorded the last version in the history when app was uploaded to google play successfully.
echo "appVersionName=${currAppVersionName}" > ${android_history_list}
echo "appVersionCode=${currAppVersionCode}" >> ${android_history_list}
fi

uploadApp $BUILD_PLATFORM $singedApkPath $appJenkinsUrl "" $universalApkPath $universalAppJenkinsUrl
if [[ $? != 0 ]]; then
echo "Building android is successful, but upload failed, maybe caused by establishing network, it exited, please try again."
exit -1
fi
fi
else
cat $buildLog
echo "Building android is failed. it exited."
exit -1
fi
}

#Building ios app
function buildIos() {
# for ios
#Checking if the version existed
#/* Debug */
#/* Release */
#CURRENT_PROJECT_VERSION = 1;
#MARKETING_VERSION = 4.9;
ios_history_list="${APP_HISTORY_LIST}.ios"
echo "ios_history_list=$ios_history_list"
if [[ -f "${ios_history_list}" && "$UPLOAD_APPSTORE" == "Y" ]]; then
currMarketingVersion=`cat ios/${APP_NAME}.xcodeproj/project.pbxproj|grep "MARKETING_VERSION"|sed -n '2p'|sed 's;\;$;;'|awk -F ' = ' '{print $2}'`
#historyProjectVersion=`cat ${ios_history_list}|grep "CURRENT_PROJECT_VERSION"|awk -F ' = ' '{print $2}'`
historyMarketingVersion=`cat ${ios_history_list}|grep "MARKETING_VERSION"|awk -F ' = ' '{print $2}'`
#echo "currProjectVersion=$currProjectVersion"
echo "currMarketingVersion=$currMarketingVersion"
#echo "historyProjectVersion=$historyProjectVersion"
echo "historyMarketingVersion=$historyMarketingVersion"
if [[ `echo "$currMarketingVersion <= $historyMarketingVersion" | bc` == 1 ]]; then
echo "IOS: The current version you build is less than or equal to the version of histroy, please increase the number of version."
exit -1
fi
fi

BUILD_PLATFORM="ios"
rm -fr $APP_SAVE_PATH/IOS.bundle.zip $APP_SAVE_PATH/*.ipa $APP_SAVE_PATH/*.plist $APP_SAVE_PATH/ios_qrcode.png
cd ${WORKSPACE}
#sed -i "" "s;^ *export const ENV *= *'.*';export const ENV = '${ENV}';g" ${WORKSPACE}/component/Common/Environment.js
echo "Building ios: nvm use 16.15.1 npm install --legacy-peer-deps"
nvm use 16.15.1
npm install --legacy-peer-deps > /dev/null
echo "Building ios: npm run build-ios"
npm run build-ios > /dev/null
cd ios

output=build/outputs/
rm -fr $output/*.ipa
xcarchiveBackUpFolder=$output/xcarchive-`date +%Y%m%d%H%M%S`
mkdir $xcarchiveBackUpFolder
mv $output/*.xcarchive $xcarchiveBackUpFolder/

if [[ "$ONLY_HOTUPDATE" == "N" ]]; then

proxy_on

echo "Building ios: pod install"
/usr/local/bin/pod install

proxy_off

echo "Building ios: xcodebuild clean"
echo "xcodebuild \
-workspace \"${APP_NAME}.xcworkspace\" \
-scheme \"${APP_NAME}\" \
-configuration \"${BUILD_TYPE}\" \
clean > /dev/null"
xcodebuild \
-workspace "${APP_NAME}.xcworkspace" \
-scheme "${APP_NAME}" \
-configuration "${BUILD_TYPE}" \
clean > /dev/null

echo "Building ios: xcodebuild archive"
echo "xcodebuild archive -workspace \"${APP_NAME}.xcworkspace\" \
-scheme ${APP_NAME} \
-configuration \"${BUILD_TYPE}\" \
-archivePath \"${output}/${APP_NAME}-${BUILD_TYPE}.xcarchive\" > /dev/null"
security unlock-keychain -p 'xxxxxx'
xcodebuild archive -workspace "${APP_NAME}.xcworkspace" \
-scheme ${APP_NAME} \
-configuration "${BUILD_TYPE}" \
-archivePath "${output}/${APP_NAME}-${BUILD_TYPE}.xcarchive" > /dev/null

if [[ $? != 0 ]]; then
echo "Archive failed!"
exit -1
fi

echo "Building ios: xcodebuild export archive to ipa"
if [[ "$ENV" == "prod" ]]; then
echo "xcodebuild -exportArchive -archivePath \"${output}/${APP_NAME}-${BUILD_TYPE}.xcarchive\" \
-exportPath \"${output}/${APP_NAME}-${BUILD_TYPE}.ipa\" \
-exportOptionsPlist $RELEASE_PLIST > /dev/null"
xcodebuild -exportArchive -archivePath "${output}/${APP_NAME}-${BUILD_TYPE}.xcarchive" \
-exportPath "${output}/${APP_NAME}-${BUILD_TYPE}.ipa" \
-exportOptionsPlist $RELEASE_PLIST \
-allowProvisioningUpdates YES > /dev/null

if [[ $? != 0 ]]; then
echo "Exporting archive to ipa failed!"
exit -1
fi

if [[ "$UPLOAD_APPSTORE" == "Y" ]]; then
IPAPATH=${output}/${APP_NAME}-${BUILD_TYPE}.ipa/${APP_NAME}.ipa
echo "Uploading file to app store, it may make a few minutes, please wait..."
echo "\"${ALTOOLPATH}\" --upload-app -f \"${IPAPATH}\" -u \"${appId}\" -p \"******\" --output-format xml"
uploadResult=`"${ALTOOLPATH}" --upload-app -f "${IPAPATH}" -u "${appId}" -p "${appPassword}" -t ios --output-format xml`
echo "uploadResult=$uploadResult"
#"${ALTOOLPATH}" --upload-app -f "${IPAPATH}" -u "${appId}" -p "${appPassword}" --output-format xml | grep "No errors uploading"
echo "$uploadResult" | grep "No errors uploading" > /dev/null
if [[ $? != 0 ]]; then
echo "Building ios successfully, but uploading to app store failed!"
exit -1
else
echo "Uploading file to app store successfully!"
#Recorded the last version in the history when app was uploaded to google play successfully.
#echo "CURRENT_PROJECT_VERSION = ${currAppVersionName}" > ${ios_history_list}
echo "MARKETING_VERSION = ${currMarketingVersion}" > ${ios_history_list}
fi
fi
else
xcodebuild -exportArchive -archivePath "${output}/${APP_NAME}-${BUILD_TYPE}.xcarchive" \
-exportPath "${output}/${APP_NAME}-${BUILD_TYPE}.ipa" \
-exportOptionsPlist $DEV_PLIST \
-allowProvisioningUpdates YES > /dev/null
fi
fi
if [[ $? == 0 ]]; then
currPwd=`pwd`
cd ${WORKSPACE}/ios/bundle
zip -rq ${APP_SAVE_PATH}/IOS.bundle.zip *
cd $currPwd
ipaFile=`ls $output|grep ipa`
# IPA only exist when non-hotfix
if [[ $? == 0 && -d $output/$ipaFile ]]; then
filePath=$output/$ipaFile/${APP_NAME}.ipa
ipaFile=${APP_NAME}-${RELEASE_NAME}.ipa
cp -a $filePath $APP_SAVE_PATH/${ipaFile}
iosIpaUrl=${APP_URL}/${ipaFile}
pngUrl=${APP_BASE_URL}/xpay-merchant-app.png
md5Size=`ls -l $filePath | awk '{print $5}'`
cat $PLIST_TEMPLATE | sed "s;#{downloadFile};${iosIpaUrl};g" | sed "s;#{md5Size};${md5Size};g"| sed "s;#{pngFile};${pngUrl};g" | sed "s;#{releaseName};$RELEASE_NAME;g" > $APP_SAVE_PATH/${APP_NAME}.plist
appJenkinsUrl="itms-services://?action=download-manifest&url=${APP_URL}/${APP_NAME}.plist"
uploadApp $BUILD_PLATFORM $filePath $appJenkinsUrl $iosIpaUrl
if [[ $? != 0 ]]; then
echo "Building ios is successful, but upload failed, maybe caused by establishing network, it exited, please try again."
exit -1
fi
fi
else
echo "Building ios is failed, it exited."
exit -1
fi
}

function proxy_off() {
unset http_proxy
unset https_proxy
echo -e "The proxy has been closed!"
}
function proxy_on() {
export no_proxy="127.0.0.1,localhost,*.abc.net,192.168.100.88,10.0.0.0/8,192.168.0.0/16,172.16.0.0/12"
export http_proxy="http://${PROXY_HOST}:${PROXY_PORT}"
export https_proxy=$http_proxy
echo -e "The proxy has been opened!"
}

#Enabled proxy
# proxy_on

#Init the project
cd ${WORKSPACE}/init
./update.sh

#SSL Pinning
cd ${WORKSPACE}
if [[ -f pinset.json ]]; then
echo "npx pinset gen -f"
npx pinset gen -f
if [[ $? != 0 ]]; then
echo "npx pinset gen failure!"
exit -1
fi
fi

#Replacing Environment variables
if [[ -d ${EVN_FOLDER} ]]; then
echo "Destination path '${EVN_FOLDER}' already exists, delete first..."
rm -fr ${EVN_FOLDER}
fi
git clone http://gitlab.xxx.net/x-pay/k8s-${ENV}-config/ ${EVN_FOLDER}

if [[ ! -d ${EVN_FOLDER}/${K8S_FILE_NAME} ]]; then
echo "Replacing Environment variables failed: Destination path '${EVN_FOLDER}/${K8S_FILE_NAME}' doesn't exist."
exit -1
fi

#Starting build
cd ${WORKSPACE}
# sed -i "" "s;^ *export const ENV *= *'.*';export const ENV = '${ENV}';g" ${WORKSPACE}/component/Common/Environment.js
/bin/cp -a ${EVN_FOLDER}/${K8S_FILE_NAME}/Constants.js ${WORKSPACE}/src/
if [[ "$PLATFORM" == "android" ]]; then
/bin/cp -a ${EVN_FOLDER}/${K8S_FILE_NAME}/google-services.json ${WORKSPACE}/android/app/
buildAndroid
elif [[ "$PLATFORM" == "ios" ]]; then
# /bin/cp -a ${EVN_FOLDER}/${K8S_FILE_NAME}/GoogleService-Info.plist ${WORKSPACE}/ios/${APP_NAME}/
buildIos
elif [[ "$PLATFORM" == "both" ]]; then
/bin/cp -a ${EVN_FOLDER}/${K8S_FILE_NAME}/google-services.json ${WORKSPACE}/android/app/
buildAndroid

# /bin/cp -a ${EVN_FOLDER}/${K8S_FILE_NAME}/GoogleService-Info.plist ${WORKSPACE}/ios/${APP_NAME}/
buildIos
fi

if [[ "$TAG_DESC" == "" ]]; then
TAG_DESC="For prod version ${newTag} based on $releaseBranch via jenkins"
fi

#Disabled proxy
proxy_off
#Tagging for the prod git release version
if [[ "$ENV" == "prod" ]]; then
echo "Tagging the release version for prod..."
releaseBranch=${GIT_BRANCH//origin\//}
#releaseBranch=${GIT_BRANCH//refs\/heads\//}
newTag=${releaseBranch}-`date +%Y%m%d%H%M`
git tag -a $newTag -m "${TAG_DESC}"
echo "Pushing the release version to the origin..."
git push origin ${newTag}
fi

自动清理过期文件:

vim cleanHistoryFiles.sh

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

days=90
#Cleaning the files before days of the works directory
find /Users/jenkins/works/xpayapp-* -type f -mtime +${days} -exec rm -rf {} \;
find /Users/jenkins/works/xwallet-* -type f -mtime +${days} -exec rm -rf {} \;
find /Users/jenkins/works/xpaymerchant-* -type f -mtime +${days} -exec rm -rf {} \;
#cleaning the files before days of the app_host directory
#find /opt/app-host/shared/public/uploads/pkg -type f -mtime +${days} -exec rm -rf {} \;
echo "Cleaning files is done!

参考