iOS-Unity2018.4.24f1使用Jenkins自動(dòng)化構(gòu)建

適合iOS工程是Unity為主導(dǎo),native代碼是作為插件形式接入垄提。
本文腳本是從Unity生成xcode工程之后開始執(zhí)行价捧,不一定完全適用,請(qǐng)按照自己需求進(jìn)行修改饺藤。

注意修改腳本中“xxxxxx”的地方包斑。

一.安裝xcodeproj

#安裝ruby xcodeproj庫
$gem install xcodeproj
#如果提示沒有權(quán)限運(yùn)行下面這條命令:
$sudo gem install xcodeproj

二、配置xcodeproj工程

#執(zhí)行腳本示例:
ruby '配置腳本文件路徑' 'Unity生成的xcode工程根目錄'
#或者增加參數(shù)可自動(dòng)打開工程:
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"

    #打開項(xiàng)目工程.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創(chuàng)建文件夾: #{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創(chuàng)建文件:#{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}已經(jīng)添加過! #{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}拷貝失斣俟谩C鹊帧!元镀!#{old_file_full_path}\n"
                            exit
                        end
                    else
                        puts "\033[41mERROR:#{file_name}文件不存在I芴睢!栖疑!#{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生成的啟動(dòng)資源
    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生成的啟動(dòng)資源完成\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}不存在S龈铩G淠帧!\n"
            exit
        end
        
        puts "創(chuàng)建新資源文件夾:#{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}不存在B芸臁6亡!\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 設(shè)置完成\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)

    #添加系統(tǒng)動(dòng)態(tài)庫
    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)

    #添加系統(tǒng)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生成的啟動(dòng)資源
    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結(jié)束配置#{TARGET_NAME}.xcodeproj\033[0m\n "

    if is_auto_open_xcodeproj == '1'
        puts " ?????? \033[44m#{TARGET_NAME}.xcodeproj配置已經(jīng)全部完成旋恼,2秒后將自動(dòng)打開工程, Have fun奄容!\033[0m\n"
        sleep 2
        system "open -- #{project_path}"
    else
        puts " ?????? \033[44m#{TARGET_NAME}.xcodeproj配置已經(jīng)全部完成冰更,Have fun产徊!\033[0m\n"
    end

end

exit

三、編譯Xcode工程冬殃、導(dǎo)出ipa囚痴、發(fā)布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

#版本號(hào)
BUNDLE_VERSION=$4

#build號(hào)
BUNDLE_BUILD_VERSION=$5

#應(yīng)用網(wǎng)絡(luò)環(huán)境
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打包儲(chǔ)存根目錄
IOS_BUILD_SAVE_DIR="/Users/${USER}/Desktop/Project/Local/iOS"

#獲取腳本執(zhí)行目錄
SCRIP_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

#iOS工程目錄
PROJECT_PATH="${NATIVE_ROOT_DIR}/Project"

#進(jìn)入工程目錄
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 項(xiàng)目如果是用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 "http:/// ${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
}

#解析本地儲(chǔ)存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
}

#根據(jù)分發(fā)方式定義各類路徑名稱
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
    #導(dǎo)出.ipa文件所在路徑
    EXPORT_IPA_PATH=${IOS_BUILD_SAVE_DIR}/${BUNDLE_VERSION}/Build/${BUNDLE_BUILD_VERSION}/ipa_file/AdHoc
    #ipa文件存放目標(biāo)路徑
    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
}

#設(shè)置xcode工程版本號(hào)生兆、編譯號(hào)和網(wǎng)絡(luò)環(huán)境配置
function setBundleEnvironment(){
  build_info_json="${PROJECT_PATH}/Data/Raw/Build.json"
  #修改app環(huán)境配置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

  #設(shè)置本地json文件版本號(hào)
  BUILD_VERSION_WITH_JSON=`jq -r .Version ${build_info_json}`
  sed -i "" "s/${BUILD_VERSION_WITH_JSON}/${BUNDLE_VERSION}/" ${build_info_json}
}

