2012-01-04 34 views
29

Với mục đích của CI, tôi cần có khả năng tạo tệp XCARCHIVE và IPA trong bản dựng hàng đêm của chúng tôi. IPA dành cho những người thử nghiệm của chúng tôi, được ký bằng các khóa đặc biệt của chúng tôi và XCARCHIVE gửi cho khách hàng để họ có thể nhập nó vào Xcode và gửi nó đến cửa hàng ứng dụng khi họ hài lòng với nó.Tạo xcarchive vào một thư mục cụ thể từ dòng lệnh

Tạo IPA đủ đơn giản với một chút googling, tuy nhiên cách tạo tệp .XCARCHIVE là điều khiến tôi thích. Gần nhất tôi đã tìm thấy là:

xcodebuild -scheme myscheme archive 

Tuy nhiên, điều này lưu trữ các .xcarchive trong một số khó tìm thư mục, ví dụ:

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

Có một số cách để kiểm soát nơi lưu trữ là đặt, tên của nó là gì và cách tránh phải biên dịch lại nó? Tôi đoán kết quả tốt nhất có thể sẽ là tạo ra xcarchive từ DSYM và APP được tạo ra khi bạn thực hiện một 'xcodebuild build' - điều này có khả thi không?

Trả lời

2

Giải pháp hiện tại của tôi là đổi tên thư mục lưu trữ hiện tại của người dùng, chạy bản dựng và thực hiện 'tìm' để sao lưu các lưu trữ mà tôi muốn, sau đó xóa thư mục lưu trữ và đổi tên thư mục cũ trở lại, mã như thế này trong tập lệnh xây dựng ruby ​​của tôi:

# 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') 

Có một chút hacky nhưng hiện tại tôi không thấy giải pháp nào tốt hơn. Ít nhất nó bảo tồn thư mục 'lưu trữ' của người dùng và tất cả các lưu trữ đã tồn tại từ trước của họ.

--Important note -

tôi kể từ khi phát hiện ra rằng các dòng mã mà tôi tìm thấy kho lưu trữ và cp nó vào thư mục tôi muốn không sao chép liên kết tượng trưng trong các kho lưu trữ một cách chính xác, do đó phá vỡ mã ký trong ứng dụng. Bạn sẽ muốn thay thế bằng 'mv' hoặc thứ gì đó duy trì liên kết tượng trưng. Chúc mừng!

+0

Đây là một tìm kiếm tuyệt vời, nhưng không hoạt động đối với một hệ thống CI có nhiều bản dựng đồng thời chạy cùng một lúc. Tôi sẽ thử bit bashery này: xuất ARCHIVE_BASEPATH = "$ {HOME}/Thư viện/Nhà phát triển/Xcode/Lưu trữ/$ (ngày +% Y-% m-% d)/$ {SCHEME} "&& \ ls -td" $ {ARCHIVE_BASEPATH} "* | \ đầu -n 1 Trường hợp SCHEME là tên chuỗi của sơ đồ Xcode đang được xây dựng (có thể chứa dấu cách). Điều này vẫn sẽ có một điều kiện chủng tộc nếu hai CI xây dựng khác nhau hiện đang xây dựng cùng một sơ đồ. – phatblat

41

Bắt đầu với Xcode 4 Xem trước 5 có ba biến môi trường có thể truy cập được trong các tác vụ sau của lưu trữ lược đồ.

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. 

Bạn có thể di chuyển/sao chép lưu trữ tại đây. Tôi muốn kiểm soát quá trình này nhiều hơn trong một kịch bản CI, vì vậy tôi đã lưu một tệp tạm thời có thể dễ dàng có nguồn gốc trong tập lệnh CI chứa các giá trị này.

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 

Sau đó, trong kịch bản CI của tôi, tôi có thể chạy như sau:

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

Cảm ơn bạn cảm ơn bạn cảm ơn bạn! Làm thế nào trên trái đất bạn đã tìm thấy điều này? Tôi đã chải các tài liệu cho những ngày tìm kiếm một cái gì đó như thế này. – jemmons

+0

để xây dựng trên nhận xét @jemmons ... nơi DID bạn tìm thấy điều này? Sau những ngày chải qua các kịch bản tùy chỉnh của mọi người, tôi muốn đọc một số tài liệu chính thức – evanflash

+0

Đây là đề cập duy nhất tôi có thể tìm thấy. Tài liệu crappy tốt nhất của nó. http://developer.apple.com/library/ios/releasenotes/developertools/rn-xcode/#//apple_ref/doc/uid/TP40001051-SW72 –

0

Tương tự như những người khác, nhưng có lẽ đơn giản hơn một chút kể từ khi tôi cố gắng ghi lại vị trí các tập tin .xcarchive của. (Tôi cũng không di chuyển thư mục lưu trữ, vì vậy điều này sẽ hoạt động tốt hơn nếu bạn đang thực hiện nhiều bản dựng cùng một lúc.)

