2012-01-04 81 views
29

對於CI的目的的特定文件夾,我需要能夠生成XCARCHIVE在我們每晚構建IPA文件。該IPA是我們的測試,與我們的ad-hoc密鑰簽名,並XCARCHIVE是要發送到客戶端,以便他們可以將其導入到Xcode和其提交到應用商店時,他們感到高興。生成xcarchive進入命令行

產生IPA是有點谷歌搜索非常簡單,但是如何生成.XCARCHIVE文件是什麼令我困惑不解。我發現的最接近的是:

xcodebuild -scheme myscheme archive 

然而,這種存儲.xcarchive在一些難以找到的文件夾,例如:

/Users/me/Library/Developer/Xcode/Archives/2011-12-14/MyApp 14-12-11 11.42 AM.xcarchive 

是否有某種方式來控制,其中存檔放,它的名字是什麼,以及如何避免重新編譯它?我想最可能的結果是從DSYM和APP生成xcarchive,這是在執行'xcodebuild build'時生成的 - 這可能嗎?

回答

2

我目前的解決方案是重命名用戶的現有檔案文件夾,運行構建,並執行「查找」複製我想要的檔案,然後刪除檔案文件夾並將舊文件夾重命名爲原樣這樣的代碼在我的紅寶石構建腳本:

# Move the existing archives out of the way 
system('mv ~/Library/Developer/Xcode/Archives ~/Library/Developer/Xcode/OldArchivesTemp') 
# Build the .app, the .DSYM, and the .xcarchive 
system("xcodebuild -scheme \"#{scheme}\" clean build archive CONFIGURATION_BUILD_DIR=\"#{build_destination_folder}\"") 
# Find the xcarchive wherever it was placed and copy it where i want it 
system("find ~/Library/Developer/Xcode/Archives -name *.xcarchive -exec cp -r {} \"#{build_destination_folder}\" \";\"") 
# Delete the new archives folder with this new xcarchive 
system('rm -rf ~/Library/Developer/Xcode/Archives') 
# Put the old archives back 
system('mv ~/Library/Developer/Xcode/OldArchivesTemp ~/Library/Developer/Xcode/Archives') 

它有點哈克,但我沒有看到一個更好的解決方案目前。至少它保留了用戶的「檔案」文件夾及其所有預先存檔的檔案。

--Important注 - !

我既然發現了的代碼,我找到了存檔和CP它,我想不正確複製存檔內的符號鏈接的文件夾行,從而打破代碼在應用程序中籤名。你會想用'mv'或其他維護符號鏈接的東西替換它。乾杯!

+0

這是一個很棒的發現,但不適用於大量同時運行的併發構建的CI系統。 我打算嘗試一下這個basily: export ARCHIVE_BASEPATH =「$ {HOME}/Library/Developer/Xcode/Archives/$(date +%Y-%m-%d)/ $ {SCHEME} 「&& \ ls -td」$ {ARCHIVE_BASEPATH}「* | \ head -n 1 其中,SCHEME是正在構建的Xcode方案的字符串名稱(可能包含空格)。如果兩個不同的CI構建目前正在構建相同的方案,這仍然會存在競爭狀況。 – phatblat 2013-07-10 17:49:40

41

從Xcode 4預覽版5開始,有三個環境變量可以在方案歸檔的後續操作中訪問。

ARCHIVE_PATH: The path to the archive. 
ARCHIVE_PRODUCTS_PATH: The installation location for the archived product. 
ARCHIVE_DSYMS_PATH: The path to the product’s dSYM files. 

您可以在此移動/複製存檔。我希望對CI腳本中的進程有更多的控制權,所以我保存了一個臨時文件,可以很容易地從我的CI腳本中找到包含這些值的文件。因爲我嘗試記錄.xcarchive文件的位置

xcodebuild -alltargets -scheme [Scheme Name] -configuration [Config Name] clean archive 
source build/archive_paths.sh 
ARCHIVE_NAME=AppName-$APP_VERSION-$APP_BUILD.xcarchive 
cp -r "$ARCHIVE_PATH" "$BUILD_DIR/$ARCHIVE_NAME" 
+4

