Posts match “ Xcodebuild ” tag:

執行Shell Script打包.ipa檔案

最近學習用Jenkins把iOS開發整個串起來,奇怪的是Jenkins的XCode plugin一直沒辦法打包.ipa檔案,所以就改用執行Shell Script的方式來做。

目標是只用最少檔案產生.ipa檔案

  1. source code
  2. adhoc.mobileprovision
  3. adhoc.sh

原理

因為.mobileprovision檔案裡面有完整的描述,包含所有Build & Archive會用到的參數

  1. PROFILE_NAME
  2. UUID
  3. CODE_SIGN_IDENTITY

檔案配置

因為下列原因,所以把.mobileprovision與build script跟source code放在一起

1. Bundle id與帳號轉換

為了未來置換.mobileprovision檔案(從企業版帳號換到一般帳號)

2. 測試Build script功能

要先確定在local端執行script可以正確的Build出能安裝的.ipa檔案

遇到的問題

1. Build過但是不能安裝

之前有試著把CODE_SIGN_IDENTITY這個參數拿掉,我原本以為Xcodebuild會聰明的拿.mobileprovision內的資料自動去比對,因為他Build沒出錯但最後的.ipa卻不能安裝。

2. 從.mobileprovision抓取CODE_SIGN_IDENTITY

因為這個是一個base64的data,所以在抓取過程中遇到許多挫折,後來找到一個gist卻因為看不動複雜的linux指定而放棄,後來我試著改用application-identifier作為CODE_SIGN_IDENTITY竟然成功了!

剩下就是Build script了~

adhoc.sh

#!/bin/bash

# 使用者參數
PROJECT_NAME="jenkinsdemo"
PROFILE="adhoc.mobileprovision"

function NSLog(){
    clear
    MESSAGE=$1
    echo "$(tput setaf 220)\n ${MESSAGE} \n$(tput sgr 0)"
}


## 確認參數
NSLog "** CHECK PARAMETERS **"

# 沒給ProjectName則用FolderName
if [[(-z "$PROJECT_NAME")]]
then
    PROJECT_NAME=${PWD##*/}
fi

# 沒給ProvisioningProfile從檔案拿
if [[(-z "${PROFILE}")]]
then
    echo "\n$(tput setaf 1)  缺少ProvisioningProfile\n"
    exit 0
fi

## 系統參數
BUILD_PATH="JenkinsBuild"
IPA_FILE="${PROJECT_NAME}.ipa"
ARCHIVE_FILE="${PROJECT_NAME}.xcarchive"

# Error Log檔案
BUILD_ERROR_FILE=build_errors.log

ARCHIVE_PATH="./${BUILD_PATH}/${ARCHIVE_FILE}"
EXPORT_PATH="./${BUILD_PATH}/${IPA_FILE}"

# Provisioning Profile
PROFILE_DATA=$(security cms -D -i ${PROFILE})
PROVISIONING_PROFILE_NAME=$(/usr/libexec/PlistBuddy -c 'Print :Name' /dev/stdin <<< $PROFILE_DATA)
UUID=$(/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $PROFILE_DATA)
APP_ID_PREFIX=$(/usr/libexec/PlistBuddy -c 'Print :ApplicationIdentifierPrefix:0' /dev/stdin <<< $PROFILE_DATA)
CODE_SIGN_IDENTITY=$(/usr/libexec/PlistBuddy -c 'Print :Entitlements:application-identifier' /dev/stdin <<< $PROFILE_DATA)

# Copy 來源的 Provisioning Profile 至 OS
cp -rf $PROFILE ~/Library/MobileDevice/Provisioning\ Profiles/$UUID.mobileprovision

echo "PROJECT_NAME: ${PROJECT_NAME}"
echo "PROVISIONING_PROFILE: ${PROFILE}"
echo "PROFILE_NAME: ${PROVISIONING_PROFILE_NAME}"
echo "UUID: ${UUID}"
echo "CODE_SIGN_IDENTITY: ${CODE_SIGN_IDENTITY}"
echo "APP_ID_PREFIX: ${APP_ID_PREFIX}"
echo ""


## 建置前清除 
NSLog "** CLEAN BEFORE BUILD **"

xcodebuild -alltargets clean
rm -rf ${BUILD_PATH}
rm $BUILD_ERROR_FILE
mkdir ${BUILD_PATH}

## 建置與封裝
NSLog "** BUILD & ARCHIVE **"
# 可換成xcodebuild
xcodebuild \
 -scheme $PROJECT_NAME \
 archive \
 PROVISIONING_PROFILE="$UUID" \
 CODE_SIGN_IDENTITY="$CODE_SIGN_IDENTITY" \
 -archivePath ${ARCHIVE_PATH} \
 CONFIGURATION_BUILD_DIR=${BUILD_PATH} \
 2>${BUILD_ERROR_FILE} \


## 檢查建置錯誤
NSLog "** CHECK BUILD ERROR ** "

errors=`grep -wc "The following build commands failed" ${BUILD_ERROR_FILE}`
if [ "$errors" != "0" ]
then
    echo "$(tput setaf 1)BUILD FAILED. Error Log:"
    cat ${BUILD_ERROR_FILE}
    echo "$(tput sgr 0)"
    exit 0
else
    rm $BUILD_ERROR_FILE
fi

# ... continue


## 輸出IPA檔案
NSLog "** EXPORT IPA FILE **"

xcodebuild \
 -exportArchive \
 -exportFormat IPA \
 -exportProvisioningProfile $PROVISIONING_PROFILE_NAME \
 -archivePath ${ARCHIVE_PATH} \
 -exportPath ${EXPORT_PATH} \


##移除多餘檔案 
NSLog "** REMOVE UNUSED FILES **"

rm "./${BUILD_PATH}/${PROJECT_NAME}.app"
rm -rf "./${BUILD_PATH}/${PROJECT_NAME}.app.dSYM"
rm -rf ${ARCHIVE_PATH}

# ... finish all