由于公司需要,需有一套代碼出多個APP,(有企業(yè)版也有Store版),同時企業(yè)版又分多個渠道(二維碼放在不同的地方推廣),由于企業(yè)版和Store版證書App的Logo、啟動圖、友盟、支付、分享scheme什么的都不相同,一套代碼出好幾個app,外加幾個渠道,一次打近十個包,改到很來多時候自己都蒙了,所以為了不出錯,也是為了不頭疼所以就只能想想解決辦法。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 一個自動打包腳本是多么的重要.pic.jpg
1.多target
2.buildSetting中設置不同的宏,以區(qū)分是哪個target
3.將channel字斷加入到plist中,以區(qū)分多版本
4.PlistBuddy修改plist(version及channel)
5.打包腳本
一、多target
如果只是一套代碼多個APP可以創(chuàng)建多個target,每個target一套配置文件

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?添加target.jpg

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 三處修改.jpg
1.點擊工程
2.右鍵target點擊Duplicate
3.修改target名稱、修改plist名稱、修改scheme(點擊上圖3處選擇EditScheme->MamagerScheme,修改一下名稱)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 修改Scheme.jpg
4.添加宏代碼中通過判斷是否定義了該宏來判斷當前是哪個target

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?添加宏.jpg
5.如果你是swift和oc混編的工程interfaceHeader原來是一個配置的值,由于改了target名稱回導致新建的target找不到這個文件,所以要這個配置值改為固定值

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?修改interfaceHeader.jpg
6.代碼中判斷當前是哪個target
#ifdef HSENTERPRISE
?//hs
#elif defined XUETUENTERPRISE
//xuetu
#endif
二、多渠道
多渠道主要是給每個app加一個標識符,以區(qū)分是哪個渠道,我們是在每次網(wǎng)絡請求時都會上傳當前channel,用以統(tǒng)計每個渠道的注冊量或者購買等,這里channel字段要加在plist當中,通過自動腳本打包,每次修改一下channel字段,生成對應的ipa包。不然手動改真的爆炸。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 將channel字段加入到plist中.jpg
每個target都有對應的一個info-plist,所以我們可以通過以下方法獲取到當前target綁定的plist,從而獲取channel,當然上面通過宏來判斷是哪個target,也可以在plist文件加一個標識符來區(qū)分是哪個target。
NSDictionary*infoDictionary=[[NSBundle mainBundle]infoDictionary];NSString*channel=[infoDictionary objectForKey:@"channel"];
三、PlistBuddy修改plist
PlistBuddy是mac自帶的命令行修改plist的工具,同樣我們也可以在腳本中通過PlistBuddy來修改plist
終端輸入/usr/libexec/PlistBuddy --help可以查看幫助文檔
舉幾個常用的例子:
添加
/usr/libexec/PlistBuddy -c "Add :addtest string xixi " /Users/hsedu/Desktop/hskaoyanStrore-Info.plist
修改
/usr/libexec/PlistBuddy -c "Set :addtest haha " /Users/hsedu/Desktop/hskaoyanStrore-Info.plist
輸出
/usr/libexec/PlistBuddy -c "print addtest" /Users/hsedu/Desktop/hskaoyanStrore-Info.plist
刪除
/usr/libexec/PlistBuddy -c "Delete :addtest " /Users/hsedu/Desktop/hskaoyanStrore-Info.plist
添加字典
/usr/libexec/PlistBuddy -c "add :adddict:name string zhangsan " /Users/hsedu/Desktop/hskaoyanStrore-Info.plist
創(chuàng)建數(shù)組
/usr/libexec/PlistBuddy -c "add :arrayname array " /Users/hsedu/Desktop/hskaoyanStrore-Info.plist
為數(shù)組增加值
/usr/libexec/PlistBuddy -c "add :arrayname:0 string lisi " /Users/hsedu/Desktop/hskaoyanStrore-Info.plist
四、自動打包腳本
1、shell幾個常用語句
定義變量
APPVERSION="2.1.7"
For in循環(huán)(變量無需聲明直接用)
archiveIpas="? vkeEnterprise xuetuEnterprise vkeStore hsStore";for produce in $archiveIpasdo#codingdone
函數(shù)及case($1代表傳入的參數(shù))
teamID=$(getteamID ${produce})function getteamID(){? ? teamid=""? ? case $1 in? ? hsEnterprise)? ? teamid="93C8xxxxx";? ? ;;? ? hsStore)? ? teamid="5Txxxxxxx";? ? ;;? ? vkeEnterprise)? ? teamid="93CxxxX";? ? ;;? ? vkeStore)? ? teamid="xxxxxJ28";? ? ;;? ? xuetuEnterprise)? ? teamid="9xxxxxYX";? ? ;;? ? esac? ? echo $teamid;}
if語句
methodString=""B="Enterprise"#判斷是否包含Enterprise,從而判定是企業(yè)版還是stroe版證書if [[ $produce == *$B* ]]thenmethodString="enterprise"#包含elsemethodString="ad-hoc"#不包含fi
2.xcodebuild 打包
需要哪些準備
teamID
可以在appleDevelop賬號的Membership Details中查看開發(fā)賬號的teamID
可以在project文件顯示包內(nèi)容中的project.pbxproj 中搜索team查看teamID
證書名字
可以在鑰匙串顯示簡介中查看
描述文件(Provisioning Profiles)UUID
可以終端中vi 描述文件(Provisioning Profiles)查看UUID
3.生成xcarchive文件
xcodebuild -help可查看xcodebuild相關(guān)幫助文檔
man xcodebuild可查看xcodebuild相關(guān)幫助文檔
xcodebuild -list可查看當前工程target、Configurations以及scheme
#archive workspace-用cocoaPods的#xcodebuild-archivePath"${archiveProducePath}${produce}${channel}.xcarchive"-workspace hskaoyan.xcworkspace-scheme"${produce}"-sdk iphoneos-configuration ${configuration}CODE_SIGN_IDENTITY="$IDENTITY"PROVISIONING_PROFILE="$PROFILE_UUID"archive#archive project-沒用cocoaPods或者cocoaPods在工程內(nèi),不含workspacexcodebuild-archivePath"${archiveProducePath}${produce}${channel}.xcarchive"-project hskaoyan.xcodeproj-scheme"${produce}"-sdk iphoneos-configuration ${configuration}CODE_SIGN_IDENTITY="$IDENTITY"PROVISIONING_PROFILE="$PROFILE_UUID"archive
-archivePath生成archive文件的存放路徑
-workspaceworkspace 名稱
-sdk所用sdk(xcodebuild -showsdks可查看可用sdk)
iOSSDKs:iOS 10.2? ? ? ? ? ? ? ? ? ? ? ? -sdk iphoneos10.2iOS SimulatorSDKs:Simulator - iOS 10.2? ? ? ? ? ? -sdk iphonesimulator10.2macOSSDKs:macOS 10.12? ? ? ? ? ? ? ? ? ? -sdk macosx10.12tvOSSDKs:tvOS 10.1? ? ? ? ? ? ? ? ? ? ? -sdk appletvos10.1tvOS SimulatorSDKs:Simulator - tvOS 10.1? ? ? ? ? -sdk appletvsimulator10.1watchOSSDKs:watchOS 3.1? ? ? ? ? ? ? ? ? ? -sdk watchos3.1watchOS SimulatorSDKs:Simulator - watchOS 3.1? ? ? ? -sdk watchsimulator3.1
-configuration選擇configuration

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 配置configuration.png
CODE_SIGN_IDENTITY證書名稱

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 證書名稱.png
PROVISIONING_PROFILE描述文件UUID