謝謝謝謝謝謝謝謝!你究竟發現了這一點?我已經梳理了幾天尋找這樣的文檔的文檔。 – jemmons 2012-08-06 16:55:14

+0

建立在@jemmons評論......你在哪裏找到這個?經過幾天梳理每個人的自定義腳本,我很想閱讀一些官方文檔 – evanflash 2012-12-20 16:55:30

+0

這是我能找到的唯一提及。最糟糕的文檔。 http://developer.apple.com/library/ios/releasenotes/developertools/rn-xcode/#//apple_ref/doc/uid/TP40001051-SW72 – 2013-06-14 17:20:30

0

類似於別人,但也許有點簡單:

BUILD_DIR=$PROJECT_DIR/build 
echo "ARCHIVE_PATH=\"$ARCHIVE_PATH\"" > $BUILD_DIR/archive_paths.sh 
echo "ARCHIVE_PRODUCTS_PATH=\"$ARCHIVE_PRODUCTS_PATH\"" >> $BUILD_DIR/archive_paths.sh 
echo "ARCHIVE_DSYMS_PATH=\"$ARCHIVE_DSYMS_PATH\"" >> $BUILD_DIR/archive_paths.sh 
echo "INFOPLIST_PATH=\"$INFOPLIST_PATH\"" >> $BUILD_DIR/archive_paths.sh 

然後在我的CI的腳本,我可以運行以下。 (我也不移動存檔文件夾,所以如果你同時進行多個構建,這會更好。)

我的調用者構建腳本生成一個新的臨時文件,並將其路徑設置爲一個名爲環境變量XCARCHIVE_PATH_TMPFILE。這個環境變量在我的方案的Archive post-action shell腳本中可用,然後將.xcarchive的路徑寫入該文件。構建腳本可以在調用xcodebuild archive之後讀取該文件。

後操作shell腳本

echo $ARCHIVE_PATH > "$XCARCHIVE_PATH_TMPFILE" 
2

這裏有點慶典,我已經拿出我們的詹金斯CI系統。這些命令應在xcodebuild archive命令完成後立即在腳本中運行。

BUILD_DIR="${WORKSPACE}/build" 
XCODE_SCHEME="myscheme" 

# Common path and partial filename 
ARCHIVE_BASEPATH="${HOME}/Library/Developer/Xcode/Archives/$(date +%Y-%m-%d)/${XCODE_SCHEME}" 

# Find the latest .xcarchive for the given scheme 
NEW_ARCHIVE=$(ls -td "${ARCHIVE_BASEPATH}"* | head -n 1) 

# Zip it up so non-Apple systems won't treat it as a dir 
pushd "${NEW_ARCHIVE%/*}" 
zip -r "${BUILD_DIR}/${NEW_ARCHIVE##*/}.zip" "${NEW_ARCHIVE##*/}" 
popd 

# Optional, disk cleanup 
rm -rf "${NEW_ARCHIVE}" 

