iOS脚本打包API2.0蒲公英上传同步钉钉消息群

311 阅读2分钟
#!/bin/bash
# 通过shell脚本来实现将本地app文件通过APIV2上传到蒲公英
# https://www.pgyer.com/doc/view/api#fastUploadApp
# step1: 将该脚本放在工程的根目录下(在.xcodeproj或者.xcworkspace文件同级目录)
# step2: 根据情况修改下面的参数
# step3: 打开终端,执行脚本,直接把脚本拖进终端,按下enter键即可


# ---------------------------------------------------------------
# functions
# ---------------------------------------------------------------
logBase() {
    echo -e "\033[36m $* \033[0m"
}

logFail() {
    echo -e "\033[31m $* \033[0m"
}

logTitle() {
    echo -e "\033[37m ============== $* ============== \033[0m"
}

execCommand() {
    echo "$@"
    result=$(eval $@)
}


# ---------------------------------------------------------------
# read configs
# ---------------------------------------------------------------
logBase "更新描述内容:"
read -e update_desc
logBase "请选择打包方式 ? [ 1:ad-hoc 2:development ]"
read number
logBase "请选择发送钉钉群 ? [ 1:研发钉群 2:产品钉群 3:钉群同步发]"
read dingNum


# ---------------------------------------------------------------
# shell configs
# ---------------------------------------------------------------
# 配置蒲公英
buildType="ipa"
pgyerURL="https://www.pgyer.com"
api_key="蒲公英ApiKey"
# 工程名称(必填)
workspace_name="WorkspaceName"
# 指定项目的scheme名称,必填
scheme_name="${workspace_name}"
# 指定要打包编译的方式 : Release、Debug。必填
build_configuration="Release"
# method,打包的方式。方式分别为 ad-hoc, development 。必填
method="ad-hoc"
# 项目的bundleID,手动管理Profile时必填
bundle_identifier="Bundle Identifier"
# 项目的bundleID,手动管理Profile时必填(以下我只用到NotificationService,额外另加)
bundle_identifier_Notification="Bundle Identifier Notification"
# 下面两个参数只是在手动指定Pofile文件的时候用到,如果使用Xcode自动管理Profile,直接留空就好
#(跟method对应的)mobileprovision文件名,需要先双击安装.mobileprovision文件.手动管理Profile时必填
mobileprovision_name="MobileprovisionNameAdhoc"
mobileprovision_name_Notification="NotificationMobileprovisionNameAdhoc"
# 指定输出导出文件夹路径
export_path="导出文件夹路径"
# 指定导出ipa包需要用到的plist配置文件的路径
export_options_plist_path="$export_path/ExportOptions.plist"
# 指定输出归档文件路径
export_archive_path="$export_path/$scheme_name.xcarchive"
# 工程根目录
project_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

if [ $number == 2 ]; then
build_configuration="Debug"
method="development"
mobileprovision_name="MobileprovisionNameDev"
mobileprovision_name_Notification="NotificationMobileprovisionNameDev"
else
build_configuration="Release"
method="ad-hoc"
mobileprovision_name="MobileprovisionNameAdhoc"
mobileprovision_name_Notification="NotificationMobileprovisionNameAdhoc"
fi

logBase "scheme_name = ${scheme_name}"
logBase "method = ${method}"
logBase "build_configuration = ${build_configuration}"
logBase "bundle_identifier = ${bundle_identifier}"
logBase "mobileprovision_name = ${mobileprovision_name}"
logBase "mobileprovision_name_Notification = ${mobileprovision_name_Notification}"
logBase "project_dir = ${project_dir}"
logBase "export_path = ${export_path}"
logBase "export_archive_path = ${export_archive_path}"
logBase "export_options_plist_path = ${export_options_plist_path}"


# ---------------------------------------------------------------
# 项目构建
# ---------------------------------------------------------------
logTitle "项目构建"
# 进入项目工程目录
cd ${project_dir}
# 指定输出文件目录不存在则创建
if [ -d "$export_path" ]; then
  rm -rf "$export_path"
fi
# 编译前清理工程
xcodebuild clean -workspace ${workspace_name}.xcworkspace -scheme ${scheme_name} -configuration ${build_configuration}
# 清理工程后构建
xcodebuild archive -workspace ${workspace_name}.xcworkspace -scheme ${scheme_name} -configuration ${build_configuration} -archivePath ${export_archive_path}
#检查是否构建成功
#xcarchive 实际是一个文件夹不是一个文件所以使用 -d 判断
if [ -d "$export_archive_path" ]; then
 logBase "项目构建成功 🚀 🚀 🚀"
else
 logFail "项目构建失败 😢 😢 😢"
 exit 1
fi


# ---------------------------------------------------------------
# ExportOptions配置
# ---------------------------------------------------------------
logTitle "ExportOptions配置"
# 先删除ExportOptions.plist文件
if [ -f ${export_options_plist_path} ]; then
 logBase "${export_options_plist_path}文件存在,进行删除"
 rm -f ${export_options_plist_path}
fi

#根据参数生成export_options_plist文件,就是添加了一个字典,字典名称是provisioningProfiles,对应内容key=${bundle_identifier},value=${mobileprovision_name}
/usr/libexec/PlistBuddy -c "Add :provisioningProfiles:${bundle_identifier} String ${mobileprovision_name}" $export_options_plist_path
/usr/libexec/PlistBuddy -c "Add :provisioningProfiles:${bundle_identifier_Notification} String ${mobileprovision_name_Notification}"  $export_options_plist_path
/usr/libexec/PlistBuddy -c "Add :signingStyle String manual"  $export_options_plist_path
/usr/libexec/PlistBuddy -c "Add :method string ${method}" $export_options_plist_path
#如果您的工程是开启Bitcode的话,请把false改为true
/usr/libexec/PlistBuddy -c "Add :compileBitcode bool false" $export_options_plist_path


