天天看點

iOS基于jenkins打包+上傳蒲公英+釘釘群通知

背景:iOS稍微大一點的項目,archive一次需要十幾分鐘,對開發而言,有時候需要切換分支打包,如果異地辦公的情況還要提供測試包,非常麻煩,是以提供遠端打包是必不可少的。

一、本地配置jenkins

安裝:

方式一:建議使用brew安裝jenkins

brew install jenkins

iOS基于jenkins打包+上傳蒲公英+釘釘群通知

如果是M1晶片,根據提示使用 arch -x86_64 brew install jenkins

方式二:到官網下載下傳war包,位址:Jenkins download and deployment

解除安裝:

brew uninstall jenkins 

iOS基于jenkins打包+上傳蒲公英+釘釘群通知

Jenkins的啟動 & 關閉 & 重新開機

brew services start jenkins

brew services stop jenkins

brew services restart jenkins

共享本機jenkins服務

區域網路通路本機的jenkins,localhost:8080 替換成自己的IP:8080即可。

區域網路使用IP通路jenkins

使用brew安裝jenkins會避免很多其他安裝方式産生的使用者權限問題,但是會将httpListenAddress預設設定為127.0.0.1,這樣我們雖然可以在本地用localhost:8080通路,但是本機和區域網路均無法用ip通路。解決辦法為修改兩個路徑下的plist配置。

~/Library/LaunchAgents/homebrew.mxcl.jenkins.plist

/usr/local/opt/jenkins/homebrew.mxcl.jenkins.plist 

第二路徑下沒有的話,可以去看下homebrew所在檔案

終端輸入 /opt/homebrew/opt/jenkins 回車。輸入open .  回車, 打開檔案夾

将上面兩個plist中的httpListenAddress後的ip位址,修改為本機IP或者0.0.0.0即可。

上述兩個配置檔案修改完後,重新開機Jenkins服務

建立項目
iOS基于jenkins打包+上傳蒲公英+釘釘群通知
配置代碼倉庫位址及賬号
iOS基于jenkins打包+上傳蒲公英+釘釘群通知
General 配置中,選擇

參數化建構過程

中的

Git Parameter

選項,然後按下面進行配置。
iOS基于jenkins打包+上傳蒲公英+釘釘群通知
iOS基于jenkins打包+上傳蒲公英+釘釘群通知
iOS基于jenkins打包+上傳蒲公英+釘釘群通知
iOS基于jenkins打包+上傳蒲公英+釘釘群通知
jenkins效果:
iOS基于jenkins打包+上傳蒲公英+釘釘群通知
更多使用參考:http://www.mydlq.club/article/45/

 可選jenkins插件

Ant

Build Timeout

Email Extension

Environment Injector Plugin

fir-plugin

GitHub Branch Source

GitLab

Gitlab Authentication plugin

Gitlab Hook Plugin

Gradle Plugin

Keychains and Provisioning Profiles Management

LDAP Plugin

PAM Authentication

Pipeline

Pipeline: GitHub Groovy Libraries

SSH Slaves

Subversion

Timestamper

Workspace Cleanup

Xcode integration

 二、配置plist檔案

可以采用直接項目内預置exportPlist檔案,也可以用腳本生成

iOS基于jenkins打包+上傳蒲公英+釘釘群通知

 三、xcode打包

1、設定全局gitlab賬号、郵箱

/usr/bin/git  config --global user.name "zhangsan"
/usr/bin/git  config --global user.email "[email protected]"
           

2、鑰匙串通路

##鑰匙串路徑  這幾句的意思是允許通路鑰匙串,因為我們在打包的時候需要通路鑰匙串 用裡面的證書檔案
KEY_PATH="/Users/Library/Keychains/login.keychain"
/usr/bin/security unlock-keychain -p '鑰匙串密碼' ${KEY_PATH}
/usr/bin/security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '鑰匙串密碼' ${KEY_PATH}
/usr/bin/security set-keychain-settings ${KEY_PATH}
           

 3、clean -> pod update-> archive -> 生成export.plist-> export ipa

export LANG=en_US.UTF-8

#version="3.6.8"
#defaultEnv='0'
#switchEnvEnable='1'
#buildType="inhouse"