#設(shè)置工程的version、build信息
function setBundlePlistInfo(){
  #設(shè)置xcode版本號(hào)
  /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${BUNDLE_VERSION}" "${INFO_PLIST_PATH}"
  #設(shè)置xcode build號(hào)
  /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}"

  #生成符號(hào)表目錄
  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 "http:/// 正在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 "http:/// ${IPA_FILE_NAME_WITH_OSS} Archive完成"
    echo '///--------'
    echo ''
  else
    echo '///--------'
    echo "http:/// Archive失敗!"
    echo '///--------'
    echo ''

    exit 1
  fi
}

#保存符號(hào)表文件
function saveSymtabFile(){
  if [ "$DISTRIBUTION_METHOD" = "AdHoc" ]
  then
    return
  fi

  echo '///--------'
  echo "http:/// 正在生成符號(hào)表文件..."
  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}

    #生成符號(hào)表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 "符號(hào)表成功生成"
      echo '///--------'
      echo ''
    fi

    cd "${CURRENT_PWD_DIR}"
  else
    echo '///--------'
    echo "dSYM文件不存在"
    echo '///--------'
    echo ''
  fi
}

#編譯ipa包
function buildIpa(){
  echo '///--------'
  echo "正在導(dǎo)出${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 "http:/// ipa包已導(dǎo)出:$IPA_FILE_PATH "
    echo '/// ----------'
  else
    echo '///------------'
    echo '/// ipa包導(dǎo)出失敗!'
    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 "http:/// [${FILE_PATH}]不存在!"
     echo '/// ----------'
  fi
}