進入描述文件查看UUID.png

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? UUID.png
4.導出ipa包
#導出ipaxcodebuild -exportArchive -archivePath "${archiveProducePath}${produce}${channel}.xcarchive"? -exportPath "${ipaProducePath}${produce}${channel}"? -exportOptionsPlist "$optionsPlist_FILE_PATH"
-archivePath剛才生成的archive文件路徑
-exportPathipa包導出路徑
-exportOptionsPlist導出相關(guān)配置的plist

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? exportOptionsPlist.png
可以通過修改method參數(shù)來選擇你要的包是adhoc還是企業(yè)版或者是store(不通包所需的描述文件不同)
5.自動打包腳本最終版
#!/bin/bashecho "? ? ? _? ? ? ? ? ------ _? ? ? ? ? ? ? ? ? "echo "? ? (_)? ? ? ? / /? ? ) )? ? ? ___? ? ? ? "echo "? ? / /? ? ? ? / /? ? ) )? ? ? / __ \? ? ? "echo "? / /? ? ? ? / /__ _)_)? ? ? / /_/ /\? ? ? "echo "? /_/? ? ? ? /_/? ? ? ? ? ? ? \____/\ \? ? "#hsEnterprise xx企業(yè)版#hsStore? ? ? xxStore版#vkeEnterprise? Vx企業(yè)版#vkeStore? ? ? ? xxStore版#xuetuEnterprise? ? x途企業(yè)版#*****************************************設置區(qū)域**********************************************##設置archive生成的.xcarchive文件路徑(絕對路徑)archiveProducePath="/Users/hsedu/Desktop/ipa/"#設置ipa包生成路徑(絕對路徑)ipaProducePath="/Users/hsedu/Desktop/ipa/"#設置Plist文件路徑前半部分部分(后半部分需要動態(tài)拼接)infoPlist_HEAD_PATH=$(pwd)#設置exportOptions.plist文件路徑optionsPlist_FILE_PATH="$(pwd)/exportOptions.plist"#APP版本號APPVERSION="2.1.7"#設置是打測試版還是發(fā)布版本(Release or Debug)configuration="Release"#設置為哪些App打包ipa hsEnterprise vkeEnterprise xuetuEnterprise vkeStore hsStorearchiveIpas=" vkeStore vkeEnterprise xuetuEnterprise vkeStore hsStore";#設置APP所對應的渠道標志function getChannel(){? ? channel=""? ? case $1 in? ? hsEnterprise)? ? channel="www xxbang xixxwu xxshi";? ? ;;? ? hsStore)? ? channel="www xx";? ? ;;? ? vkeEnterprise)? ? channel="xxx xx";? ? ;;? ? vkeStore)? ? channel="xxx xx";? ? ;;? ? xuetuEnterprise)? ? channel="www xx";? ? ;;? ? esac? ? echo $channel;}#設置APP所對應的teamID的名字function getteamID(){? ? teamid=""? ? case $1 in? ? hsEnterprise)? ? teamid="93xxxxxYX";? ? ;;? ? hsStore)? ? teamid="5xxxxAH36";? ? ;;? ? vkeEnterprise)? ? teamid="93xxxxxX";? ? ;;? ? vkeStore)? ? teamid="xxxxx28";? ? ;;? ? xuetuEnterprise)? ? teamid="9xxxxZYX";? ? ;;? ? esac? ? echo $teamid;}#設置APP所對應的CODE_SIGN_IDENTITY的名字function getCODE_SIGN_IDENTITY(){? ? identity=""? ? case $1 in? ? hsEnterprise)? ? identity="iPhone Distribution: xxx Network Technology Beijing Co.Ltd.";? ? ;;? ? hsStore)? ? identity="iPhone Distribution: xxxao (5x8xxx6)";? ? ;;? ? vkeEnterprise)? ? identity="iPhone Distribution: xxx Network Technology Beijing Co.Ltd.";? ? ;;? ? vkeStore)? ? identity="iPhone Distribution: xxxx Network Technology (Beijing) Co.,Ltd. (Sxxxx8)";? ? ;;? ? xuetuEnterprise)? ? identity="iPhone Distribution: xxxr Network Technology Beijing Co.Ltd.";? ? ;;? ? esac? ? echo $identity;}#設置APP所對應的PROFILE_UUID的名字function getPROFILE_UUID(){? ? identity=""? ? case $1 in? ? hsEnterprise)? ? identity="7xxxxxx3-196exxcxx6";? ? ;;? ? hsStore)#0exxd79-db21-4xxxcxxx8-118xxxxx5d6 adhoc#36xx17xx-17xx-4xxx-b4xxx25xxxx66c appstore? ? identity="0eb8xxx9-db21-4bxc-8exx-118xxxxxd6";? ? ;;? ? vkeEnterprise)? ? identity="bdxxx6xx-9b92-4xx4-xxx8-cdxxxdb3";? ? ;;? ? vkeStore)#183fxxxxxxxxx07 adhoc#1535ba7dxxxxxxd98 appstore? ? identity="1xxfxxx-2d2f-4xxc-8bxxx8-527fxx44b07";? ? ;;? ? xuetuEnterprise)? ? identity="bccxxx9-cxxx-4xxx-xx0-2e8xxxx5";? ? ;;? ? esac? ? echo $identity;}#*****************************************Coding**********************************************#pwd | grep -q '[[:blank:]]' && {echo "Source path: $(pwd)"echo "Out of tree builds are impossible with whitespace in source path."exit 1;}for produce in $archiveIpasdoecho "${produce}"#*****************************************修改infoPlistVersion**********************************************##拼接info.plist路徑infoPlist_FILE_PATH="${infoPlist_HEAD_PATH}/${produce}-info.plist"echo "infoPlistPath:${infoPlist_FILE_PATH}"#修改plist中Version/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $APPVERSION" $infoPlist_FILE_PATH#輸出修改后versionversionPrint=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" $infoPlist_FILE_PATH)echo "plistVersion:$versionPrint"#****************************************修改exportOptionPlist***************************************##method : String#Describes how Xcode should export the archive. Available options: app-store, package, ad-hoc, enterprise, development, and developer-id. The list of options varies based on the type of archive. Defaults to development.methodString=""B="Enterprise"#判斷是否包含Enterprise,從而判定是企業(yè)版還是stroe版證書if [[ $produce == *$B* ]]thenmethodString="enterprise"#包含elsemethodString="ad-hoc"#不包含fi#修改plist中method/usr/libexec/PlistBuddy -c "Set :method $methodString" $optionsPlist_FILE_PATH#輸出修改后methodmethodPrint=$(/usr/libexec/PlistBuddy -c "Print method" $optionsPlist_FILE_PATH)echo "plistMethod:$methodPrint"#設置provisioningProfileNameteamID=$(getteamID ${produce})echo "${teamID}"#修改plist中teamID/usr/libexec/PlistBuddy -c "Set :teamID $teamID" $optionsPlist_FILE_PATH#輸出修改后teamIDchannelPrint=$(/usr/libexec/PlistBuddy -c "Print teamID" $optionsPlist_FILE_PATH)echo "plistTeamID:$channelPrint"for channel in $(getChannel ${produce})do#修改plist中channel/usr/libexec/PlistBuddy -c "Set :channel $channel" $infoPlist_FILE_PATH#輸出修改后channelchannelPrint=$(/usr/libexec/PlistBuddy -c "Print channel" $infoPlist_FILE_PATH)echo "plistChannel:$channelPrint"PROFILE_UUID=$(getPROFILE_UUID ${produce})IDENTITY=$(getCODE_SIGN_IDENTITY ${produce})#archive workspace-用cocoaPods的#xcodebuild -archivePath "${archiveProducePath}${produce}${channel}.xcarchive" -workspace hskaoyan.xcworkspace? -scheme "${produce}"? -sdk iphoneos -configuration ${configuration}? archive#archive project-沒用cocoaPods或者cocoaPods在工程內(nèi),不含workspacexcodebuild -archivePath "${archiveProducePath}${produce}${channel}.xcarchive" -project hskaoyan.xcodeproj? -scheme "${produce}"? -sdk iphoneos -configuration ${configuration} CODE_SIGN_IDENTITY="$IDENTITY" PROVISIONING_PROFILE="$PROFILE_UUID" archive#rvm list 可查看安裝的ruby列表#rvm system#導出ipaxcodebuild -exportArchive -archivePath "${archiveProducePath}${produce}${channel}.xcarchive"? -exportPath "${ipaProducePath}${produce}${channel}"? -exportOptionsPlist "$optionsPlist_FILE_PATH"donedoneprintf "\n(-_-)-Complete-(-_-)\n\n"exit 0
注意
現(xiàn)在xcode都是自動簽名的,因為腳本需要指定證書和描述文件所以工程中不能使用自動簽名,當然也可以不指定,采用自動簽名,但是具體打出包是什么類型不知道,沒去研究。下面兩個是遇到的錯誤及解決的辦法
Error Domain=IDEDistributionErrorDomain Code=14 "No applicable devices found." UserInfo={NSLocalizedDescription=No applicable devices found.}
這里
遇到的坑:①? Code=1 (這個操作不能完成)、② Code=14 (沒有試用的設備 Domain=IDEDistributionErrorDomain Code=14 "No applicable devices found.)、③ "rvm use ..." rvm不可用的問題。
解決辦法:code=1,證書有問題,重做證書。code=14,先rvm system,然后再export也可以。如果rvm不能用,出現(xiàn)rvm use ...、rvm找不到等問題,那就是使用的rvm或者rvm路徑不正確,導致使用的默認ruby有問題,這里需要使用系統(tǒng)的ruby,需要查看本機rvm。個人遇到的問題是,本機rvm路徑有問題,PATH里面的rvm路徑也有問題,找不到正確的rvm以及ruby。unset rvm 清空PATH,重新添加相關(guān)路徑(source /ect/paths)即可,刪除rvm(不需要rvm,rvm system不能用就刪除rvm不需要),重啟。
如果工程中某個target報某個類沒有找到,那一定是創(chuàng)建類的時候忘記勾選targt了,(我這是git兩個分支合并的時候運行報的xxx這個類找不到)
點擊這個類,右邊類的屬性中target memberShip勾選一下即可

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?勾選一下即可.pic.jpg