echo "打包選項為:branch=${branch}\nbuild_type=${buildType}\nversion=${version}\ndefaultEnv=${defaultEnv}\nswitchEnvEnable=${switchEnvEnable}"

echo '正在清理工程'

xcodebuild \
clean -configuration ${development_mode} -quiet  || exit

echo '清理完成'

#pod更新檢測
echo '删除Pods檔案夾'

rm -rf Pods

echo "開始pod update"

pod_result=$(/usr/local/bin/pod update --no-repo-update)
echo 'pod 結果' + $pod_result
error_string='pod repo update'
if [[ $pod_result =~ $error_string ]]; then
  echo 'pod報錯,需要更新repo,開始更新repo'
  /usr/local/bin/pod update --repo-update
fi

####################參數、環境變量定義#########################

# method,打包的方式。方式分别為 app-store, ad-hoc, enterprise, development, validation
if [ $buildType = "inhouse" ];then
    echo '///-----------'
    echo '/// 編譯環境:内測環境'
    echo '///-----------'
    method="development"
    #"development"
    bundle_id="com.xxx.xxx"
    team_id="BW7T59ZXXX"
    provision_name="deleloper_profile"
#    preprocessor_define="INHOUSE=1"
#    sign="Ad Hoc Distribution"
#    "iPhone Distribution"#"Apple Development"
    build_config="Release"
else
    echo '///-----------'
    echo '/// 編譯環境:PRD環境'
    echo '///-----------'
    method="app-store"
    bundle_id="com.xxx.xxx"
    team_id="BW7T59ZXXX"
    provision_name="distribution_appstore"
    sign="Apple Distribution"
    build_config="Release"
fi

#echo "配置資訊:\nbundle_id=${bundle_id}\nteam_id=${team_id}\nmethod=${method}\nprovision_name=${provision_name}\npreprocessor_define=${preprocessor_define}\nsign=${sign}\nbuild_config=${build_config}"

#工程項目路徑
projectPath="$(pwd)"
#工程項目名稱
projectName="eduiPhone"
#工程項目打包模式
buildConfiguration="Release"
#IPA配置檔案
#exportOptionsPlist="${projectPath}/Package/${Archive}.plist"
exportOptionsPlist="exportOptionsPlist.plist"

#證書
ADHOCCODE_SIGN_IDENTITY="Apple Distribution: XXXX XXXX Information Technology LTD "
DEVELOPMENT_TEAM="BW7T59ZXXX"
#描述檔案
Main_Provisioning_Profile="3db7db7e-e783-48e7-8faf-dfef20xxxxxx"

#build檔案路徑
buildPath="${projectPath}/build"
#釋出檔案路徑
releasePath="${projectPath}/build/Release-iphoneos"
#archive儲存路徑
archivePath="${projectPath}/archive"
archiveName="${projectName}.xcarchive"
archiveFilePath="${archivePath}/${archiveName}"

#ipa儲存路徑
ipaPath="${projectPath}/ipa"
#log日志路徑
logfilePath="${projectPath}/ChangeLog"

#取目前時間字元串添加到檔案結尾
dateString=$(date +"%Y%m%d%H%M")
infoPlistPath="eduiPhone/Info.plist"

#配置版本号
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${dateString}" ${infoPlistPath}
if [[ ${version} != "" ]]; then
  echo "輸入了版本号"+$version
  /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${version}" ${infoPlistPath}
fi

version_final=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" ${infoPlistPath})
buildId_final=$dateString
echo "版本号為"+$version_final
echo "buildId為"+$buildId_final

#echo "info.plist内容為"
#/usr/libexec/PlistBuddy -c "print" ${infoPlistPath}

#配置環境屬性
echo "選擇了打包環境"
echo ${defaultEnv}

echo "是否允許切換環境選擇了"
echo ${switchEnvEnable}

echo "開始将上述配置寫入到代碼中"
constantFilePath="eduiPhone/EDUDefineFile/EDUInterfaceDefine.h"
sed -i '' -e "s;#define linetest.*;#define linetest ${defaultEnv};g" ${constantFilePath}
sed -i '' -e "s;#define EDU_SWITCH_ENV_ENABLE.*;#define EDU_SWITCH_ENV_ENABLE ${switchEnvEnable};g" ${constantFilePath}
#echo "寫入成功,寫入後的檔案内容為"
#cat ${constantFilePath}