# ---------------------------------------------------------------
# 导出ipa文件
# ---------------------------------------------------------------
logTitle "导出ipa文件"
xcodebuild -exportArchive -archivePath ${export_archive_path} -exportPath ${export_path} -exportOptionsPlist ${export_options_plist_path} -allowProvisioningUpdates
# 检查文件是否存在(DisplayName换成项目对应名称)
file="${export_path}/DisplayName.ipa"
if [ -f "$file" ]; then
 logBase "导出 ${file} 包成功 🎉 🎉 🎉 "
 open $export_path
else
 logFail "导出 ${file} 包失败 😢 😢 😢"
 exit 1
fi

# 删除export_options_plist文件(中间文件)
if [ -f "$export_options_plist_path" ]; then
 logBase "${export_options_plist_path}文件存在,准备删除"
 rm -f $export_options_plist_path
fi

# 输出打包总用时
logBase "打包总用时: ${SECONDS}s"


# ---------------------------------------------------------------
# 获取上传凭证
# ---------------------------------------------------------------
logTitle "获取凭证"

command="curl -s"
[ -n "$api_key" ]                && command="${command} --form-string '_api_key=${api_key}'";
[ -n "$buildType" ]              && command="${command} --form-string 'buildType=${buildType}'";
command="${command} http://www.pgyer.com/apiv2/app/getCOSToken";
execCommand $command

[[ "${result}" =~ \"endpoint\":\"([\:\_\.\/\\A-Za-z0-9\-]+)\" ]] && endpoint=`echo ${BASH_REMATCH[1]} | sed 's!\\\/!/!g'`
[[ "${result}" =~ \"key\":\"([\.a-z0-9]+)\" ]] && key=`echo ${BASH_REMATCH[1]}`
[[ "${result}" =~ \"signature\":\"([\=\&\_\;A-Za-z0-9\-]+)\" ]] && signature=`echo ${BASH_REMATCH[1]}`
[[ "${result}" =~ \"x-cos-security-token\":\"([\_A-Za-z0-9\-]+)\" ]] && x_cos_security_token=`echo ${BASH_REMATCH[1]}`

if [ -z "$key" ] || [ -z "$signature" ] || [ -z "$x_cos_security_token" ] || [ -z "$endpoint" ]; then
    logFail "获取凭证 😢 😢 😢"
    exit 1
fi


# ---------------------------------------------------------------
# 上传文件
# ---------------------------------------------------------------
logTitle "上传文件"
file_name=${file##*/}
execCommand "curl -s -o /dev/null -w '%{http_code}' \
--form-string 'key=${key}' \
--form-string 'signature=${signature}' \
--form-string 'x-cos-security-token=${x_cos_security_token}' \
--form-string 'x-cos-meta-file-name=${file_name}' \
-F 'file=@${file}' ${endpoint}"
if [ $result -ne 204 ]; then # if http code != 204, upload failed
    logFail "上传蒲公英失败 😢 😢 😢"
    exit 1
fi


# ---------------------------------------------------------------
# 检查结果
# ---------------------------------------------------------------
logTitle "检查结果"
for i in {1..60}; do
    execCommand "curl -s http://www.pgyer.com/apiv2/app/buildInfo?_api_key=${api_key}\&buildKey=${key}"
    [[ "${result}" =~ \"code\":([0-9]+) ]] && code=`echo ${BASH_REMATCH[1]}`
    if [ $code -eq 0 ]; then
        logBase $result
        break
    else
        sleep 1
    fi
done

appVersion=$(echo ${result} | jq -r '.data.buildVersion')
appQRCodeURL=$(echo ${result} | jq -r '.data.buildQRCodeURL')
appShortcutUrl=$(echo ${result} | jq -r '.data.buildShortcutUrl')
appBuildVersion=$(echo ${result} | jq -r '.data.buildBuildVersion')
if [ ! -n "$appQRCodeURL" ]; then
    logFail "检查结果失败 😢 😢 😢"
    exit 1
fi


# ---------------------------------------------------------------
# 发通知到钉钉群
# ---------------------------------------------------------------
logTitle "发通知到钉钉群"
singleURL="$pgyerURL/$appShortcutUrl"
#通知到钉钉群  `title`需含关键词(钉钉机器人关键词规则)
talkReq() {
    curl $* \
     -H 'Content-Type: application/json' \
     -d '
     {
        "msgtype": "actionCard",
        "actionCard": {
            "title":"title",
            "text":"![screenshot]('"${appQRCodeURL}"') \n\n ### '"${update_desc}"' \n\n 环境:'"${build_configuration}"' 版本:'"${appVersion}"'('"${appBuildVersion}"')", 
            "btnOrientation": "0", 
            "singleTitle" : "Go Go Go",
            "singleURL" : "'"${singleURL}"'"
        }
    }'
}

if [ $dingNum == 1 ];then
   talkReq '研发钉群机器人webhokurl'
elif [ $dingNum == 2 ]; then
   talkReq '产品钉群机器人webhokurl'
else
   talkReq '研发钉群机器人webhokurl'
   talkReq '产品钉群机器人webhokurl'
fi

logBase "\n#### '"${update_desc}"' \n> 环境:'"${build_configuration}"' 版本:'"${appVersion}"'('"${appBuildVersion}"') \n> 短链接:'"${singleURL}"' \n"