的BUILD_DIR用於收集文物,這樣很容易從詹金斯歸檔他們有水珠如build/*.ipa,build/*.zip

0

上的Xcode 4.6,可以指定方案生成後行動被編譯成xcarchive:

echo "ARCHIVE_PATH=\"$ARCHIVE_PATH\"" > $PROJECT_DIR/archive_paths.sh 

構建腳本可以用來檢查是否$ ARCHIVE_PATH運行xcodebuild聯編之後定義,如果是這樣的話,輸出xcarchive可以移動到指定的文件夾中。

如果項目中的目標是一個很大的數字,那麼這種方法不是很好維護,因爲每一個都需要將相應的方案標記爲「共享」並添加生成後操作。

爲了解決這個問題,我創建了一個構建腳本,通過提取與當前日期的目標名稱匹配的最後一個構建,以編程方式生成歸檔路徑。只要沒有在機器上運行相同目標名稱的多個構建(這可能是運行多個併發構建的生產環境中的問題),此方法就可以可靠地工作。用一個例子Xcode項目

#!/bin/bash 
# 
# Script to archive an existing xcode project to a target location. 
# The script checks for a post-build action that defines the $ARCHIVE_PATH as follows: 
# echo "ARCHIVE_PATH=\"$ARCHIVE_PATH\"" > $PROJECT_DIR/archive_paths.sh 
# If such post-build action does not exist or sourcing it doesn't define the $ARCHIVE_PATH 
# variable, the script tries to generate it programmatically by finding the latest build 
# in the expected archiving folder 
# 

post_build_script=archive_paths.sh 
build_errors_file=build_errors.log 
OUTPUT=output/ 
XCODEBUILD_CMD='/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild' 
TARGET_SDK=iphoneos 

function archive() 
{ 
    echo "Archiving target '$1'" 

    # Delete $post_build_script if it already exists as it should be generated by a 
    # post-build action 
    rm -f $post_build_script 

    # Use custom provisioning profile and code sign identity if specified, otherwise 
    # default to project settings 
    # Note: xcodebuild always returns 0 even if the build failed. We look for failure in 
    # the stderr output instead 
    if [[ ! -z "$2" ]] && [[ ! -z "$3" ]]; then 
     ${XCODEBUILD_CMD} clean archive -scheme $1 -sdk "${TARGET_SDK}" \ 
     "CODE_SIGN_IDENTITY=$3" "PROVISIONING_PROFILE=$2" 2>$build_errors_file 
    else 
     ${XCODEBUILD_CMD} clean archive -scheme $1 -sdk "${TARGET_SDK}" 
     2>$build_errors_file 
    fi 

    errors=`grep -wc "The following build commands failed" $build_errors_file` 
    if [ "$errors" != "0" ] 
    then 
     echo "BUILD FAILED. Error Log:" 
     cat $build_errors_file 
     rm $build_errors_file 
     exit 1 
    fi 
    rm $build_errors_file 

    # Check if archive_paths.sh exists 
    if [ -f "$post_build_script" ]; then 
     source "$post_build_script" 
     if [ -z "$ARCHIVE_PATH" ]; then 
      echo "'$post_build_script' exists but ARCHIVE_PATH was not set. 
       Enabling auto-detection" 
     fi 
    fi 
    if [ -z "$ARCHIVE_PATH" ]; then 
     # This is the format of the xcarchive path: 
     # /Users/$USER/Library/Developer/Xcode/Archives/`date +%Y-%m-%d`/$1\ 
     # `date +%d-%m-%Y\ %H.%M`.xcarchive 
     # In order to avoid mismatches with the hour/minute of creation of the archive and 
     # the current time, we list all archives with the correct target that have been 
     # built in the current day (this may fail if the build wraps around midnight) and 
     # fetch the correct file with a combination of ls and grep. 
     # This script can break only if there are multiple targets with exactly the same 
     # name running at the same time. 
     EXTRACTED_LINE=$(ls -lrt /Users/$USER/Library/Developer/Xcode/Archives/`date 
      +%Y-%m-%d`/ | grep $1\ `date +%d-%m-%Y` | tail -n 1) 
     if [ "$EXTRACTED_LINE" == "" ]; then 
      echo "Error: couldn't fetch archive path" 
      exit 1 
     fi 
     # ls -lrt prints lines with the following format 
     # drwxr-xr-x 5 mario 1306712193 170 25 Jul 17:17 ArchiveTest 25-07-2013 
     # 17.17.xcarchive 
     # We can split this line with the " " separator and take the latest bit: 
     # 17.17.xcarchive 
     FILE_NAME_SUFFIX=$(echo $EXTRACTED_LINE | awk '{split($0,a," "); print a[11]}') 
     if [ "$FILE_NAME_SUFFIX" == "" ]; then 
      echo "Error: couldn't fetch archive path" 
      exit 1 
     fi 
     # Finally, we can put everything together to generate the path to the xcarchive 
     ARCHIVE_PATH="/Users/$USER/Library/Developer/Xcode/Archives/`date 
      +%Y-%m-%d`/$1 `date +%d-%m-%Y` $FILE_NAME_SUFFIX/" 
    fi 

    # Create output folder if it doesn't already exist 
    mkdir -p "$OUTPUT" 

    # Move archived xcarchive build to designated output folder 
    mv -v "$ARCHIVE_PATH" "$OUTPUT" 
} 


# Check number of command line args 
if [ $# -lt 1 ]; then 
    echo "Syntax: `basename $0` <target name> [/path/to/provisioning-profile] 
     [<code sign identity]" 
    exit 1 
fi 

if [ ! -z "$2" ]; then 
    PROVISIONING_PROFILE="$2" 
fi 

if [ ! -z "$3" ]; then 
    SIGN_PROVISIONING_PROFILE="$3" 
else 
    if [ ! -z "$PROVISIONING_PROFILE" ]; then 
     SIGN_PROVISIONING_PROFILE=$(cat "$PROVISIONING_PROFILE" | egrep -a -o 
      '[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}') 
    fi 
fi 


archive "$1" "$PROVISIONING_PROFILE" "$SIGN_PROVISIONING_PROFILE" 

完整的源代碼可以在這裏找到:

https://github.com/bizz84/Xcode-xcarchive-command

50

的Xcode 5現在支持-archivePath選項:

​​

您現在還可以導出從您剛剛構建的檔案中籤署IPA:

xcodebuild -exportArchive -exportFormat IPA -exportProvisioningProfile my_profile_name -archivePath /path/to/AppName.xcarchive -exportPath /path/to/AppName.ipa 
+0

太棒了!不知道'xcodebuild'是否具備這個功能,將會非常有用 – 2014-02-19 20:34:48

+0

更好的解決方案。 – 2014-03-06 02:29:05

+0

很高興他們添加了這個參數......這是正確的答案,一定要包括xcarchive的文件名,而不僅僅是路徑......謝謝!!! – 2014-11-03 16:36:40

8

我剛剛解決了這個一個 - 只需添加參數-archivePath到Xcode構建命令行,因爲最初的問題,這將意味着:

xcodebuild -scheme myscheme archive 

成爲...

xcodebuild -scheme myscheme archive -archivePath Build/Archive 

(注:路徑是相對的,我輸出我的構建到$PWD/Build

這將然後將您的。應用程序文件夾中:

xcrun -v -sdk iphoneos PackageApplication -v `pwd`'/Build/Archive.xarchive/Products/Application/my.app' -o `pwd`'/myapp.ipa' 

(注:

Build/Archive.xarchive/Products/Application 

如果您的構建目標已經有你的簽名證書和供給曲線在它你就可以不使用以下命令重新簽署創建IPA文件:xcrun不喜歡相對路徑因此pwd

-v args轉儲大量有用的信息 - 此命令可能無法正確簽署,仍然退出代碼爲0,嘆息!

如果你發現,你不能運行內置的.ipa它可能是一個簽約的問題,你可以做使用雙重檢查:如果它的正確簽名,並與未篡改

codesign --verify -vvvv myapp.app 

輸出都會有這個在:

myapp.app: valid on disk 
myapp.app: satisfies its Designated Requirement 

如果沒有,你會看到類似這樣的:

Codesign check fails : /blahpath/myapp.app: a sealed resource is missing or invalid 
file modified: /blahpath/ls-ios-develop.app/Assets.car 

...這通常意味着您正嘗試使用中間輸出目錄而不是正確的歸檔文件。

+0

謝謝。你的信息解決了我的麻煩。 – firebear 2014-09-23 05:45:15

+0

'xcrun PackageApplication'已被棄用,我相信; 'xcodebuild -exportArchive'在'xcodebuild archive'之後似乎是首選(顯然是Xcode 6的情況,事情開始在Xcode 7的PackageApplication中突破)。可悲的是,功能集不相同;如果在使用'-exportArchive'時沒有在pbxproj中設置特定的配置文件,似乎很難獲得。 – leander 2015-12-14 18:06:09