#上傳ipa包
function uploadIpa(){
  if [ "$DISTRIBUTION_METHOD" = "AppStore" ]
  then
    if [ "${ORIGINAL_DISTRIBUTION_METHOD}" = "All" ]
    then
      disposeIpaUploadResult "導(dǎo)出Release ipa成功"
    else
      echo '/// ----------'
      echo "http:/// 正在驗(yàn)證ipa..."
      echo '/// ----------'
      echo ''

      #驗(yàn)證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 "http:/// 驗(yàn)證ipa成功员淫!"
        echo '/// ----------'
        echo ''
        echo "http:/// 正在上傳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重復(fù)"
          else
            disposeIpaUploadResult "上傳AppStore失敗"
          fi
        fi
      else
        if [[ "${IPA_VALIDATE_TO_APPSTORE_RESPONSE}" == *'already uploaded a build'* ]]
        then
          disposeIpaUploadResult "上傳AppStore重復(fù)"
        else
          disposeIpaUploadResult "上傳AppStore驗(yàn)證失敗"
        fi
      fi
    fi
  else
    if [ "$FIR_API_TOKEN" = "" ]
    then
      echo '/// ----------'
      echo "http:/// 上傳fir失敽媳巍!error:token不存在"
      echo '/// ----------'
      echo ''
    else
      echo '/// ----------'
      echo "http:/// 正在上傳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上傳結(jié)果
function disposeIpaUploadResult(){
  #上傳結(jié)果
  IPA_UPLOAD_TO_APPSTORE_RESULT=$1

  #獲取發(fā)行人電話號(hào)碼
  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 "http:/// ipa上傳AppStore成功介返!"
      echo '/// ----------'
      echo ''

      #發(fā)送DingTalk消息
      DINGTALK_MESSAGE_TITLE='AppStore應(yīng)用交付成功'
      DING_TALK_NOTIFY_USERS_INFO='{'isAtAll':true}'
      DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE} \n>#### - Jenkins執(zhí)行參數(shù):\n>###### · URL:${JENKINS_URL}\n>###### · 任務(wù)名:${JECKINS_BRANCH_NAME}\n>###### · 執(zhí)行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本號(hào):${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重復(fù)")
      echo '/// ----------'
      echo "http:/// ipa上傳重復(fù)拴事!AppStore已存在版本號(hào):${BUNDLE_VERSION} build:${BUNDLE_BUILD_VERSION}"
      echo '/// ----------'
      echo ''

      #發(fā)送DingTalk消息
      DINGTALK_MESSAGE_TITLE='AppStore應(yīng)用重復(fù)提交'
      DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
      DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins執(zhí)行參數(shù):\n>###### · URL:${JENKINS_URL}\n>###### · 任務(wù)名:${JECKINS_BRANCH_NAME}\n>###### · 執(zhí)行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本號(hào):${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驗(yàn)證失敗")
      echo '/// ----------'
      echo "http:/// ipa上傳AppStore驗(yàn)證失敗!"
      echo '/// ----------'
      echo ''
      echo "http:/// 正在上傳ipa到OSS..."
      echo ''

      #上傳ipa文件到OSS
      IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`

      #發(fā)送DingTalk消息
      DINGTALK_MESSAGE_TITLE='AppStore應(yīng)用驗(yàn)證失敗'
      DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
      DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins執(zhí)行參數(shù):\n>###### · URL:${JENKINS_URL}\n>###### · 任務(wù)名:${JECKINS_BRANCH_NAME}\n>###### · 執(zhí)行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本號(hào):${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 "http:/// ipa上傳AppStore失敗!"
      echo '/// ----------'
      echo ''
      echo "http:/// 正在上傳ipa到OSS..."
      echo ''

      #上傳ipa文件到OSS
      IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`

      #發(fā)送DingTalk消息
      DINGTALK_MESSAGE_TITLE='AppStore應(yīng)用交付失敗'
      DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
      DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins執(zhí)行參數(shù):\n>###### · URL:${JENKINS_URL}\n>###### · 任務(wù)名:${JECKINS_BRANCH_NAME}\n>###### · 執(zhí)行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本號(hào):${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 "http:/// 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 "http:///正在上傳ipa到OSS..."
        echo ''

        #上傳ipa文件到OSS
        IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`

        #發(fā)送釘釘消息
        DINGTALK_MESSAGE_TITLE="fir-iOS內(nèi)測(cè)應(yīng)用更新成功"
        DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
        DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins執(zhí)行參數(shù):\n>###### · URL:${JENKINS_URL}\n>###### · 任務(wù)名:${JECKINS_BRANCH_NAME}\n>###### · 執(zhí)行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本號(hào):${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n>###### · 環(huá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[向右] **[點(diǎn)擊這里進(jì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
        #發(fā)送釘釘消息
        DINGTALK_MESSAGE_TITLE="fir-iOS內(nèi)測(cè)應(yīng)用更新成功"
        DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
        DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins執(zhí)行參數(shù):\n>###### · URL:${JENKINS_URL}\n>###### · 任務(wù)名:${JECKINS_BRANCH_NAME}\n>###### · 執(zhí)行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本號(hào):${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n>###### · 環(huá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[向右] **[點(diǎn)擊這里進(jì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 "http:/// ipa上傳fir失敗!"
      echo '/// ----------'
      echo ''
      echo "http:/// 正在上傳ipa到OSS..."
      echo ''

      #上傳ipa文件到OSS
      IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`

      #發(fā)送DingTalk消息
      DINGTALK_MESSAGE_TITLE='fir-iOS內(nèi)測(cè)應(yīng)用更新失敗'
      DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
      DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins執(zhí)行參數(shù):\n>###### · URL:${JENKINS_URL}\n>###### · 任務(wù)名:${JECKINS_BRANCH_NAME}\n>###### · 執(zhí)行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本號(hào):${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n>###### · 環(huá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}
    ;;
    "導(dǎo)出Release ipa成功")
      echo '/// ----------'
      echo "http:/// 導(dǎo)出release ipa成功!"
      echo '/// ----------'
      echo ''
      echo "http:/// 正在上傳ipa到OSS..."
      echo ''

      #上傳ipa文件到OSS
      IPA_DOWNLOAD_URL=`uploadFileToOSS $IPA_FILE_PATH "${IPA_FILE_NAME_WITH_OSS}.ipa"`

      #發(fā)送DingTalk消息
      DINGTALK_MESSAGE_TITLE='導(dǎo)出ReleaseIpa成功'
      DING_TALK_NOTIFY_USERS_INFO="{'atMobiles':[${DING_TALK_NOTIFY_USER_PHONE}],'isAtAll':false}"
      DINGTALK_MESSAGE_CONTENT="## ${DINGTALK_MESSAGE_TITLE}\n>#### - Jenkins執(zhí)行參數(shù):\n>###### · URL:${JENKINS_URL}\n>###### · 任務(wù)名:${JECKINS_BRANCH_NAME}\n>###### · 執(zhí)行人:${JECKINS_BUILD_USER_NAME}\n>###### · 版本號(hào):${BUNDLE_VERSION}\n>###### · Build:${BUNDLE_BUILD_VERSION}\n>###### · 環(huá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
}