Tập lệnh tạo trình gọi của tôi tạo ra một tệp tạm thời mới và đặt đường dẫn đến biến môi trường có tên XCARCHIVE_PATH_TMPFILE. Biến môi trường này có sẵn trong kịch bản lệnh nén Post-action Archive của chương trình của tôi, sau đó viết đường dẫn .xcarchive của tệp đó. Tập lệnh xây dựng có thể đọc tệp đó sau khi nó gọi xcodebuild archive.

sau hành động shell script

echo $ARCHIVE_PATH > "$XCARCHIVE_PATH_TMPFILE" 
2

Dưới đây là một chút của bash mà tôi đã đưa ra cho hệ thống Jenkins CI của chúng tôi. Các lệnh này sẽ được chạy trong tập lệnh ngay sau khi lệnh xcodebuild archive kết thúc.

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}" 

Các BUILD_DIR được sử dụng để thu thập hiện vật để nó dễ dàng để lưu trữ chúng từ Jenkins với một glob như build/*.ipa,build/*.zip

0

Mở Xcode 4.6 chúng ta có thể xác định một hành động sau xây dựng cho các chương trình để được biên soạn thành một xcarchive:

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

một xây dựng kịch bản có thể được sử dụng để kiểm tra xem $ ARCHIVE_PATH được xác định sau khi chạy xcodebuild và nếu đây là trường hợp, các xcarchive đầu ra có thể được chuyển vào một thư mục được chỉ định.

Phương pháp này không thể duy trì được nếu các mục tiêu trong dự án là một số lớn, vì mỗi đối tượng cần phải gắn thẻ lược đồ tương ứng là 'được chia sẻ' và thêm hành động sau xây dựng.

Để giải quyết vấn đề này, tôi đã tạo tập lệnh xây dựng tạo đường dẫn lưu trữ theo lập trình bằng cách trích xuất bản dựng cuối khớp với tên mục tiêu vào ngày hiện tại. Phương thức này hoạt động đáng tin cậy miễn là không có nhiều bản dựng có cùng tên mục tiêu đang chạy trên máy (điều này có thể là một vấn đề trong môi trường sản xuất khi nhiều bản dựng đồng thời được chạy).

#!/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" 

mã nguồn đầy đủ với một dự án ví dụ Xcode có thể được tìm thấy ở đây:

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

50

Xcode 5 bây giờ hỗ trợ một tùy chọn -archivePath:

xcodebuild -scheme myscheme archive -archivePath /path/to/AppName.xcarchive 

Bạn cũng có thể hiện xuất IPA đã ký từ lưu trữ bạn vừa tạo:

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

Tuyệt vời! Không biết' xcodebuild' có tính năng này. Sẽ hữu ích hơn. –

+0

Giải pháp tốt hơn nhiều. –

+0

Vui mừng khi họ thêm đối số ... đây là câu trả lời đúng, hãy chắc chắn bao gồm tên tệp của xcarchive chứ không phải chỉ đường dẫn ... Cảm ơn !!! –

8

Tôi vừa giải quyết này - chỉ cần thêm tham số -archivePath để xcode dòng build lệnh của bạn, đưa ra câu hỏi ban đầu có nghĩa là:

xcodebuild -scheme myscheme archive 

trở thành ...

xcodebuild -scheme myscheme archive -archivePath Build/Archive 

(Lưu ý: đường dẫn là tương đối, tôi xuất bản dựng của tôi thành $PWD/Build)

Sau đó, địa điểm này sẽ diễn ra của bạn.thư mục ứng dụng trong:

Build/Archive.xarchive/Products/Application 

Nếu xây dựng mục tiêu của bạn đã có giấy chứng nhận ký của bạn và provisioning hồ sơ trong đó bạn có thể tạo file IPA của bạn mà không tái ký sử dụng lệnh sau:

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

(Lưu ý : xcrun không thích đường dẫn tương đối do đó, pwd)

Rất nhiều thông tin hữu ích - lệnh này có thể không ký đúng và vẫn thoát với mã 0, tiếng thở dài!

Nếu bạn thấy rằng bạn không thể chạy được xây dựng .ipa nó có thể là một vấn đề ký kết mà bạn có thể làm một kiểm tra đúp vào sử dụng:

codesign --verify -vvvv myapp.app 

Nếu nó đã ký một cách chính xác và bỏ giả mạo với đầu ra sẽ có điều này trong:

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

Nếu không, bạn sẽ thấy một cái gì đó tương tự như sau:

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

... thường có nghĩa là bạn đang cố gắng sử dụng thư mục đầu ra trung gian thay vì lưu trữ thích hợp.

+0

cảm ơn. Thông tin của bạn đã giải quyết được rắc rối của tôi. – firebear

+0

'xcrun PackageApplication' không được chấp nhận, tôi tin; 'xcodebuild -exportArchive' sau khi một' xcodebuild archive' dường như được ưa chuộng hơn (dường như là trường hợp đôi khi xung quanh Xcode 6, và mọi thứ bắt đầu phá vỡ trong PackageApplication xung quanh Xcode 7). Đáng buồn thay, các bộ chức năng không giống nhau; có vẻ khó để có được một hồ sơ cung cấp cụ thể được sử dụng nếu nó chưa được thiết lập trong pbxproj khi sử dụng '-exportArchive'. – leander

Các vấn đề liên quan