iOS自動化編譯

http://www.cnblogs.com/brycezhang/p/4097487.htmljavascript

最近研究了一下iOS的自動化編譯,目的是爲了簡化測試和開發的同窗溝通協調的次數,實現測試同窗能夠隨時從網頁操做編譯SVN最新源碼並打包ipa進行測試。
具體思路是經過從配置文件讀取須要編譯的項目配置列表展現在網頁上,測試同窗選擇須要編譯的項目,肯定後將選擇項目的相關參數傳入shell腳本運行,編譯完成自動跳轉至下載頁面。
主要流程包括:php

  1. Shell腳本的編寫。經過xcodebuild和xcrun實現自動編譯並打包。
  2. PHP調用腳本。開啓OS X自帶的Apache服務器,編寫PHP來調用shell。

編寫shell腳本

自動編譯其實就是使用了xcodebuild的相關命令來實現編譯功能,再使用xcrun來將app打包成ipa。
xcodebuild的官方文檔見這裏css

用到的關鍵命令

  • 編譯workspacehtml

    xcodebuild -workspace workspacename -scheme schemename -configuration [-configuration configurationname] clean build SYMROOT=(SYMROOT)
  • 編譯projectjava

    xcodebuild -target targetname -configuration [-configuration configurationname] clean build SYMROOT=(SYMROOT)
  • 查看配置信息python

    xcodebuild -list
  • xcrun打包ipanginx

    xcrun -sdk iphoneos PackageApplication -v projectName.app -o ipaName.ipa

完整的shell腳本稍長放在文章的最後,該腳本改自BashShell
須要注意,腳本中的路徑最好使用絕對路徑。git

配置Apache和PHP

啓動Apache

啓動:sudo apachectl start 中止:sudo apachectl stop 重啓:sudo apachectl restart

文件根目錄系統級的根目錄

http://localhosts/github

對應的文件目錄是:
/Library/WebServer/Documents/docker

系統級根目錄默認沒有開啓目錄列表,開啓方法:
編輯 /etc/apache2/httpd.conf 文件
搜索找到 <Directory "/Library/WebServer/Documents">
將 Options Multiviews 修改成 Options Indexes Multiviews

用戶級根目錄

另外一個 Web 根目錄默認是 ~/Sites ,10.9 中你須要手動建立這個Sites目錄。

檢查這個目錄下是否有 username.conf 文件
/etc/apache2/users/
若是沒有,則須要新建一個,username 須要是你的帳戶名字,建議使用終端建立這個文件:

cd /etc/apache2/users sudo vi username.conf

貼入如下內容,注意修改 username 爲你的帳戶名字

<Directory "/Users/username/Sites/"> Options Indexes MultiViews FollowSymLinksAllowOverride AllOrder allow,denyAllow from allRequire all granted </Directory>

這個文件的權限應該是:
-rw-r--r-- 1 root wheel 298 Jun 28 16:47 username.conf
若是不是,請修改
sudo chmod 644 username.conf
編輯 /etc/apache2/httpd.conf 文件,刪除下列這些代碼前的註釋符號: #

Include /private/etc/apache2/extra/httpd-userdir.conf LoadModule authz_core_module libexec/apache2/mod_authz_core.soLoadModule authz_host_module libexec/apache2/mod_authz_host.soLoadModule userdir_module libexec/apache2/mod_userdir.so

編輯 /etc/apache2/extra/httpd-userdir.conf 文件,刪除下列這些代碼前的註釋符號: #