#先删除存在的檔案目錄
rm -rdf "$buildPath"
rm -rdf "$archivePath"
rm -rdf "$ipaPath"
rm -rdf "${logfilePath}"
#再建立新的檔案目錄
mkdir "$buildPath"
mkdir "$releasePath"
mkdir "$archivePath"
mkdir "$ipaPath"
touch "${logfilePath}"

echo "***********************參數、環境變量***********************"
echo "目前目錄路徑-------->${projectPath}"
echo '打包模式:'$buildConfiguration
echo '工程目錄:'$projectPath
echo '工程名稱:'$projectName
echo '安裝包路徑 '$archiveFilePath
echo '\n'

echo "***********************開始build archive app檔案***********************"

#打包的指令
  archive_result=$(xcodebuild archive -workspace ${projectName}.xcworkspace -scheme "$projectName" -configuration ${build_config} -archivePath ${archiveFilePath} CONFIGURATION_BUILD_DIR="${releasePath}")

echo 'archive_result='+${archive_result}
if [[ $archive_result =~ 'ARCHIVE FAILED' ]]; then
  exit
fi

echo "***********************結束build archive app檔案***********************"

echo "先删除導出選項plist"
rm -rf exportOptionsPlist.plist

#配置導出檔案
#/usr/libexec/PlistBuddy -c "Set :aps-environment string distribution" 恒大寶.entitlements
if [ $buildType = "inhouse" ];then
   /usr/libexec/PlistBuddy -c "Add :compileBitcode bool YES" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :method string ${method}" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :provisioningProfiles dict" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :provisioningProfiles:${bundle_id} string ${provision_name}" exportOptionsPlist.plist
#   /usr/libexec/PlistBuddy -c "Add :APP_IDENTIFIER string ${sign}" exportOptionsPlist.plist
#   /usr/libexec/PlistBuddy -c "Add :signingCertificate string ${sign}" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :signingStyle string automatic" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :stripSwiftSymbols bool true" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :teamID string ${team_id}" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :thinning string <none>" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :destination string export" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "print" exportOptionsPlist.plist
else
   #/usr/libexec/PlistBuddy -c "Add :compileBitcode bool YES" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :method string ${method}" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :provisioningProfiles dict" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :provisioningProfiles:${bundle_id} string ${provision_name}" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :signingCertificate string ${sign}" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :signingStyle string manual" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :stripSwiftSymbols bool true" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :teamID string ${team_id}" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :uploadBitcode bool false" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :uploadSymbols bool true" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :manageAppVersionAndBuildNumber bool true" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "Add :destination string export" exportOptionsPlist.plist
   /usr/libexec/PlistBuddy -c "print" exportOptionsPlist.plist
fi

echo "begin archive"

#導出ipa
export_result=$(xcodebuild -exportArchive -archivePath ${archiveFilePath} -exportPath ${ipaPath} -exportOptionsPlist ${exportOptionsPlist})
echo 'export_result='+${export_result}
if [[ $export_result =~ 'EXPORT FAILED' ]]; then
  exit
fi

echo "***********************設定包名稱資訊***********************"
#app檔案存放位置和命名
appPath="${archiveFilePath}/Products/Applications"
appFile="${appPath}/${projectName}.app"
#app檔案中Info.plist檔案路徑
appInfoPlistPath=$appFile/Info.plist
#取版本号
version=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" ${appInfoPlistPath})
#取Build号
buildNo=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" ${appInfoPlistPath})
#取bundle id
bundleId=$(/usr/libexec/PlistBuddy -c "print CFBundleIdentifier" ${appInfoPlistPath})
#取應用名稱
appName=$(/usr/libexec/PlistBuddy -c "print CFBundleDisplayName" ${appInfoPlistPath})
#包編譯類型(ad-hoc,enterprise...)
buildMethod=$(/usr/libexec/PlistBuddy -c "print method" ${exportOptionsPlist})
#打包的時間
date=$(date +%Y%m%d%H%M)
#判斷放ipa包的目錄是否存在
destinationPath="${projectPath}/Package/${buildMethod}/${projectName}/${version}"
if [ ! -d "$destinationPath" ]; then
    mkdir -p "$destinationPath"
