iOS 一套代碼多APP/多渠道/多target+自動打包腳本

由于公司需要,需有一套代碼出多個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 $archiveIpas
do
#coding
done
  • 函數(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* ]]
then
methodString="enterprise"
#包含
else
methodString="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相關幫助文檔
man xcodebuild可查看xcodebuild相關幫助文檔
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)尚洽,不含workspace
xcodebuild -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文件的存放路徑
-workspace workspace 名稱
-sdk 所用sdk(xcodebuild -showsdks可查看可用sdk)

iOS SDKs:
    iOS 10.2                        -sdk iphoneos10.2

iOS Simulator SDKs:
    Simulator - iOS 10.2            -sdk iphonesimulator10.2

macOS SDKs:
    macOS 10.12                     -sdk macosx10.12

tvOS SDKs:
    tvOS 10.1                       -sdk appletvos10.1

tvOS Simulator SDKs:
    Simulator - tvOS 10.1           -sdk appletvsimulator10.1

watchOS SDKs:
    watchOS 3.1                     -sdk watchos3.1

watchOS Simulator SDKs:
    Simulator - watchOS 3.1         -sdk watchsimulator3.1

-configuration 選擇configuration

配置configuration.png

CODE_SIGN_IDENTITY 證書名稱
證書名稱.png

PROVISIONING_PROFILE描述文件UUID

進入描述文件查看UUID.png
UUID.png

4.導出ipa包

#導出ipa
xcodebuild -exportArchive -archivePath "${archiveProducePath}${produce}${channel}.xcarchive"  -exportPath "${ipaProducePath}${produce}${channel}"   -exportOptionsPlist "$optionsPlist_FILE_PATH"

-archivePath 剛才生成的archive文件路徑
-exportPath ipa包導出路徑
-exportOptionsPlist 導出相關配置的plist

exportOptionsPlist.png

可以通過修改method參數(shù)來選擇你要的包是adhoc還是企業(yè)版或者是store(不通包所需的描述文件不同)

5.自動打包腳本最終版

#!/bin/bash

echo "      _          ------ _                   "
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 hsStore
archiveIpas=" 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 $archiveIpas
do
echo "${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
#輸出修改后version
versionPrint=$(/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* ]]
then
methodString="enterprise"
#包含
else
methodString="ad-hoc"
#不包含
fi

#修改plist中method
/usr/libexec/PlistBuddy -c "Set :method $methodString" $optionsPlist_FILE_PATH
#輸出修改后method
methodPrint=$(/usr/libexec/PlistBuddy -c "Print method" $optionsPlist_FILE_PATH)

echo "plistMethod:$methodPrint"
#設置provisioningProfileName
teamID=$(getteamID ${produce})
echo "${teamID}"

#修改plist中teamID
/usr/libexec/PlistBuddy -c "Set :teamID $teamID" $optionsPlist_FILE_PATH
#輸出修改后teamID
channelPrint=$(/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
#輸出修改后channel
channelPrint=$(/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)靶累,不含workspace
xcodebuild -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
#導出ipa
xcodebuild -exportArchive -archivePath "${archiveProducePath}${produce}${channel}.xcarchive"  -exportPath "${ipaProducePath}${produce}${channel}"   -exportOptionsPlist "$optionsPlist_FILE_PATH"

done


done

printf "\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,重新添加相關路徑(source /ect/paths)即可逐纬,刪除rvm(不需要rvm蛔屹,rvm system不能用就刪除rvm不需要),重啟豁生。

如果工程中某個target報某個類沒有找到兔毒,那一定是創(chuàng)建類的時候忘記勾選targt了,(我這是git兩個分支合并的時候運行報的xxx這個類找不到)
點擊這個類甸箱,右邊類的屬性中target memberShip勾選一下即可

勾選一下即可.pic.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末育叁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子芍殖,更是在濱河造成了極大的恐慌豪嗽,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豌骏,死亡現(xiàn)場離奇詭異龟梦,居然都是意外死亡,警方通過查閱死者的電腦和手機窃躲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門计贰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人框舔,你說我怎么就攤上這事蹦玫∈昊椋” “怎么了刘绣?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挣输。 經(jīng)常有香客問我纬凤,道長,這世上最難降的妖魔是什么撩嚼? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任停士,我火速辦了婚禮,結(jié)果婚禮上完丽,老公的妹妹穿的比我還像新娘恋技。我一直安慰自己,他們只是感情好逻族,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布蜻底。 她就那樣靜靜地躺著,像睡著了一般聘鳞。 火紅的嫁衣襯著肌膚如雪薄辅。 梳的紋絲不亂的頭發(fā)上要拂,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音站楚,去河邊找鬼脱惰。 笑死,一個胖子當著我的面吹牛窿春,可吹牛的內(nèi)容都是我干的拉一。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼旧乞,長吁一口氣:“原來是場噩夢啊……” “哼舅踪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起良蛮,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤抽碌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后决瞳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體货徙,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年皮胡,在試婚紗的時候發(fā)現(xiàn)自己被綠了痴颊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡屡贺,死狀恐怖蠢棱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情甩栈,我是刑警寧澤泻仙,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站量没,受9級特大地震影響玉转,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜殴蹄,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一究抓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧袭灯,春花似錦刺下、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春捺癞,著一層夾襖步出監(jiān)牢的瞬間夷蚊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工髓介, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惕鼓,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓唐础,卻偏偏與公主長得像箱歧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子一膨,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 本文始發(fā)于我的博文詳解Shell腳本實現(xiàn)iOS自動化編譯打包提交呀邢,現(xiàn)轉(zhuǎn)發(fā)至此。 目錄 前言 Shell腳本涉及的工...
    zackzheng閱讀 44,451評論 95 173
  • 起初想法: 基于公司原有的Jenkins服務的基礎上豹绪,最近在公司自動化打包的時价淌,遇到一個尷尬的問題?為什么不能直接...
    Evans_Xiao閱讀 3,779評論 0 3
  • 本文轉(zhuǎn)自CaryaLiu's Blog瞒津。 本文最終實現(xiàn)的是使用腳本打 Ad-hoc 包蝉衣,并發(fā)布測試,當然稍微修改一...
    M_Baron閱讀 1,003評論 1 0
  • #!/bin/bash #$1表示第一個參數(shù) PROJECTPATH="$1" build_configurati...
    biggerworld閱讀 398評論 0 0
  • 紀伯倫說過巷蚪,“友誼要在溫柔甜美中充滿歡笑和同樂”病毡,“不是為了填補你心靈的空虛,而是為了滿足你的需要”屁柏±材ぃ“因為在友誼...
    簡簡風閱讀 298評論 0 6