适合iOS工程是Unity为主导,native代码是作为插件形式接入。
本文脚本是从Unity生成xcode工程之后开始执行,不一定完全适用,请按照自己需求进行修改。
注意修改脚本中“xxxxxx”的地方。
一.安装xcodeproj
#安装ruby xcodeproj库
$gem install xcodeproj
#如果提示没有权限运行下面这条命令:
$sudo gem install xcodeproj
二、配置xcodeproj工程
#执行脚本示例:
ruby '配置脚本文件路径' 'Unity生成的xcode工程根目录'
#或者增加参数可自动打开工程:
ruby '配置脚本文件路径' 'Unity生成的xcode工程根目录' 1
require "fileutils"
require 'xcodeproj'
xcodeproj_path_directory = ARGV[0]
@config_asset_directory = File.dirname(__FILE__) + "/"
FileUtils.cd(xcodeproj_path_directory) do
is_auto_open_xcodeproj = ARGV[1]
#工程中target名称
TARGET_NAME = "xxxxxx"
#打开项目工程.xcodeproj
project_path = "#{TARGET_NAME}.xcodeproj"
project = Xcodeproj::Project.open(project_path)
#找到需要操作的target
targetIndex = 0
project.targets.each_with_index do |target,index|
if target.name == TARGET_NAME
targetIndex = index
end
end
target = project.targets[targetIndex]
#删除目录
def delete_directory(dirPath)
if File.directory?(dirPath)
Dir.foreach(dirPath) do |subFile|
if subFile != '.' and subFile != '..'
delete_directory(dirPath + "/" + subFile);
end
end
Dir.rmdir(dirPath);
# puts "删除目录:#{dirPath}"
else
# puts "删除文件:#{dirPath}"
File.delete(dirPath);
end
end
#拷贝文件
def copy(from, to)
File.open(from) do |input|
File.open(to, "w") do |output|
output.write(input.read)
end
end
end
#拷贝目录
def copy_directory(from_path, to_path)
if File.directory?(from_path)
if File::exist?(to_path) == false
Dir::mkdir(to_path)
puts "\033[40m\033[37m创建文件夹: #{to_path}\033[0m\n"
end
Dir.foreach(from_path) do |sub_from_file|
if sub_from_file != '.' && sub_from_file != '..' && sub_from_file != ".DS_Store"
need_copy_file = from_path + "/" + sub_from_file
need_create_file = to_path + "/" + sub_from_file
# puts "递归遍历文件夹:#{need_copy_file}; #{need_create_file}"
copy_directory(need_copy_file, need_create_file)
end
end
else
if File::exist?(to_path)
puts "\033[33m文件已存在,删除:#{to_path}\033[0m\n"
File.delete(to_path)
end
puts "\033[40m\033[37m创建文件:#{to_path}\033[0m\n"
copy(from_path, to_path)
end
end
#判断引用是否存在
def exist_file_reference?(build_phase, file_name)
if file_name != "." && file_name != ".." && file_name != " " && file_name != ".DS_Store" then
build_phase.files.each do |file|
return true if file.file_ref.name == file_name
end
end
false
end
#添加resource引用
def add_resource_file_reference(project, group, file_name)
project.targets.each do |target|
next unless TARGET_NAME == target.name
build_phase = target.resources_build_phase
next if exist_file_reference?(build_phase, file_name)
file_ref = group.new_reference(file_name)
build_phase.add_file_reference(file_ref, false)
puts "添加 #{file_name} reference\n"
project.save
end
end
#添加bundle文件并添加引用
def add_asset_file(project, target, file_names)
project.targets.each do |target|
next unless TARGET_NAME == target.name
file_names.each do |file_name|
old_file_full_path = @config_asset_directory + file_name
new_file_full_path = "./" + file_name
# if File::exist?(new_file_full_path)
# puts "\033[32m#{file_name}已经添加过! #{new_file_full_path}\n\033[0m\n"
# else
if File::exist?(old_file_full_path)
#拷贝旧文件至新文件位置
FileUtils.cp_r(old_file_full_path, new_file_full_path)
#添加文件引用
if File::exist?(new_file_full_path)
add_resource_file_reference(project, project.main_group, new_file_full_path)
puts "\033[32m添加#{file_name}配置完成! #{new_file_full_path}\n\033[0m\n"
else
puts "\033[41mERROR:#{file_name}拷贝失败!!!#{old_file_full_path}\n"
exit
end
else
puts "\033[41mERROR:#{file_name}文件不存在!!!#{old_file_full_path}\n"
exit
end
# end
end
end
end
#add system framework
def add_system_frameworks(project, names, optional = false)
project.targets.each do |target|
next unless TARGET_NAME == target.name
build_phase = target.frameworks_build_phase
framework_group = project.frameworks_group
names.each do |name|
next if exist_file_reference?(build_phase, "#{name}.framework")
path = "System/Library/Frameworks/#{name}.framework"
file_ref = framework_group.new_reference(path)
file_ref.name = "#{name}.framework"
file_ref.source_tree = 'SDKROOT'
build_file = build_phase.add_file_reference(file_ref)
if optional
build_file.settings = { 'ATTRIBUTES' => ['Weak'] }
end
puts "添加 #{path} reference\n"
end
puts "\033[32mSystem framework reference添加完成\n\033[0m\n"
end
end
#add system tbd
def add_system_tbds(project, names, optional = false)
project.targets.each do |target|
next unless TARGET_NAME == target.name
build_phase = target.frameworks_build_phase
framework_group = project.frameworks_group
names.each do |name|
next if exist_file_reference?(build_phase, "#{name}.tbd")
path = "usr/lib/#{name}.tbd"
file_ref = framework_group.new_reference(path)
file_ref.name = "#{name}.tbd"
file_ref.source_tree = 'SDKROOT'
build_file = build_phase.add_file_reference(file_ref)
if optional
build_file.settings = { 'ATTRIBUTES' => ['Weak'] }
end
puts "添加 #{path} reference\n"
end
puts "\033[32mSystem tbd 引用添加完成\n\033[0m\n"
end
end
#添加bundle文件配置
def add_bundle_files(project, target)
file_names = ["xxxxxx.entitlements", "LaunchScreen-iPad.png", "LaunchScreen-iPad.storyboard", "LaunchScreen-iPhone.storyboard", "LaunchScreen-iPhoneLandscape.png", "LaunchScreen-iPhonePortrait.png"]
add_asset_file(project, target, file_names)
end
#替换UnityAppController.h、UnityAppController.mm
def replace_unity_app_controller(project, target)
project.targets.each do |target|
next unless TARGET_NAME == target.name
file_names = ["UnityAppController.h", "UnityAppController.mm"]
target_direcory_path = "./Classes/"
file_names.each do |file_name|
old_file_full_path = @config_asset_directory + file_name
new_file_full_path = target_direcory_path + file_name
#拷贝旧文件至新文件位置
FileUtils.cp_r(old_file_full_path, new_file_full_path)
end
puts "\033[32m替换UnityAppController.h、UnityAppController.mm完成\n\033[0m\n"
end
end
#替换Unity生成的启动资源
def replace_unity_launch_screen_resouce(project, target)
project.targets.each do |target|
next unless TARGET_NAME == target.name
file_names = ["LaunchScreen-iPad.png", "LaunchScreen-iPad.storyboard", "LaunchScreen-iPhone.storyboard", "LaunchScreen-iPhoneLandscape.png", "LaunchScreen-iPhonePortrait.png"]
file_names.each do |file_name|
old_file_full_path = @config_asset_directory + file_name
new_file_full_path = "./" + file_name
#拷贝旧文件至新文件位置
FileUtils.cp_r(old_file_full_path, new_file_full_path)
end
puts "\033[32m替换Unity生成的启动资源完成\n\033[0m\n"
end
end
#替换Images.xcassets文件夹
def replace_assets_file(project, target)
old_file_full_path = @config_asset_directory + "Images.xcassets"
new_file_full_path = "./#{TARGET_NAME}/Images.xcassets"
if File::exist?(new_file_full_path)
puts "删除旧资源文件夹:#{new_file_full_path}"
delete_directory(new_file_full_path);
else
puts "\033[41mERROR:#{new_file_full_path}不存在!!!\n"
exit
end
puts "创建新资源文件夹:#{new_file_full_path}"
FileUtils.cp_r(old_file_full_path, "./#{TARGET_NAME}")
# copy_directory(old_file_full_path, new_file_full_path)
puts "\033[32m替换新资源文件夹完成\n\033[0m\n"
end
#替换Info.plist文件
def replace_info_plist_file(project, target)
old_file_full_path = @config_asset_directory + "Info.plist"
if File::exist?(old_file_full_path)
new_file_full_path = "./Info.plist"
copy(old_file_full_path, new_file_full_path)
puts "\033[32m替换info.plist文件完成\n\033[0m\n"
else
puts "\033[41mERROR:#{old_file_full_path}不存在!!!\n"
exit
end
end
#配置Build Settings
def add_build_settings(project, target)
target.build_configurations.each do |config|
# 获得build settings
build_settings = config.build_settings
build_settings["GCC_PREPROCESSOR_DEFINITIONS"] = "DEBUG=1"
puts "GCC_PREPROCESSOR_DEFINITIONS ==> DEBUG=1"
build_settings["CURRENT_PROJECT_VERSION"] = 0
puts "CURRENT_PROJECT_VERSION ==> 0"
build_settings["CODE_SIGN_ENTITLEMENTS"] = "xxxxxx.entitlements"
puts "Build Settings: CODE_SIGN_ENTITLEMENTS ==> xxxxxx.entitlements"
build_settings["ARCHS"] = "arm64";
puts "Build Settings: ARCHS ==> arm64"
build_settings["CODE_SIGN_STYLE"] = "Automatic"
puts "Build Settings: CODE_SIGN_STYLE ==> Automatic"
build_settings["CODE_SIGN_IDENTITY"] = "Apple Development"
puts "Build Settings: CODE_SIGN_IDENTITY ==> Apple Development"
build_settings["DEVELOPMENT_TEAM"] = "xxxxxx"
puts "Build Settings: DEVELOPMENT_TEAM ==> xxxxxx"
build_settings["PROVISIONING_PROFILE_SPECIFIER"] = ""
puts "Build Settings: PROVISIONING_PROFILE_SPECIFIER ==> "
build_settings["ENABLE_BITCODE"] = "NO";
puts "Build Settings: ENABLE_BITCODE ==> NO"
build_settings["GCC_C_LANGUAGE_STANDARD"] = "gnu99";
puts "Build Settings: GCC_C_LANGUAGE_STANDARD ==> gnu99"
build_settings["GCC_ENABLE_OBJC_EXCEPTIONS"] = "YES";
puts "Build Settings: GCC_ENABLE_OBJC_EXCEPTIONS ==> YES"
puts "\033[32m#{config.name}模式Build Settings 设置完成\n\033[0m\n"
project.save
end
end
####################################### Begin ###########################################
puts "\033[1m开始配置#{TARGET_NAME}.xcodeproj...\033[0m\n "
#配置Build_Settings
add_build_settings(project, target)
#添加系统动态库
system_frameworks_names = ["AudioToolbox", "AssetsLibrary", "AVFoundation", "AVKit", "CFNetWork", "CoreGraphics", "CoreMedia", "CoreMotion", "CoreLocation", "CoreText", "CoreVideo", "Foundation", "MobileCoreServices", "iAd", "StoreKit", "Photos", "MapKit", "Security", "WebKit", "AppTrackingTransparency", "CoreTelephony", "ImageIO"]
add_system_frameworks(project, system_frameworks_names, false)
#添加系统tdb库
system_tbds_names = ["libresolv", "libz", "libsqlite3", "libc++"]
add_system_tbds(project, system_tbds_names, false)
#替换UnityAppController.h、UnityAppController.mm
replace_unity_app_controller(project, target)
#替换Unity生成的启动资源
replace_unity_launch_screen_resouce(project, target)
#添加Associated Domains文件配置
add_bundle_files(project, target)
#替换Info.plist文件
replace_info_plist_file(project, target)
#替换Images.xcassets文件夹
replace_assets_file(project, target)
#置灰iPhone X横条
UIRectEdgeOldStr = "- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures\n{\n UIRectEdge res = UIRectEdgeNone;\n if (UnityGetDeferSystemGesturesTopEdge())\n res |= UIRectEdgeTop;\n if (UnityGetDeferSystemGesturesBottomEdge())\n res |= UIRectEdgeBottom;\n if (UnityGetDeferSystemGesturesLeftEdge())\n res |= UIRectEdgeLeft;\n if (UnityGetDeferSystemGesturesRightEdge())\n res |= UIRectEdgeRight;\n return res;\n}\n\n- (BOOL)prefersHomeIndicatorAutoHidden\n{\n return UnityGetHideHomeButton();\n}"
UIRectEdgeNewStr = "- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures\n{\n return UIRectEdgeAll;\n}"
File.open("./Classes/UI/UnityViewControllerBase+iOS.mm","r:utf-8") do |lines|
read = lines.read.clone
if read[UIRectEdgeNewStr]
puts "已置灰iPhoneX横条"
else
buffer = read.gsub(UIRectEdgeOldStr,UIRectEdgeNewStr)
File.open("./Classes/UI/UnityViewControllerBase+iOS.mm","w"){|l|
l.write(buffer)
}
end
end
puts "\033[32m置灰iPhone X横条完成\n\033[0m\n"
#修改UNITY_TRAMPOLINE_IN_USE配置
UNITY_TRAMPOLINE_IN_USE_old = "#define UNITY_USES_REMOTE_NOTIFICATIONS 0"
UNITY_TRAMPOLINE_IN_USE_new = "#define UNITY_USES_REMOTE_NOTIFICATIONS 1"
File.open("./Classes/Preprocessor.h","r:utf-8") do |lines|
read = lines.read.clone
if read.include?(UNITY_TRAMPOLINE_IN_USE_new)
puts "\nPreprocessor.h已修改UNITY_USES_REMOTE_NOTIFICATIONS为1"
else
buffer = read.gsub(UNITY_TRAMPOLINE_IN_USE_old,UNITY_TRAMPOLINE_IN_USE_new)
File.open("./Classes/Preprocessor.h","w"){|l|
l.write(buffer)
}
end
end
puts "\033[32mPreprocessor.h修改UNITY_USES_REMOTE_NOTIFICATIONS为1\n\033[0m\n"
project.save
puts "\033[1m结束配置#{TARGET_NAME}.xcodeproj\033[0m\n "
if is_auto_open_xcodeproj == '1'
puts " 🎉🎉🎉 \033[44m#{TARGET_NAME}.xcodeproj配置已经全部完成,2秒后将自动打开工程, Have fun!\033[0m\n"
sleep 2
system "open -- #{project_path}"
else
puts " 🎉🎉🎉 \033[44m#{TARGET_NAME}.xcodeproj配置已经全部完成,Have fun!\033[0m\n"
end
end
exit
三、编译Xcode工程、导出ipa、发布ipa包到fir和AppStore
#!/bin/sh
#Jenkins工作URL
JENKINS_URL=$1
#Jenkins BRANCH_NAME
JECKINS_BRANCH_NAME=$2
#Jenkins Job User ID
JECKINS_BUILD_USER_ID=$3
#版本号
BUNDLE_VERSION=$4
#build号
BUNDLE_BUILD_VERSION=$5
#应用网络环境
APP_ENVIRONMENT=$6
#打包类型(DEBUG、RELEASE、ALL)
ORIGINAL_DISTRIBUTION_METHOD=$7
#打包类型(DEBUG、RELEASE、ALL)
DISTRIBUTION_METHOD=$7
#fir更新日志
FIR_CHANGE_LOG=$8
#是否上传至OSS
IS_UPLOAD_TO_OSS=$9
echo ''
echo "JENKINS_URL——${JENKINS_URL}——1111"
echo "JECKINS_BRANCH_NAME——${JECKINS_BRANCH_NAME}——2222"
echo "JECKINS_BUILD_USER_ID——${JECKINS_BUILD_USER_ID}——3333"
echo "BUNDLE_VERSION——${BUNDLE_VERSION}——4444"
echo "BUNDLE_BUILD_VERSION——${BUNDLE_BUILD_VERSION}——5555"
echo "APP_ENVIRONMENT——${APP_ENVIRONMENT}——6666"
echo "DISTRIBUTION_METHOD——${DISTRIBUTION_METHOD}——7777"
echo "FIR_CHANGE_LOG——${FIR_CHANGE_LOG}——8888"
echo "IS_UPLOAD_TO_OSS--${IS_UPLOAD_TO_OSS}--9999"
echo ''
#Jenkins脚本目录
JENKINS_ROOT_DIR="/Users/${USER}/Desktop/Project/Script"
#Unity代码目录
UNITY_ROOT_DIR="/Users/${USER}/Desktop/Project/Unity_IOS/xxxxx"
#iOS代码目录
NATIVE_ROOT_DIR="/Users/${USER}/Desktop/Project/Native/iOS"
#iOS打包脚本目录
IOS_BUILD_SCRIPT_DIR="/Users/${USER}/Desktop/Project/Script"
#iOS打包储存根目录
IOS_BUILD_SAVE_DIR="/Users/${USER}/Desktop/Project/Local/iOS"
#获取脚本执行目录
SCRIP_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
#iOS工程目录
PROJECT_PATH="${NATIVE_ROOT_DIR}/Project"
#进入工程目录
cd "${PROJECT_PATH}"
#获取工程名
PROJECT_NAME=`find . -name *.xcodeproj | awk -F "[/.]" '{print $(NF-1)}'`
#scheme名
SCHEME_NAME=${PROJECT_NAME}
#获取工程plist配置文件
INFO_PLIST_PATH="${PROJECT_PATH}/Info.plist"
#PROJECT_TYPE 项目如果是用cocoapod,就改为 xcworkspace,否则用 xcodeproj
PROJECT_TYPE=xcodeproj
#打包类型
if [ "$PROJECT_TYPE" = "xcodeproj" ]
then
PROJECT_BUILD_TYPE=project
else
PROJECT_BUILD_TYPE=workspace
fi
if [ -e "${PROJECT_PATH}/${PROJECT_NAME}.${PROJECT_TYPE}" ]
then
echo ''
echo "存在${PROJECT_NAME}.${PROJECT_TYPE}工程"
else
echo '/// ----------'
echo "/// ${PROJECT_NAME}.${PROJECT_TYPE}工程不存在!"
echo '/// ----------'
exit 1
fi
#编译所需json信息
BUILD_SECRET_JSON="${IOS_BUILD_SCRIPT_DIR}/common/json/buildSecret.json"
#获取Unity和Native git信息
function getGitInfo(){
CURRENT_PWD_DIR=$(pwd)/
#获取Unit git信息
cd ${UNITY_ROOT_DIR}
UNITY_GIT_COMMIT_BRANCH=`git branch | grep \* | cut -d ' ' -f2`
#Unity Git最后三次提交日志
UNITY_GIT_COMMIT_DESC=`sh "${IOS_BUILD_SCRIPT_DIR}/common/shell/getGitLog.sh" "/Users/${USER}/Desktop/Project/Unity_IOS/kidsplus_bobo"`
#获取Native git信息
cd ${NATIVE_ROOT_DIR}
NATIVE_GIT_COMMIT_BRANCH=`git branch | grep \* | cut -d ' ' -f2`
#Native Git最后三次提交日志
NATIVE_GIT_COMMIT_RECORD=`sh "${IOS_BUILD_SCRIPT_DIR}/common/shell/getGitLog.sh" "${NATIVE_ROOT_DIR}" qingwu`
#回到之前操作目录
cd $CURRENT_PWD_DIR
}
#添加git tag
function addGitTag(){
CURRENT_PWD_DIR=$(pwd)/
#tag名称
GIT_TAG_NAME="iOS_${BUNDLE_VERSION}"
#添加git tag脚本路径
ADD_GIT_TAG_SCRIPT_PATH="/Users/${USER}/Desktop/Project/Script/Common/shell/addGitTag.sh"
#Jenkins
sh ${ADD_GIT_TAG_SCRIPT_PATH} ${JENKINS_ROOT_DIR} ${GIT_TAG_NAME}
#Unity
sh ${ADD_GIT_TAG_SCRIPT_PATH} ${UNITY_ROOT_DIR} ${GIT_TAG_NAME}
#iOS
sh ${ADD_GIT_TAG_SCRIPT_PATH} ${NATIVE_ROOT_DIR} ${GIT_TAG_NAME}
#回到之前操作目录
cd $CURRENT_PWD_DIR
}
#解析本地储存json
function analysisBuildSecretJson(){
BUILD_SECRET_JSON="${IOS_BUILD_SCRIPT_DIR}/common/json/buildSecret.json"
if [ -e $BUILD_SECRET_JSON ]
then
COMPUTER_USER_NAME=`jq -r .computer_user_name $BUILD_SECRET_JSON`
FIR_API_TOKEN=`jq -r .fir_api_token $BUILD_SECRET_JSON`
else
echo '/// 缺少打包必要json文件!'
echo ''
exit 1
fi
}
#根据分发方式定义各类路径名称
function definePath(){
if [ "$DISTRIBUTION_METHOD" = "AdHoc" ]
then
#打包模式 Debug/Release
DEVELOPMENT_MODE="Debug"
#exportOptionsPlist文件所在路径
EXPORT_OPTIONS_PLIST_PATH=${IOS_BUILD_SCRIPT_DIR}/iOS/export_ipa_plist/ExportOptions-adhoc.plist
#archive路径
ARCHIVE_FILE_PATH=${IOS_BUILD_SAVE_DIR}/${BUNDLE_VERSION}/Build/${BUNDLE_BUILD_VERSION}/archive/AdHoc/bobo.xcarchive
#导出.ipa文件所在路径
EXPORT_IPA_PATH=${IOS_BUILD_SAVE_DIR}/${BUNDLE_VERSION}/Build/${BUNDLE_BUILD_VERSION}/ipa_file/AdHoc
#ipa文件存放目标路径
IPA_FILE_PATH=${EXPORT_IPA_PATH}/Apps/bobo.ipa
#ipa文件存放OSS的名称
IPA_FILE_NAME_WITH_OSS=AdHoc_${BUNDLE_VERSION}_${BUNDLE_BUILD_VERSION}_${APP_ENVIRONMENT}
#fir安装二维码
FIR_INSTALL_QRCODE_IMAGE_PATH=${EXPORT_IPA_PATH}/Apps/fir-bobo.png
else
DEVELOPMENT_MODE="Release"
EXPORT_OPTIONS_PLIST_PATH=${IOS_BUILD_SCRIPT_DIR}/iOS/export_ipa_plist/ExportOptions-appstore.plist
ARCHIVE_FILE_PATH=${IOS_BUILD_SAVE_DIR}/${BUNDLE_VERSION}/Build/${BUNDLE_BUILD_VERSION}/archive/AppStore/bobo.xcarchive
EXPORT_IPA_PATH=${IOS_BUILD_SAVE_DIR}/${BUNDLE_VERSION}/Build/${BUNDLE_BUILD_VERSION}/ipa_file/AppStore
IPA_FILE_PATH=${EXPORT_IPA_PATH}/bobo.ipa
IPA_FILE_NAME_WITH_OSS=AppStore_${BUNDLE_VERSION}_${BUNDLE_BUILD_VERSION}_${APP_ENVIRONMENT}
#fir安装二维码
FIR_INSTALL_QRCODE_IMAGE_PATH=${EXPORT_IPA_PATH}/fir-bobo.png
fi
}
#设置xcode工程版本号、编译号和网络环境配置
function setBundleEnvironment(){
build_info_json="${PROJECT_PATH}/Data/Raw/Build.json"
#修改app环境配置json
case "${APP_ENVIRONMENT}" in
"T")
sed -i "" 's/xxxxxx/xxxxxx/' ${build_info_json}
;;
"Q")
sed -i "" 's/xxxxxx/xxxxxx/' ${build_info_json}
;;
*)
sed -i "" 's/xxxxxx/xxxxxx/' ${build_info_json}
;;
esac
#设置本地json文件版本号
BUILD_VERSION_WITH_JSON=`jq -r .Version ${build_info_json}`
sed -i "" "s/${BUILD_VERSION_WITH_JSON}/${BUNDLE_VERSION}/" ${build_info_json}
}
#设置工程的version、build信息
function setBundlePlistInfo(){
#设置xcode版本号
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${BUNDLE_VERSION}" "${INFO_PLIST_PATH}"
#设置xcode build号
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${BUNDLE_BUILD_VERSION}" "${INFO_PLIST_PATH}"
}
#检查归档文件、ipa包目录、dSYMs文件目录
function checkArchiveIpaDir(){
#清空上次相同版本的打包目录
rm -rf "${IOS_BUILD_SAVE_DIR}/${BUNDLE_VERSION}/Build"
#生成新的打包目录
mkdir -p "${IOS_BUILD_SAVE_DIR}/${BUNDLE_VERSION}/Build/${BUNDLE_BUILD_VERSION}"
#生成符号表目录
if [ ! -d "${IOS_BUILD_SAVE_DIR}/symtab" ]
then
mkdir -p "${IOS_BUILD_SAVE_DIR}/symtab"
fi
}
#清理工程
function clearXcodeProject(){
echo ''
echo '///-----------'
echo '/// 正在清理工程'
echo '///-----------'
xcodebuild \
clean -configuration ${DEVELOPMENT_MODE} -quiet
echo '///--------'
echo '/// 清理完成'
echo '///--------'
echo ''
}
#归档工程
function archiveXcodeProject(){
echo '///-----------'
echo "/// 正在Archive:${DEVELOPMENT_MODE}"
echo '///-----------'
xcodebuild \
archive -${PROJECT_BUILD_TYPE} ${PROJECT_PATH}/${PROJECT_NAME}.${PROJECT_TYPE} \
-scheme ${SCHEME_NAME} \
-configuration ${DEVELOPMENT_MODE} \
-archivePath ${ARCHIVE_FILE_PATH} \
-allowProvisioningUpdates \
-quiet
if [ -e ${ARCHIVE_FILE_PATH} ]
then
echo '///--------'
echo "/// ${IPA_FILE_NAME_WITH_OSS} Archive完成"
echo '///--------'
echo ''
else
echo '///--------'
echo "/// Archive失败!"
echo '///--------'
echo ''
exit 1
fi
}
#保存符号表文件
function saveSymtabFile(){
if [ "$DISTRIBUTION_METHOD" = "AdHoc" ]
then
return
fi
echo '///--------'
echo "/// 正在生成符号表文件..."
echo '///--------'
echo ''
#dSYM文件路径
dSYM_FILE_PATH="${ARCHIVE_FILE_PATH}/dSYMs/bobo.app.dSYM"
if [ -e $dSYM_FILE_PATH ]
then
CURRENT_PWD_DIR=$(pwd)/
cd "${ARCHIVE_FILE_PATH}/dSYMs/"
#获取uuid
dSYM_FILE_NAME_WITH_UUID=`xcrun dwarfdump --uuid bobo.app.dSYM`
echo "dSYM_FILE_NAME_WITH_UUID:${dSYM_FILE_NAME_WITH_UUID}"
dSYM_FILE_NAME_WITH_UUID=${dSYM_FILE_NAME_WITH_UUID:6:36}
#生成符号表zip文件
cd ${SCRIP_PATH}/tools/buglySymboliOS3.0.0
java -jar buglySymboliOS.jar -i "${IOS_BUILD_SAVE_DIR}/dSYMs/bobo.app.dSYM" -o "${IOS_BUILD_SAVE_DIR}/symtab/${dSYM_FILE_NAME_WITH_UUID}.zip"
if [ -e "${IOS_BUILD_SAVE_DIR}/symtab/${dSYM_FILE_NAME_WITH_UUID}.zip" ]
then
echo '///--------'
echo "符号表成功生成"
echo '///--------'
echo ''
fi
cd "${CURRENT_PWD_DIR}"
else
echo '///--------'
echo "dSYM文件不存在"
echo '///--------'
echo ''
fi
}
#编译ipa包
function buildIpa(){
echo '///--------'
echo "正在导出${IPA_FILE_NAME_WITH_OSS}.ipa ..."
echo ''
xcodebuild -exportArchive -archivePath ${ARCHIVE_FILE_PATH} \
-configuration ${DEVELOPMENT_MODE} \
-exportPath ${EXPORT_IPA_PATH} \
-exportOptionsPlist ${EXPORT_OPTIONS_PLIST_PATH} \
-allowProvisioningUpdates \
-quiet
if [ -e ${IPA_FILE_PATH} ]
then
echo '/// ----------'
echo "/// ipa包已导出:$IPA_FILE_PATH "
echo '/// ----------'
else
echo '///------------'
echo '/// ipa包导出失败!'
echo '///------------'
#清空本次打包目录
rm -rf "${IOS_BUILD_SAVE_DIR}/${BUNDLE_VERSION}/Build"
exit 1
fi
}
#上传文件到OSS
function uploadFileToOSS(){
FILE_PATH=$1
FILE_NAME=$2
if [ -e "${FILE_PATH}" ]
then
UPLOAD_OSS_PY="${IOS_BUILD_SCRIPT_DIR}/common/python/uploadoss.py"
if [ -e $UPLOAD_OSS_PY ]
then
python3 $UPLOAD_OSS_PY $FILE_PATH $FILE_NAME iOS/"$BUNDLE_VERSION"/"$DISTRIBUTION_METHOD"
else
echo '/// 无上传oss脚本'
echo ''
fi
else
echo '/// ----------'
echo "/// [${FILE_PATH}]不存在!"
echo '/// ----------'
fi
}
#上传ipa包
function uploadIpa(){
if [ "$DISTRIBUTION_METHOD" = "AppStore" ]
then
if [ "${ORIGINAL_DISTRIBUTION_METHOD}" = "All" ]
then
disposeIpaUploadResult "导出Release ipa成功"
else
echo '/// ----------'
echo "/// 正在验证ipa..."
echo '/// ----------'
echo ''
#验证ipa
IPA_VALIDATE_TO_APPSTORE_RESPONSE=`xcrun altool --validate-app -f $IPA_FILE_PATH -t ios --apiKey xxxxxx --apiIssuer xxxxxx --verbose --output-format json`
if [[ "${IPA_VALIDATE_TO_APPSTORE_RESPONSE}" == *"No errors validating archive"* ]]
then
echo '/// ----------'
echo "/// 验证ipa成功!"
echo '/// ----------'
echo ''
echo "/// 正在上传ipa到AppStore..."
echo ''
#上传ipa
IPA_UPLOAD_TO_APPSTORE_RESPONSE=`xcrun altool --upload-app -f $IPA_FILE_PATH -t ios --apiKey xxxxxx --apiIssuer xxxxxx --verbose --output-format json`
if [[ "${IPA_UPLOAD_TO_APPSTORE_RESPONSE}" == *"No errors uploading"* ]]
then
disposeIpaUploadResult "上传AppStore成功"
else
if [[ "${IPA_UPLOAD_TO_APPSTORE_RESPONSE}" == *'already uploaded a build'* ]]
then
disposeIpaUploadResult "上传AppStore重复"
else
disposeIpaUploadResult "上传AppStore失败"
fi
fi
else
if [[ "${IPA_VALIDATE_TO_APPSTORE_RESPONSE}" == *'already uploaded a build'* ]]
then
disposeIpaUploadResult "上传AppStore重复"
else
disposeIpaUploadResult "上传AppStore验证失败"
fi
fi
fi
else
if [ "$FIR_API_TOKEN" = "" ]
then
echo '/// ----------'
echo "/// 上传fir失败!error:token不存在"
echo '/// ----------'
echo ''
else
echo '/// ----------'
echo "/// 正在上传ipa到fir..."
echo '/// ----------'
echo ''
fir login -T ${FIR_API_TOKEN}
IPA_UPLOAD_TO_FIR_RESULT=`fir p ${IPA_FILE_PATH} -c ${FIR_CHANGE_LOG} --need_release_id`
echo "IPA_UPLOAD_TO_FIR_RESULT:${IPA_UPLOAD_TO_FIR_RESULT}"
IPA_RELEASE_URL=${IPA_UPLOAD_TO_FIR_RESULT##*'Published succeed: '}
echo "IPA_RELEASE_URL2:${IPA_RELEASE_URL}"
if [[ "$IPA_RELEASE_URL" == "http"* ]]
then
if [[ "$IPA_RELEASE_URL" == *","* ]]
then
IPA_RELEASE_URL=${IPA_RELEASE_URL%%','*}
echo "IPA_RELEASE_URL3:${IPA_RELEASE_URL}"
IPA_RELEASE_URL=${IPA_RELEASE_URL%??}
echo "IPA_RELEASE_URL4:${IPA_RELEASE_URL}"
fi
disposeIpaUploadResult "上传fir成功"
else
disposeIpaUploadResult "上传fir失败"
fi
fi
fi
}
#处理ipa上传结果
function disposeIpaUploadResult(){
#上传结果
IPA_UPLOAD_TO_APPSTORE_RESULT=$1
#获取发行人电话号码
JECKINS_BUILD_USER_NAME=`jq -r ".${JECKINS_BUILD_USER_ID} | .name" "${IOS_BUILD_SCRIPT_DIR}/common/json/dingTalkPhone.json"`
DING_TALK_NOTIFY_USER_PHONE=`jq -r ".${JECKINS_BUILD_USER_ID} | .phone" "${IOS_BUILD_SCRIPT_DIR}/common/json/dingTalkPhone.json"`
if [[ -z ${JECKINS_BUILD_USER_NAME} ]]
then
JECKINS_BUILD_USER_NAME="未知"
fi
if [ "${DING_TALK_NOTIFY_USER_PHONE}" = "" ]
then
DING_TALK_NOTIFY_USER_PHONE="159xxxxxxx"
fi
SEND_DING_TALK_MSG_SCRIPT_PATH="/Users/${USER}/Desktop/Project/Script/common/shell/sendDingTalkMsg.sh"
case "${IPA_UPLOAD_TO_APPSTORE_RESULT}" in
"上传AppStore成功")
echo '/// ----------'
echo "/// ipa上传AppStore成功!"
echo '/// ----------'
echo ''
#发送DingTalk消息
DINGTALK_MESSAGE_TITLE='AppStore应用交付成功'
DING_TALK_NOTIFY_USERS_INFO='{'isAtAll':true}'
DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE} \n>#### - Jenkins执行参数:\n>###### · URL:${JENKINS_URL}\n>###### · 任务名:${JECKINS_BRANCH_NAME}\n>###### · 执行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本号:${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n#### - Unity日志(${UNITY_GIT_COMMIT_BRANCH}):\n${UNITY_GIT_COMMIT_DESC}\n#### - iOS日志(${NATIVE_GIT_COMMIT_BRANCH}):\n${NATIVE_GIT_COMMIT_RECORD}\n\n@所有人\n"
sh $SEND_DING_TALK_MSG_SCRIPT_PATH ${DINGTALK_MESSAGE_TITLE} ${DING_TALK_NOTIFY_USERS_INFO} ${DINGTALK_MESSAGE_CONTENT}
#AppStore交付成功后添加git tag
addGitTag
;;
"上传AppStore重复")
echo '/// ----------'
echo "/// ipa上传重复!AppStore已存在版本号:${BUNDLE_VERSION} build:${BUNDLE_BUILD_VERSION}"
echo '/// ----------'
echo ''
#发送DingTalk消息
DINGTALK_MESSAGE_TITLE='AppStore应用重复提交'
DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins执行参数:\n>###### · URL:${JENKINS_URL}\n>###### · 任务名:${JECKINS_BRANCH_NAME}\n>###### · 执行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本号:${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n#### - Unity日志(${UNITY_GIT_COMMIT_BRANCH}):\n${UNITY_GIT_COMMIT_DESC}\n#### - iOS日志(${NATIVE_GIT_COMMIT_BRANCH}):\n${NATIVE_GIT_COMMIT_RECORD}\n\n@${DING_TALK_NOTIFY_USER_PHONE}\n"
sh $SEND_DING_TALK_MSG_SCRIPT_PATH ${DINGTALK_MESSAGE_TITLE} ${DING_TALK_NOTIFY_USERS_INFO} ${DINGTALK_MESSAGE_CONTENT}
;;
"上传AppStore验证失败")
echo '/// ----------'
echo "/// ipa上传AppStore验证失败!"
echo '/// ----------'
echo ''
echo "/// 正在上传ipa到OSS..."
echo ''
#上传ipa文件到OSS
IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`
#发送DingTalk消息
DINGTALK_MESSAGE_TITLE='AppStore应用验证失败'
DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins执行参数:\n>###### · URL:${JENKINS_URL}\n>###### · 任务名:${JECKINS_BRANCH_NAME}\n>###### · 执行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本号:${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n#### - Unity日志(${UNITY_GIT_COMMIT_BRANCH}):\n${UNITY_GIT_COMMIT_DESC}\n#### - iOS日志(${NATIVE_GIT_COMMIT_BRANCH}):\n${NATIVE_GIT_COMMIT_RECORD}\n\n@${DING_TALK_NOTIFY_USER_PHONE}\n>##### **[ipa下载地址:${IPA_DOWNLOAD_URL}](${IPA_DOWNLOAD_URL})** \n>"
sh $SEND_DING_TALK_MSG_SCRIPT_PATH ${DINGTALK_MESSAGE_TITLE} ${DING_TALK_NOTIFY_USERS_INFO} ${DINGTALK_MESSAGE_CONTENT}
;;
"上传AppStore失败")
echo '/// ----------'
echo "/// ipa上传AppStore失败!"
echo '/// ----------'
echo ''
echo "/// 正在上传ipa到OSS..."
echo ''
#上传ipa文件到OSS
IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`
#发送DingTalk消息
DINGTALK_MESSAGE_TITLE='AppStore应用交付失败'
DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins执行参数:\n>###### · URL:${JENKINS_URL}\n>###### · 任务名:${JECKINS_BRANCH_NAME}\n>###### · 执行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本号:${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n#### - Unity日志(${UNITY_GIT_COMMIT_BRANCH}):\n${UNITY_GIT_COMMIT_DESC}\n#### - iOS日志(${NATIVE_GIT_COMMIT_BRANCH}):\n${NATIVE_GIT_COMMIT_RECORD}\n\n@${DING_TALK_NOTIFY_USER_PHONE}\n>##### **[ipa下载地址:${IPA_DOWNLOAD_URL}](${IPA_DOWNLOAD_URL})** \n"
sh $SEND_DING_TALK_MSG_SCRIPT_PATH ${DINGTALK_MESSAGE_TITLE} ${DING_TALK_NOTIFY_USERS_INFO} ${DINGTALK_MESSAGE_CONTENT}
;;
"上传fir成功")
echo '/// ----------'
echo "/// ipa上传fir成功!"
echo '/// ----------'
echo ''
#上传安装二维码图片
QRCODE_IMAGE_DOWNLOAD_URL=`uploadFileToOSS ${FIR_INSTALL_QRCODE_IMAGE_PATH} "${IPA_FILE_NAME_WITH_OSS}.png"`
if [[ "${IS_UPLOAD_TO_OSS}" = "是" ]]
then
echo "///正在上传ipa到OSS..."
echo ''
#上传ipa文件到OSS
IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`
#发送钉钉消息
DINGTALK_MESSAGE_TITLE="fir-iOS内测应用更新成功"
DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins执行参数:\n>###### · URL:${JENKINS_URL}\n>###### · 任务名:${JECKINS_BRANCH_NAME}\n>###### · 执行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本号:${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n>###### · 环境:${APP_ENVIRONMENT}\n>###### · 更新描述:${FIR_CHANGE_LOG}\n#### - Unity日志(${UNITY_GIT_COMMIT_BRANCH}):\n${UNITY_GIT_COMMIT_DESC}\n#### - iOS日志(${NATIVE_GIT_COMMIT_BRANCH}):\n${NATIVE_GIT_COMMIT_RECORD} ![screenshot](${QRCODE_IMAGE_DOWNLOAD_URL})\n[向右] **[点击这里进行安装](${IPA_RELEASE_URL})** \n\n@${DING_TALK_NOTIFY_USER_PHONE}\n>##### **[ipa下载地址:${IPA_DOWNLOAD_URL}](${IPA_DOWNLOAD_URL})** \n"
sh $SEND_DING_TALK_MSG_SCRIPT_PATH ${DINGTALK_MESSAGE_TITLE} ${DING_TALK_NOTIFY_USERS_INFO} ${DINGTALK_MESSAGE_CONTENT}
else
#发送钉钉消息
DINGTALK_MESSAGE_TITLE="fir-iOS内测应用更新成功"
DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins执行参数:\n>###### · URL:${JENKINS_URL}\n>###### · 任务名:${JECKINS_BRANCH_NAME}\n>###### · 执行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本号:${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n>###### · 环境:${APP_ENVIRONMENT}\n>###### · 更新描述:${FIR_CHANGE_LOG}\n#### - Unity日志(${UNITY_GIT_COMMIT_BRANCH}):\n${UNITY_GIT_COMMIT_DESC}\n#### - iOS日志(${NATIVE_GIT_COMMIT_BRANCH}):\n${NATIVE_GIT_COMMIT_RECORD} ![screenshot](${QRCODE_IMAGE_DOWNLOAD_URL})\n[向右] **[点击这里进行安装](${IPA_RELEASE_URL})** \n\n@${DING_TALK_NOTIFY_USER_PHONE}\n"
sh $SEND_DING_TALK_MSG_SCRIPT_PATH ${DINGTALK_MESSAGE_TITLE} ${DING_TALK_NOTIFY_USERS_INFO} ${DINGTALK_MESSAGE_CONTENT}
fi
;;
"上传fir失败")
echo '/// ----------'
echo "/// ipa上传fir失败!"
echo '/// ----------'
echo ''
echo "/// 正在上传ipa到OSS..."
echo ''
#上传ipa文件到OSS
IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`
#发送DingTalk消息
DINGTALK_MESSAGE_TITLE='fir-iOS内测应用更新失败'
DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins执行参数:\n>###### · URL:${JENKINS_URL}\n>###### · 任务名:${JECKINS_BRANCH_NAME}\n>###### · 执行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本号:${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n>###### · 环境:${APP_ENVIRONMENT}\n>###### · 更新描述:${FIR_CHANGE_LOG}\n#### - Unity日志(${UNITY_GIT_COMMIT_BRANCH}):\n${UNITY_GIT_COMMIT_DESC}\n#### - iOS日志(${NATIVE_GIT_COMMIT_BRANCH}):\n${NATIVE_GIT_COMMIT_RECORD}\n\n@${DING_TALK_NOTIFY_USER_PHONE}\n>##### **[ipa下载地址:${IPA_DOWNLOAD_URL}](${IPA_DOWNLOAD_URL})** \n"
sh $SEND_DING_TALK_MSG_SCRIPT_PATH ${DINGTALK_MESSAGE_TITLE} ${DING_TALK_NOTIFY_USERS_INFO} ${DINGTALK_MESSAGE_CONTENT}
;;
"导出Release ipa成功")
echo '/// ----------'
echo "/// 导出release ipa成功!"
echo '/// ----------'
echo ''
echo "/// 正在上传ipa到OSS..."
echo ''
#上传ipa文件到OSS
IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`
#发送DingTalk消息
DINGTALK_MESSAGE_TITLE='导出ReleaseIpa成功'
DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins执行参数:\n>###### · URL:${JENKINS_URL}\n>###### · 任务名:${JECKINS_BRANCH_NAME}\n>###### · 执行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本号:${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n>###### · 环境:${APP_ENVIRONMENT}\n>###### · 更新描述:${FIR_CHANGE_LOG}\n#### - Unity日志(${UNITY_GIT_COMMIT_BRANCH}):\n${UNITY_GIT_COMMIT_DESC}\n#### - iOS日志(${NATIVE_GIT_COMMIT_BRANCH}):\n${NATIVE_GIT_COMMIT_RECORD}\n\n@${DING_TALK_NOTIFY_USER_PHONE}\n>##### **[ipa下载地址:${IPA_DOWNLOAD_URL}](${IPA_DOWNLOAD_URL})** \n"
sh $SEND_DING_TALK_MSG_SCRIPT_PATH ${DINGTALK_MESSAGE_TITLE} ${DING_TALK_NOTIFY_USERS_INFO} ${DINGTALK_MESSAGE_CONTENT}
;;
esac
}
#打包所有活动
function buildActive(){
#根据分发方式定义各类路径名称
definePath
#检查归档文件及ipa包目录
checkArchiveIpaDir
#设置工程网络环境配置
setBundleEnvironment
#清理工程
clearXcodeProject
#归档工程
archiveXcodeProject
#生成符号表文件
saveSymtabFile
#编译ipa包
buildIpa
#上传ipa包
uploadIpa
}
#解析本地储存json
analysisBuildSecretJson
#设置ipa的version、build信息
setBundlePlistInfo
#获取Unity和Native git信息
getGitInfo
#开始执行打包流程
case "${DISTRIBUTION_METHOD}" in
"AdHoc")
#打测试分发包
buildActive
;;
"AppStore")
#打AppStore包
APP_ENVIRONMENT="P"
buildActive
;;
esac
echo ''
echo '/// 自动打包脚本已执行完毕'
echo ''
exit 0
打包脚本包含功能:
1、读取、修改本地配置json文件
2、修改Xcode工程版本、编译等信息
3、归档、导出ipa包
4、上传fir、App Store
5、保存dSYM文件
6、发布App Store成功给git打上版本号标签
7、将Jenkins任务结果发布到钉钉群消息并@执行人
8、钉钉消息添加git最后提交的三次git记录
9、一些容错处理,比如上传失败自动上传OSS
网友评论