前一篇:Jenkins十:Mac通過(guò) Tomcat里安裝Jenkins配置Master-Slave打包iOS并上傳到svn服務(wù)器
后一篇:Jenkins十二:Jenkins忘記賬號(hào)密碼處理
前言
隨著項(xiàng)目的發(fā)展蝇恶,一般的項(xiàng)目都遇到一份代碼可能會(huì)要做出多個(gè)APP的情況撮弧,
典型的就是電商的普通用戶版
和商家版
,一些換膚游戲的多個(gè)馬甲APP耀盗。這兩個(gè)版本大部分UI及邏輯都是一樣的卦尊,只會(huì)在小部分頁(yè)面主題顏色及業(yè)務(wù)有些許差別一、單target忿薇,代碼里寫死
在代碼里寫死躏哩,用多個(gè)If else,switch來(lái)進(jìn)行判斷,使用不同的主題及圖片筋栋,以及區(qū)分不同版本的業(yè)務(wù)(這種版本方便簡(jiǎn)潔正驻,誰(shuí)都會(huì),但是不方便擴(kuò)展襟交,以及容易出現(xiàn)bug伤靠,處理起來(lái)也很low)二、多Target
焕梅,這種情況就適合用多Target-Scheme
的方式管理,圖片等資源每個(gè)target自個(gè)一分徒欣,相同的代碼一起引入蜗字,不同部分添加到不同的平臺(tái)(這個(gè)各個(gè)不同的平臺(tái)的圖片及資源都獨(dú)立隔離,不同的平臺(tái)又可以共用一些相同的代碼及資源粗梭,做到了既公用又獨(dú)立级零,壞處是如果平臺(tái)或馬甲包超過(guò)3個(gè)甚至更多時(shí)及其難管理,沒(méi)次新創(chuàng)建的文件都有可能這個(gè)target引入了那個(gè)target又沒(méi)引入鉴嗤,而且如果一直在持續(xù)不斷的增加新的馬甲包平臺(tái)時(shí)序调,創(chuàng)建target也是一件痛苦的事)三、單Target,不同的平臺(tái)包在打包時(shí)動(dòng)態(tài)配置
一個(gè)target硬耍,在業(yè)務(wù)開(kāi)發(fā)時(shí)不同平臺(tái)一些差異化的地方都抽取出來(lái)做成plist進(jìn)行配置化边酒,在打包時(shí)手動(dòng)或自動(dòng)的修改bundleId
、發(fā)布證書坯认、描述文件及其他配置資源和文件(這種方式集合了方式一氓涣、方式二的優(yōu)點(diǎn)春哨,就是不同的平臺(tái)進(jìn)行了有效隔離,適合隨時(shí)增加新的平臺(tái)赴背,但也集合了方案一、方案二的缺點(diǎn)燃观,同時(shí)如果要每次手動(dòng)在xcode修改配置時(shí)是是否痛苦的,必須要和Jenkins配合自動(dòng)打包才能達(dá)到最佳功效)
- 使用xcodebuild命令進(jìn)行自動(dòng)化打包
- project.pbxproj文件解析及腳本修改證書配置思路實(shí)現(xiàn)
- 懶人福利:用腳本來(lái)修改Xcode工程
- Let's Talk About project.pbxproj
將pbxpro轉(zhuǎn)換成xml命令
plutil -convert xml1 -r -o test.xml project.pbxproj
plutil -convert json -r -o test.json Lottery.xcodeproj/project.pbxproj
通過(guò)腳本讀取p12配置并修改project配置進(jìn)行自動(dòng)化修改打包
1番川、先從svn或網(wǎng)絡(luò)或其他地方下載描述文件xxxx.mobileprovision
svn_name="xxx"
svn_pwd="xxx"
certificate_folder="./certificate"
svn export "https://xxx.xx.xx.xx/svn/xxx/xxx.mobileprovision" \
"./xxx.mobileprovision" \
--username ${svn_name} \
--password ${svn_pwd} \
--force
2颁督、解析描述文件
#設(shè)置跨shell環(huán)境及設(shè)置好賬號(hào)密碼
tempVarFile="./tempVarFile.txt"
#2.2浇雹、讀取描述文件
security cms -D -i "./xxx.mobileprovision" > "./profile.plist"
#2.3 讀取信息
#證書持有者機(jī)構(gòu)
config_TeamName=$(/usr/libexec/PlistBuddy -c "print TeamName" "./profile.plist")
echo "config_TeamName='${config_TeamName}'" >> $tempVarFile
#證書持有者組Id
config_teamId=$(/usr/libexec/PlistBuddy -c "print :Entitlements:com.apple.developer.team-identifier" "./profile.plist")
echo "config_teamId='${config_teamId}'" >> $tempVarFile
#bundleId
config_identifier=$(/usr/libexec/PlistBuddy -c "print :Entitlements:application-identifier" "./profile.plist")
config_identifier_cut="${config_teamId}."
config_identifier=${config_identifier#*$config_identifier_cut}
echo "config_identifier='${config_identifier}'" >> $tempVarFile
#發(fā)布證書名稱
config_disName=$(/usr/libexec/PlistBuddy -c "print Name" "./profile.plist")
echo "config_disName='${config_disName}'" >> $tempVarFile
#描述文件UUID
config_uuid=$(/usr/libexec/PlistBuddy -c "print UUID" "./profile.plist")
echo "config_uuid='${config_uuid}'" >> $tempVarFile
#過(guò)期時(shí)間
config_expirationDate=$(/usr/libexec/PlistBuddy -c "print ExpirationDate" "./profile.plist")
echo "config_expirationDate='${config_expirationDate}'" >> $tempVarFile
cat $tempVarFile
source $tempVarFile
3昭灵、修改project配置文件
APP_NAME="xxxx"
cp "./${APP_NAME}.xcodeproj/project.pbxproj" backup.project.pbxproj
# 轉(zhuǎn)換成plist文件
plutil -convert xml1 backup.project.pbxproj
#重命名成plist
cp backup.project.pbxproj backup.project.plist
pbx_rootObject=$(/usr/libexec/PlistBuddy -c "print :rootObject" "./backup.project.plist")
pbx_target=$(/usr/libexec/PlistBuddy -c "print :objects:$pbx_rootObject:targets:0" "./backup.project.plist")
target_buildConfigurationList=$(/usr/libexec/PlistBuddy -c "print :objects:$pbx_target:buildConfigurationList" "./backup.project.plist")
target_debug=$(/usr/libexec/PlistBuddy -c "print :objects:$target_buildConfigurationList:buildConfigurations:0" "./backup.project.plist")
target_release=$(/usr/libexec/PlistBuddy -c "print :objects:$target_buildConfigurationList:buildConfigurations:1" "./backup.project.plist")
#2.3.1烂完、生成change.json文件
cat > "./config_change.json" << END_TEXT
{
"insert" : {
},
"remove" : {
},
"modify" : {
"objects.$target_debug.buildSettings.PRODUCT_BUNDLE_IDENTIFIER" : "${config_identifier}",
"objects.$target_release.buildSettings.PRODUCT_BUNDLE_IDENTIFIER" : "${config_identifier}",
"objects.$target_debug.buildSettings.PROVISIONING_PROFILE_SPECIFIER":"${config_disName}",
"objects.$target_release.buildSettings.PROVISIONING_PROFILE_SPECIFIER":"${config_disName}",
"objects.$target_release.buildSettings.DEVELOPMENT_TEAM":"${config_teamId}",
"objects.$target_debug.buildSettings.DEVELOPMENT_TEAM":"${config_teamId}",
"objects.$pbx_rootObject.attributes.TargetAttributes.$pbx_target.DevelopmentTeam":"${config_teamId}",
"objects.$pbx_rootObject.attributes.TargetAttributes.$pbx_target.ProvisioningStyle":"Manual",
"objects.$target_debug.buildSettings.CODE_SIGN_STYLE":"Manual",
"objects.$target_release.buildSettings.CODE_SIGN_STYLE":"Manual",
"objects.$target_release.buildSettings.CODE_SIGN_IDENTITY":"iPhone Distribution",
"objects.$target_debug.buildSettings.CODE_SIGN_IDENTITY":"iPhone Distribution",
}
}
END_TEXT
cat "./config_change.json"
#判斷是否存在pbxproj
if [ ! -x "/usr/local/bin/pbxproj" ];then
echo "---------不存在pbxproj----------"
#下載命令行工具pbxproj
curl -o pbxproj "https://github.com/yulingtianxia/pbxprojHelper/releases/download/1.2.1/pbxproj"
#移動(dòng)到bin下
mv "./pbxproj" "/usr/local/bin/pbxproj"
#設(shè)置權(quán)限
chmod 755 "/usr/local/bin/pbxproj"
else
echo "---------已經(jīng)存在pbxproj---------"
fi
#2.3.2抠蚣、修改配置
/usr/local/bin/pbxproj -apply "./config_change.json" "./${APP_NAME}.xcodeproj"
#2.4、修改展示名稱
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName ${config_displayName}" "./Resource/platforms/OneNumberDev-Info.plist"
#2.5缓屠、修改版本號(hào)等信息
#2.6护侮、生成由xxx.xcarchive導(dǎo)出xxx.ipa的ExportOptions.plist
cat > "./ExportOptions.plist" << END_TEXT
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>compileBitcode</key>
<true/>
<key>destination</key>
<string>export</string>
<key>method</key>
<string>enterprise</string>
<key>provisioningProfiles</key>
<dict>
<key>${config_identifier}</key>
<string>${config_disName}</string>
</dict>
<key>signingCertificate</key>
<string>iPhone Distribution</string>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
<key>teamID</key>
<string>${config_teamId}</string>
<key>thinning</key>
<string><none></string>
</dict>
</plist>
END_TEXT
echo "===========修改好配置文件了===================="
4羊初、檢測(cè)和安裝證書
#電腦賬號(hào)
Node_User="xxx"
#登錄密碼
Node_Pwd="xxx"
#查找安裝過(guò)的證書
security find-identity -v \
codesigning "/Users/$Node_User/Library/Keychains/login.keychain" \
> "./loginKeychain.txt"
#解鎖鑰匙串
security unlock-keychain -p ${Node_Pwd} "/Users/${Node_User}/Library/Keychains/login.keychain"
# 檢測(cè)p12是否存在
function existP12()
{
find_txt=$*
replace_txt="$(date +%Y%m%d-%H%M%S)"
findPath="./loginKeychain.txt"
sed -i -e "s|$find_txt|'$replace_txt'|" $findPath
if grep -rn -s -q $replace_txt $findPath; then
return 1
else
return 0
fi
}
#檢測(cè)是否已安裝了發(fā)布證書
dis_exist_name="iPhone Distribution: $config_TeamName"
existP12 $dis_exist_name
if $? == 0 ; then
echo "=====沒(méi)有發(fā)布證書======"
dis_file_path="${certificate_folder}/${config_disp12_name}"
security import $dis_file_path \
-k "/Users/${Node_User}/Library/Keychains/login.keychain" \
-P "$config_disp12_pwd" \
-T "/usr/bin/codesign"
else
echo "=====已經(jīng)存在發(fā)布證書====="
fi
#檢測(cè)是否已安裝了推送證書
#aps_exist_name="Apple Development IOS Push Services: $config_identifier"
#existP12 $aps_exist_name
#if $? == 0 ; then
# echo "=====沒(méi)有發(fā)布推送證書====="
# aps_file_path="${certificate_folder}/${config_apsp12_name}"
# security import $aps_file_path \
# -k "/Users/${Node_User}/Library/Keychains/login.keychain" \
# -P "$config_apsp12_pwd" \
# -T "/usr/bin/codesign"
#else
# echo "=====已經(jīng)存在發(fā)布推送證書====="
#fi
#判斷有沒(méi)有描述證書
mobileprovision_path="/Users/$Node_User/Library/MobileDevice/Provisioning Profiles/$config_uuid.mobileprovision"
cp ${certificate_folder}/${config_profileFile} "./$config_uuid.mobileprovision"
mv -f "./$config_uuid.mobileprovision" "${mobileprovision_path}"
正式打包
#!/bin/bash
#臨時(shí)變量
source "./tempVarFile.txt"
# 平臺(tái)及SVN文件夾名稱
APP_NAME="xxx"
SCHEMECA="xxx"
#打包日期(年月日)
DATEOFDAY="$(date +%Y%m%d)"
#打包的時(shí)間(年月日-時(shí)分秒)
DATE="$(date +%Y%m%d-%H%M%S)"
source "./tempVarFile.txt"
#設(shè)置好svn環(huán)境,防止中文亂七八糟的問(wèn)題
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
#*************************************
#下面2行是集成有Cocopods的用法
security unlock-keychain -p ${Node_Pwd} /Users/${Node_User}/Library/Keychains/login.keychain
echo "=================clean================="
echo xcodebuild -workspace "./${APP_NAME}.xcworkspace" -scheme ${SCHEMECA} -configuration 'Release' clean
xcodebuild -workspace "./${APP_NAME}.xcworkspace" -scheme ${SCHEMECA} -configuration 'Release' clean
echo "+++++++++++++++++archive+++++++++++++++++"
#生成的archive的位置
ArchivePath="./${SCHEMECA}_${DATE}.xcarchive"
xcodebuild archive \
-workspace "./${APP_NAME}.xcworkspace" \
-scheme ${SCHEMECA} \
-configuration Release \
-archivePath ${ArchivePath}
echo "+++++++++++++++++export ipa+++++++++++++++++"
APPPath="${ArchivePath}/Products/Applications/${SCHEMECA}.app"
IPAFolderPath="./${SCHEMECA}_${DATE}"
IPAPath="${WORKSPACE}/${SCHEMECA}_${DATE}.ipa"
#在上一個(gè)shell里生成的文件
myOptionsPlist="./ExportOptions.plist"
#生成xxx.ipa
echo xcodebuild -exportArchive \
-archivePath "${ArchivePath}" \
-exportPath "${IPAFolderPath}" \
-exportOptionsPlist ${myOptionsPlist}
xcodebuild -exportArchive \
-archivePath "${ArchivePath}" \
-exportPath "${IPAFolderPath}" \
-exportOptionsPlist ${myOptionsPlist}
##讀取打包后的內(nèi)容的Info
InfoPath="${APPPath}/Info.plist"
#取build值
bundleVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" "${InfoPath}")
#取APP名稱
#打包代碼的分支
tagOrBranchName=${GIT_BRANCH_TAG/origin\//""}
#生成的唯一名稱
UNIQUE_NAME="${APP_NAME}_${SCHEMECA}_V${bundleVersion}_${tagOrBranchName}_${DATE}"
IPANAME="${UNIQUE_NAME}.ipa"
ParentSVNPath="./svn_${DATE}"
local_svn_Path="${ParentSVNPath}/${svn_ipa_folder}/${DATEOFDAY}"
#如果沒(méi)有文件夾,則創(chuàng)建文件夾
if [ ! -d ${local_svn_Path} ];then
mkdir -p ${local_svn_Path}
fi
echo cp "${IPAFolderPath}/${SCHEMECA}.ipa" "${local_svn_Path}/${IPANAME}"
cp "${IPAFolderPath}/${SCHEMECA}.ipa" "${local_svn_Path}/${IPANAME}"
#生成dSYM
dsymutil ${APPPath}/${SCHEMECA} -o "${local_svn_Path}/${UNIQUE_NAME}.app.dSYM"
echo "+++++++++++++++++將ipa上傳到svn+++++++++++++++++"
svn import "${local_svn_Path}/${IPANAME}" \
"https://xxx/xxx/${svn_ipa_folder}/${DATEOFDAY}/${IPANAME}" \
--username ${svn_name} \
--password ${svn_pwd} \
-m "測(cè)試添加文件"
echo "+++++++++++++++++將dsYM上傳到svn+++++++++++++++++"
svn import "${local_svn_Path}/${UNIQUE_NAME}.app.dSYM" \
"https://xxx/xxx/${svn_ipa_folder}/${DATEOFDAY}/${UNIQUE_NAME}.app.dSYM" \
--username ${svn_name} \
--password ${svn_pwd} \
-m "測(cè)試添加文件"
if [ ! -f "${local_svn_Path}/${IPANAME}" ];then
echo ">>>>>不存在ipa>>>>>>>"
cd ..
rm -rf "./$JOB_NAME"
exit 1
fi
if [ ! -d "${local_svn_Path}/${UNIQUE_NAME}.app.dSYM" ]; then
echo ">>>>>不存在dsYM>>>>>>>"
cd ..
rm -rf "./$JOB_NAME"
exit 1
fi
cd ..
echo $JOB_NAME
rm -rf "./$JOB_NAME"