fi
ipaFile="${projectName}_${buildMethod}_${version}(${date}).ipa"
dSYMFile="${projectName}_${buildMethod}_${version}(${date}).app.dSYM"
ipaFilePath="${destinationPath}/${ipaFile}"
dSYMFilePath="${destinationPath}/${dSYMFile}"

#将ipa跟dSYM移動到指定目錄下
mv -f "${ipaPath}/${appName}.ipa" $ipaFilePath
mv -f "${releasePath}/${projectName}.app.dSYM" $dSYMFilePath
echo "** 安裝包最終存放路徑--->${ipaFilePath} **"

#移除日志檔案
#rm -rdf "${logfileDir}"

exit
           

4、上傳蒲公英 OR fir

# 配置蒲公英ukey
pgyerUKey="97b9feec86be53b5f0389cf1b4xxxxxx"
# 配置蒲公英apiKey
pgyerApiKey="01473ebcd9c9742a93b0cd250axxxxxx"

echo "*************************開始上傳到蒲公英**************************"

RESULT=$(curl -F "[email protected]${ipaFilePath}" -F "uKey=$pgyerUKey" -F "_api_key=$pgyerApiKey" http://www.pgyer.com/apiv1/app/upload)

echo $RESULT

echo "*************************結束上傳到蒲公英**************************"
           
#echo "*************************開始上傳到fir**************************"

#fir login "fir 登入的 token"
#
#fir me
#
#
#if [ ! -f "$logfileDir" ]; then
#fir publish ${ipaFilePath} -c "無更新記錄"
#else
#fir publish ${ipaFilePath} -c ${logfileDir}
#fi
#echo "*************************結束上傳到fir**************************"
           

上傳蒲公英後,Result解析方法

   4.1 函數解析

##json解析函數
function jsonParse() { # $1 $2  json lable

     JSON_CONTENT=$1
     KEY='"'$2'":'

     echo ${JSON_CONTENT} | awk -F  ${KEY}  '{print $2}' | awk -F '"' '{print $2}'
}

##删除斜杠'\'
function trimSlash() {
    TEXT=$1
    echo ${TEXT//'\'/''}
}
appQRCodeURL=$(trimSlash $(jsonParse "${RESULT}" "appQRCodeURL"))
appVersion=$(jsonParse "${RESULT}" "appVersion")
appBuildVersion=$(jsonParse "${RESULT}" "appBuildVersion")
appUpdated=$(jsonParse "${RESULT}" "appUpdated")
           

  4.2 json裁剪擷取 QRCode,隻針對二維碼位址擷取

testStr="}}"
##蒲公英二維碼
httpstr=${RESULT#*appQRCodeURL}
httpstr=${httpstr#*:}
httpstr=${httpstr//''/''}
httpstr=${httpstr//'"'/''}
QRCode=${httpstr%${testStr}*}
           

5、發送釘釘消息 

##釘釘消息推送
curl 'https://oapi.dingtalk.com/robot/send?access_token=0de1c87a48d26e9fd31c81c80b39d0ca6395dde7ab98eede2e8xxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{
     "msgtype": "markdown",
     "markdown": {
         "title":"iOS打包",
         "text": "#### [ XXX iOS ]建構成功\n> #### 版本号:'${version}'\n> #### 代碼分支:'${branch}'\n> #### 打包環境:'${environment}'\n> #### 下載下傳位址:'https://www.pgyer.com/apSK/'\n>\n\n> ![screenshot]('${QRCode}')\n> ###### 出包時間:'${currentTime}' [jenkins網址](http://xxx) \n"
     },
    "at": {
        "atMobiles": [
            "132XXXXXXXX"
        ],
        "isAtAll": false
    }
 }'
           
釘釘消息發送還可以使用插件的形式
iOS基于jenkins打包+上傳蒲公英+釘釘群通知
 可參考:https://blog.csdn.net/zhangcongyi420/article/details/105797271

 釘釘效果:

iOS基于jenkins打包+上傳蒲公英+釘釘群通知