Include /private/etc/apache2/users/*.conf
重啓 Apache
sudo apachectl restart
這時,這個網址應該已經能夠用了:
http://localhost/~username/

PHP調用shell腳本

這裏主要用到了PHP的system命令:system($cmd)
PHP調用shell的權限是比較低的,咱們的shell裏會須要建立文件及文件夾的權限,解決辦法是經過命令行將PHP文件所在目錄及目錄下的全部文件都提高權限,不然腳本會報權限錯誤。具體步驟以下:

  1. 打開目錄 /private/etc/apache2
  2. 打開文件 httpd.conf
    找到

    User _www Group _www

    修改_www爲你的登陸用戶名

    User <登陸用戶名>
  3. 從命令行重啓Apache

    sudo apachectl restart
  4. 提高網站目錄權限。由於個人網站根目錄就是上文提到的用戶的Sites文件,所以執行如下命令

    sudo chmod 775 ~/Sites sudo chmod 775 ~/Sites/*

好了,權限問題解決了。當滿懷信心看到從網頁調用腳本輸出信息的時候,結果又報了沒法找到證書的錯誤,OMG,但從終端調用腳本就能夠成功,起初覺得權限不夠致使沒法調用證書,繞了一大圈後發現這個問題只是由於鑰匙串中的證書通常安裝在登陸下,只須要移動到系統下就好了。

移動證書

關於從SVN倉庫獲取源碼的部分就不寫了,既然均可以調用腳本了,這部分就也很簡單了。
這個過程仍是比較折騰的,但願這篇文章可以save your time :)

最後奉上相關文件的源碼。


Shell腳本文件(buildtool.sh)

#!/bin/sh export LC_ALL=zh_CN.GB2312;export LANG=zh_CN.GB2312 username=用戶名 ###############配置項目名稱和路徑等相關參數 projectName=$1 #項目所在目錄的名稱 isWorkSpace=$2 #判斷是用的workspace仍是直接project,workspace設置爲true,不然設置爲false projectDir=/Users/${username}/workspace/projects/$3/ #項目所在目錄的絕對路徑 buildConfig=$4 #編譯的方式,默認爲Release,還有Debug等 ###############配置下載的文件名稱和路徑等相關參數 wwwIPADir=/Users/${username}/Sites/$projectName #html,ipa,icon,plist最後所在的目錄絕對路徑 url="http://localhost/${projectName}" #下載路徑 ########################################################################################## ##############################如下部分爲自動生產部分,不須要手動修改############################ ########################################################################################## ####################### FUCTION START ####################### replaceString(){ local inputString=$1 result=${inputString//(/} result=${result//)/} echo $result } date_Y_M_D_W_T() { WEEKDAYS=(星期日 星期一 星期二 星期三 星期四 星期五 星期六) WEEKDAY=$(date +%w) DT="$(date +%Y年%m月%d日) ${WEEKDAYS[$WEEKDAY]} $(date "+%H:%M:%S")" echo "$DT" } ####################### FUCTION END ####################### ###Log的路徑,若是發現log裏又亂碼請在終端執行:export LC_ALL=zh_CN.GB2312;export LANG=zh_CN.GB2312 logDir=/Users/${username}/workspace/xcodebuild mkdir -pv $logDir logPath=$logDir/$projectName-$buildConfig.log echo "~~~~~~~~~~~~~~~~~~~開始編譯~~~~~~~~~~~~~~~~~~~" >>$logPath loginInfo=`who am i` loginUser=`echo $loginInfo |awk '{print $1}'` echo "登錄用戶:$loginUser" >>$logPath loginDate=`echo $loginInfo |awk '{print $3,$4,$5}'` echo "登錄時間:$loginDate" >>$logPath loginServer=`echo $loginInfo |awk '{print $6}'` if [ -n "$loginServer" ]; then echo "登錄用戶IP:$(replaceString $loginServer)" >>$logPath else echo "登錄用戶IP:localhost(127.0.0.1)" >>$logPath fi if [ -d "$logDir" ]; then echo "${logDir}文件目錄存在" else echo "${logDir}文件目錄不存在,建立${logDir}目錄成功" echo "建立${logDir}目錄成功" >>$logPath fi echo "<br />" ###############檢查html等文件放置目錄是否存在,不存在就建立 echo "開始時間:$(date_Y_M_D_W_T)" >>$logPath echo "項目名稱:$projectName" >>$logPath echo "編譯模式:$buildConfig" >>$logPath echo "開始目錄檢查........" >>$logPath if [ -d "$wwwIPADir" ]; then echo "文件目錄存在" >>$logPath else echo "文件目錄不存在" >>$logPath mkdir -pv $wwwIPADir echo "建立${wwwIPADir}目錄成功" >>$logPath fi ###############進入項目目錄 rm -rf ./build buildAppToDir=/Users/${username}/workspace/build/$projectName #編譯打包完成後.archive .ipa文件存放的目錄 ###############獲取版本號,bundleID infoPlist="${projectDir}${projectName}/$projectName-Info.plist" bundleDisplayName=`/usr/libexec/PlistBuddy -c "Print CFBundleDisplayName" $infoPlist` bundleVersion=`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" $infoPlist` bundleIdentifier=`/usr/libexec/PlistBuddy -c "Print CFBundleIdentifier" $infoPlist` bundleBuildVersion=`/usr/libexec/PlistBuddy -c "Print CFBundleVersion" $infoPlist` ###############在網頁上顯示的名字和bundleDisplayName一致 appName=$bundleDisplayName echo "$bundleDisplayName" ###############開始編譯app if $isWorkSpace ; then #判斷編譯方式 echo "開始編譯workspace...." >>$logPath echo "$projectDir$projectName.xcworkspace" xcodebuild -workspace ${projectDir}$projectName.xcworkspace -scheme $projectName -configuration $buildConfig clean build SYMROOT=$buildAppToDir else echo "開始編譯target...." >>$logPath cd ${projectDir} xcodebuild -target $projectName -configuration $buildConfig clean build SYMROOT=$buildAppToDir fi #判斷編譯結果 if test $? -eq 0 then echo "~~~~~~~~~~~~~~~~~~~編譯成功~~~~~~~~~~~~~~~~~~~" else echo "~~~~~~~~~~~~~~~~~~~編譯失敗~~~~~~~~~~~~~~~~~~~" >>$logPath echo "\n" >>$logPath exit 1 fi ###############開始打包成.ipa ipaName=`echo $projectName | tr "[:upper:]" "[:lower:]"` #將項目名轉小寫 appDir=$buildAppToDir/$buildConfig-iphoneos #app所在路徑 echo "開始打包$projectName.xcarchive成$projectName.ipa....." >>$logPath xcrun -sdk iphoneos PackageApplication -v $appDir/$projectName.app -o $appDir/$ipaName.ipa #將app打包成ipa ###############開始拷貝到目標下載目錄 iconName="icon.png" #icon名稱 iconSize=100 #icon大小 #unzipAppDir=$appDir/$projectName.app unzipAppDir=$projectDir iconImages=($(find $unzipAppDir -path "$buildAppToDir" -prune -o -type f -size +1k -name "*[iI]con*.png" |xargs ls -lSar| grep ^-)) #查找帶Icon或icon的圖標,取最大的圖片,忽略build目錄,按大小排序輸出 #iconImages=($(find $unzipAppDir -size +1k -name "*[iI]con*.png")) #查找帶Icon或icon的圖標,取最大的圖片 iconImagesLength=${#iconImages[@]} #獲取數組的count cp -f -p ${iconImages[iconImagesLength-1]} $wwwIPADir/$iconName #拷貝icon.png文件 #檢查文件是否存在 if [ -f "$appDir/$ipaName.ipa" ] then echo "打包$ipaName.ipa成功." >>$logPath else echo "打包$ipaName.ipa失敗." >>$logPath exit 1 fi cp -f -p $appDir/$ipaName.ipa $wwwIPADir/$ipaName.ipa #拷貝ipa文件 echo "複製$ipaName.ipa到${wwwIPADir}成功" >>$logPath ###############計算文件大小和最後更新時間 fileSize=`stat $appDir/$ipaName.ipa |awk '{if($8!=4096){size=size+$8;}} END{print "文件大小:", size/1024/1024,"M"}'` lastUpdateDate=`stat $appDir/$ipaName.ipa | awk '{print "最後更新時間:",$13,$14,$15,$16}'` echo "$fileSize" >>$logPath echo "$lastUpdateDate" >>$logPath plistDir=${wwwIPADir}/$ipaName.plist #plist文件的路徑 htmlDir=${wwwIPADir}/index.html #html文件的路徑 ###############生成PLIST文件 cat << EOF > $plistDir <?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>items</key> <array> <dict> <key>assets</key> <array> <dict> <key>kind</key> <string>software-package</string> <key>url</key> <string>$url/$ipaName.ipa</string> </dict> </array> <key>metadata</key> <dict> <key>bundle-identifier</key> <string>$bundleIdentifier</string> <key>bundle-version</key> <string>$bundleVersion</string> <key>kind</key> <string>software</string> <key>title</key> <string>$appName</string> </dict> </dict> </array> </dict> </plist> EOF echo "生成plist文件到$plistDir成功" >>$logPath ###############生成html下載頁面 cat << EOF > $htmlDir <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta id="viewport" name="viewport" content="width=device-width; height=device-height; initial-scale=1.0; "/> <title>安裝$appName</title> <style type="text/css"> </style> </head> <body> <h2>$appName</h2> <img src="./$iconName" width=$iconSize height = $iconSize> <ul> <li><h2><a href="itms-services://?action=download-manifest&amp;url=$url/$ipaName.plist">手機安裝$appName(V$bundleVersion.$bundleBuildVersion)</a></h2></li> <li><h2><a href="$url/$ipaName.ipa">電腦下載IPA包</a></h2></li> </ul> <p> $fileSize <p> $lastUpdateDate </body> </html> EOF echo "生成html文件到$htmlDir成功" >>$logPath echo "結束時間:$(date_Y_M_D_W_T)" >>$logPath echo "~~~~~~~~~~~~~~~~~~~結束編譯~~~~~~~~~~~~~~~~~~~" >>$logPath echo "~~~~~~~~~~~~~~~~~~~結束編譯,處理成功~~~~~~~~~~~~~~~~~~~" echo "\n" >>$logPath echo "$url" 

配置文件格式(data.json)

[
	{
		"name":"項目展現的名稱1", "projectname":"項目名稱1", "isworkspace":"是不是workspace", "foldername":"項目文件夾名1", "buildconfig":"Release/Debug/其餘自定義編譯名稱" }, { "name":"項目展現的名稱2", "projectname":"項目名稱2", "isworkspace":"是不是workspace", "foldername":"項目文件夾名2", "buildconfig":"Release/Debug/其餘自定義編譯名稱" } ]

PHP文件(index.php)

<html> <head> <title>iOS應用打包</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> </head> <body style="text-align:center"> <h1>請選擇編譯項目</h1> <form name="form1" method="post" action=""> <?php $filename ='data.json'; $jsonstring = file_get_contents($filename); $jsondecode = json_decode($jsonstring, true); for ($i= 0;$i< count($jsondecode); $i++) { $name = $jsondecode[$i]["name"]; echo "<label> <input type='radio' name='radio' value='$i'> ${name} </label> <br />"; } if($_POST) { $value = $_POST['radio']; $name = $jsondecode[$value]["name"]; $projectname = $jsondecode[$value]["projectname"]; $isworkspace = $jsondecode[$value]["isworkspace"]; $foldername = $jsondecode[$value]["foldername"]; $buildconfig = $jsondecode[$value]["buildconfig"]; echo '<br />即將編譯:',$name; echo '<br />編譯完成自動跳轉至下載頁面<br /><br /><br />'; $cmd = "./buildtool.sh $projectname $isworkspace $foldername $buildconfig"; $url = system($cmd); echo "<script language=\"javascript\">"; echo "location.href=\"$url\""; echo "</script>"; } ?> <br /> <input type="submit" name="Submit" value="提交" /> </form> </body> </html>

Posted by Bryce Zhang 
版權聲明:自由轉載-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0

 
分類:  iOS
標籤:  iOS
好文要頂  關注我  收藏該文   
7
0
 
(請您對文章作出評價)
 
« 上一篇: Model-View-ViewModel for iOS [譯]
» 下一篇: 使用CocoaPods開發並打包靜態庫
posted @  2014-11-14 15:54 brycezhang 閱讀(3965) 評論(7) 編輯 收藏

 
 
#1樓   2015-05-16 03:22 IOS應用開發  
y請問一下,怎麼在打包請,修改 plist 的版本號呢!!!
#2樓   2015-05-16 03:22 IOS應用開發  
請問一下,怎麼在打包前,修改 plist 的版本號呢!!!
#3樓   2015-06-23 14:59 heyuan110.com  
同窗,這打包的腳本是來自個人github,寫個引用出去啊~
https://github.com/heyuan110/BashShell
#4樓 [ 樓主] 2015-06-23 15:15 brycezhang  
@醉吻花顏
文中有給出提示和連接,「完整的shell腳本稍長放在文章的最後,該腳本改自BashShell。」,可能寫的不夠明顯,給你形成困惑請諒解。由於對原腳本有修改,因此文中貼出了調整後的源碼。另外感謝你的開源,當時已star表示了支持。
#5樓   2015-06-23 15:30 heyuan110.com  
@brycezhang
^0^,你總結的很不錯啦,沒注意看star哈,這個已經優化了部分地方,好比路徑不須要手動設置了,能夠自動搜索到項目路徑,還有打包ipa時查找名稱可能不對,打包出錯,已經修改了,新的我忘更新了-_-

如今改爲了傳到fir上了,由於咱們的部分測試在國外,只內網不行。fir.im這個平臺夠簡潔我喜歡~,感受比那個蒲公英強很多,最方便的是提供命令行直接上傳。對了若是搭在內網感受用nginx好像比你上面講用apache要方便很多,你能夠試試。

編譯完成打開下載頁面本身看感受沒什麼卵用啊~,最好仍是自動發個郵件給全部測試人員來幹活啦~0~
#6樓 [ 樓主] 2015-06-23 15:55 brycezhang  
@醉吻花顏
抽空去翻一下你的新源碼,最近我也正在考慮使用fir.im,既然你已經實現了,看來我又要拿來主義了,哈哈。
#7樓   2015-06-23 19:15 heyuan110.com  
@brycezhang

已經更新了,把python發郵件的也一塊兒放進去了。
 
 
發表評論

暱稱:

評論內容:
引用  粗體 
相關文章
相關標籤/搜索