#打包所有活動(dòng)
function buildActive(){
  #根據(jù)分發(fā)方式定義各類路徑名稱
  definePath
  #檢查歸檔文件及ipa包目錄
  checkArchiveIpaDir
  #設(shè)置工程網(wǎng)絡(luò)環(huán)境配置
  setBundleEnvironment
  #清理工程
  clearXcodeProject
  #歸檔工程
  archiveXcodeProject
  #生成符號(hào)表文件
  saveSymtabFile
  #編譯ipa包
  buildIpa
  #上傳ipa包
  uploadIpa
}


#解析本地儲(chǔ)存json
analysisBuildSecretJson
#設(shè)置ipa的version、build信息
setBundlePlistInfo
#獲取Unity和Native git信息
getGitInfo

#開始執(zhí)行打包流程
case "${DISTRIBUTION_METHOD}" in
  "AdHoc")
    #打測(cè)試分發(fā)包
    buildActive
  ;;
  "AppStore")
    #打AppStore包
    APP_ENVIRONMENT="P"
    buildActive
  ;;
esac

echo ''
echo '/// 自動(dòng)打包腳本已執(zhí)行完畢'
echo ''

exit 0

打包腳本包含功能:

1圣蝎、讀取刃宵、修改本地配置json文件
2、修改Xcode工程版本徘公、編譯等信息
3牲证、歸檔、導(dǎo)出ipa包
4关面、上傳fir坦袍、App Store
5、保存dSYM文件
6缭裆、發(fā)布App Store成功給git打上版本號(hào)標(biāo)簽
7键闺、將Jenkins任務(wù)結(jié)果發(fā)布到釘釘群消息并@執(zhí)行人
8寿烟、釘釘消息添加git最后提交的三次git記錄
9澈驼、一些容錯(cuò)處理,比如上傳失敗自動(dòng)上傳OSS

以上功能分為多個(gè)腳本文件筛武,可以給安卓進(jìn)行自動(dòng)化構(gòu)建使用缝其。
最后貼上釘釘消息樣式:
DingTalk消息(上傳AppStore成功).jpeg
DingTalk消息(上傳fir成功).jpeg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末挎塌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子内边,更是在濱河造成了極大的恐慌榴都,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漠其,死亡現(xiàn)場(chǎng)離奇詭異嘴高,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)和屎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門拴驮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柴信,你說我怎么就攤上這事套啤。” “怎么了随常?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵潜沦,是天一觀的道長。 經(jīng)常有香客問我绪氛,道長唆鸡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任钞楼,我火速辦了婚禮喇闸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘询件。我一直安慰自己燃乍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布宛琅。 她就那樣靜靜地躺著刻蟹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嘿辟。 梳的紋絲不亂的頭發(fā)上舆瘪,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音红伦,去河邊找鬼英古。 笑死,一個(gè)胖子當(dāng)著我的面吹牛昙读,可吹牛的內(nèi)容都是我干的召调。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼唠叛!你這毒婦竟也來了只嚣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤艺沼,失蹤者是張志新(化名)和其女友劉穎册舞,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體障般,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡调鲸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挽荡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片线得。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖徐伐,靈堂內(nèi)的尸體忽然破棺而出贯钩,到底是詐尸還是另有隱情,我是刑警寧澤办素,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布角雷,位于F島的核電站,受9級(jí)特大地震影響性穿,放射性物質(zhì)發(fā)生泄漏勺三。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一需曾、第九天 我趴在偏房一處隱蔽的房頂上張望吗坚。 院中可真熱鬧,春花似錦呆万、人聲如沸商源。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牡彻。三九已至,卻和暖如春出爹,著一層夾襖步出監(jiān)牢的瞬間庄吼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國打工严就, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留总寻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓梢为,卻偏偏與公主長得像渐行,于是被迫代替她去往敵國和親技矮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356