iOS-Unity2018.4.24f1使用Jenkins自动化构建

适合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

以上功能分为多个脚本文件,可以给安卓进行自动化构建使用。
最后贴上钉钉消息样式:
DingTalk消息(上传AppStore成功).jpeg
DingTalk消息(上传fir成功).jpeg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350