iOSアプリのビルドスクリプトを作成

Xcodeで提供されている基本的なコマンドラインツールでiOSアプリをビルドし、AppStoreに提出する方法を記述。

# 使うコマンドラインツール

## Xcodeの選択

複数のバージョンのXcodeが入っている場合は`xcode-select -s <パス>`で使用するバージョンを選択できる。

```sh:Xcodeのパス設定
$ sudo xcode-select -s '/Applications/Xcode 8.app/Contents/Developer'
```

```sh:現在のXcodeのパス表示
$ xcode-select -p
/Applications/Xcode 8.app/Contents/Developer
```

ビルドはXcodeに含まれている`xcodebuild`を使う。

```sh:Xcodeのバージョン表示
$ xcodebuild -version
Xcode 8.0
Build version 8A218a
```

## アプリのビルド

アーカイブを作成してIPAをエクスポートする。

```sh:xcodebuildコマンド例
$ xcodebuild \
    -workspace myapp.xcworkspace \
    -scheme myapp \
    -configuration Debug \
    archive \
    -archivePath . \
    HOGE_FEATURE_DISABLE=1

# (ビルドログ省略)

$ xcodebuild \
    -exportArchive \
    -archivePath . \
    -exportPath ./build \
    -exportOptionsPlist ./build/exportOptions.plist

# (ビルドログ省略)
```

上記の例では、

- 作成されるアーカイブ：`./myapp.xcarchive`ディレクトリ。
- 作成されるIPA：`./build/myapp.ipa`。
- dSYMのありか：`./build/myapp.xcarchive/dSYMs`ディレクトリ。
- ソース内で`#if HOGE_FEATURE_DISABLE`で囲んだコードが有効。
- エクスポートパラメータである`./build/exportOptions.plist`は作るIPAの種類によって内容が違う。

### エクスポートパラメータ

`xcodebuild`のエクスポートパラメータ（`-exportOptionsPlist`）に指定するファイルはplist形式。
AppStore向けのエクスポートかどうかで指定するプロパティが別れる。

プロパティ一覧は`xcodebuild -h`で確認できる。

#### AppStoreに提出するIPA

```xml:AppStoreに提出するIPAを作成する一例
<?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>method</key>
	<string>app-store</string>
	<key>teamID</key>
	<string>XXXXXXXXXX</string>
</dict>
</plist>
```

`method`プロパティに`app-store`を指定する。

#### Enterprise、Ad Hoc等で展開するIPA

```xml:Enterprise用のIPAを作成する一例
<?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>method</key>
	<string>enterprise</string>
	<key>teamID</key>
	<string>XXXXXXXXXX</string>
	<key>compileBitcode</key>
	<false/>
	<key>embedOnDemandResourcesAssetPacksInBundle</key>
	<false/>
</dict>
</plist>
```

- `method`プロパティに`ad-hoc`、`enterprise`、`development`等が指定できる。（標準：`development`）
- bitcodeに対応していない場合、`compileBitcode`プロパティをfalseにして、一からビルドするように指摘できる。

### 

## コードの署名

`xcodebuild`でビルド中の最後の方でコードの署名（`codesign`）が発生する。
`codesign`がチームの証明書と鍵が入ったキーチェインへアクセスする際、パスワードの入力GUIが出てしまう場合がある。

次の2項目（両方）を実行しておくとGUIが出るのを回避できる模様。

- ビルド直前に、キーチェインのロック解除をする。（ロック解除は制限時間があるが、その制限時間も設定できる。）
- 鍵のアクセスを「全てのアプリケーションを許可」状態にしておく。

注意点：証明書は「常に信頼」にすると問題が発生する模様。証明書は変更せず「システムデフォルト」のままにしておく。鍵のアクセスは変更しても大丈夫な模様。

### 鍵のアクセスを「全てのアプリケーションを許可」

チームの証明書・鍵を含むp12ファイルを`-A`でキーチェインにインポートすると、全アクセス許可状態で鍵が入る。

```sh:p12ファイルをインポート（ログインキーチェインに入れる場合）
$ security import MyCertificate.p12 \
    -k ~/Library/Keychains/login.keychain \
    -P MyCertificatePassword \
    -A
```

```sh:importのヘルプ
$ security help import
Usage: import inputfile [-k keychain] [-t type] [-f format] [-w] [-P passphrase] [options...]
    -k  Target keychain to import into
#(省略)
    -A  Allow any application to access the imported key without warning (insecure, not recommended!)
```

### キーチェインのロック解除

ビルド直前にチームの証明書と鍵が入ったキーチェインをロック解除する。通常ロック解除は制限時間があるが、その制限時間も設定できる。

```sh:ロック解除（ログインキーチェインの場合）
$ security unlock-keychain -p Password ~/Library/Keychains/login.keychain
```

ロック解除の制限時間を無くす場合：

```sh:制限時間無し設定のロック解除（ログインキーチェインの場合）
$ security set-keychain-settings ~/Library/Keychains/login.keychain
$ security unlock-keychain -p Password ~/Library/Keychains/login.keychain
```

```sh:set-keychain-settingsのヘルプ
$ security help set-keychain-settings
Usage: set-keychain-settings [-lu] [-t timeout] [keychain]
    -l  Lock keychain when the system sleeps
    -u  Lock keychain after timeout interval
    -t  Timeout in seconds (omitting this option specifies "no timeout")
```

### どのキーチェインに入れるか

#### ログイン中にビルドする場合

ターミナルやSSH上やXcode上等、特定のユーザーでログインしてビルドする場合は標準キーチェインがログインキーチェインになっている。よって、ログインキーチェインに証明書と鍵が入っていれば、それらが参照される。

```sh:参照対象キーチェイン確認（ログイン中の場合）
$ security list-keychains
    "/Users/rsahara/Library/Keychains/login.keychain"
    "/Library/Keychains/System.keychain"
```

```sh:デフォルトキーチェイン確認（ログイン中の場合）
$ security default-keychain
    "/Users/rsahara/Library/Keychains/login.keychain"
```

#### launchdデーモンでビルドする場合

`launchd`デーモンの場合、システムキーチェインしか使えない初期状態になっている。
実際にビルドができた方法は次のパターン：

- ログインキーチェインに証明書と鍵を入れる方法：`launchd`デーモンの設定ファイルの`UserName`プロパティにビルドユーザーを指定し、`SessionCreate`プロパティに`true`を指定すると、そのユーザーでログイン中と同様にログインキーチェインが標準キーチェインになる。（`launchd`パラメータについては[こちら](http://qiita.com/rsahara/items/7d37a4cb6c73329d4683#%E3%81%A9%E3%81%AE%E7%92%B0%E5%A2%83%E3%81%A7%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B%E3%81%8B)に記述。）
- システムキーチェインに証明書と鍵を入れる方法：`launchd`デーモンの場合、システムキーチェインが標準キーチェインになっているので、そのまま使える。

前者のログインキーチェインを使うのが良さげだった理由：
ログインキーチェインに証明書と鍵を入れておけばXcodeでビルドするときも、上の設定で`launchd`デーモンからビルドするときでも、同じログインキーチェインにある証明書と鍵が参照されるのでテストしやすくなる利点がある。

## AppStoreにIPAをアップロード

Xcodeに含まれている`altool`（Application Loader）を使って提出できる。
パスが長いし空白が含まれてる。

```sh:altoolの場所
$ ALTOOL_ABSOLUTEPATH="$(xcode-select -p)/../Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool"
```

```sh:altoolでアプリをアップロード
$ "${ALTOOL_ABSOLUTEPATH}" --upload-app \
    --file ./build/myapp.ipa \
    --username appleid@domain.jp \
    --password password
```

```sh:altoolでアプリを検証のみ
$ "${ALTOOL_ABSOLUTEPATH}" --validate-app \
    --file ./build/myapp.ipa \
    --username appleid@domain.jp \
    --password password
```

# ビルドスクリプト一例

## ユースケース

- コマンドラインでビルドしたい。
    - 設定を簡単に編集できるようにしたい。
- 別のスクリプトからも呼び出したい（BOTやlaunchdで定期ビルド等）。
    - 呼び出し側から設定を指定できるようにしたい。
- ビルドログが見れるようにしたい（でも基本的にログは見たくない）。

## 入れる機能

- 設定が足りない場合やおかしいときはすぐに分かる。
- タイムアウトを付ける（ついでにビルド時間が分かる）。
    - 意図：通信ができない等でエラーは出ないけど止まるときがあるため。
- 結果はJSON形式で返せる。
    - 意図：IPAファイルのパス等を呼び出し側は知りたい。
- Xcodeのバージョンが合っているかチェック。
    - 意図：プロジェクトごとに違う場合がある。
- ビルド前にスクリプトを指定して実行できる。
    - 意図：ライブラリの準備（`pod repo update; pod install`）やXcodeバージョンの選択（`xcode-select -p <パス>`）やキーチェインのロック解除（`security unlock-keychain -p <パスワード> <キーチチェインファイル>`）が事前にできる。
- ビルド後にスクリプトを指定して実行できる。
    - 意図：dSYMをバグトラッカーに提出、IPAをAppStoreに提出したりコピーする等の用途のため。
- ファイル名にアプリのバージョンとビルド時間を指定できる：
    - 例：出力ファイル名`app_#VERSION#_#DATETIME#.ipa`と指定したら、`app_1.0.0_20170118_1206.ipa`が作成される。
- ビルド設定は環境変数で渡す。
    - スクリプトの中で設定を簡単に編集できるようにする：`SETTING=VALUE`を上の方に書く。
    - 別スクリプトで設定を指定するときは同じ方法で統一：`SETTING=VALUE`してから`source build.sh`。
    - 外部からスクリプトを呼び出す場合は：`SETTING=VALUE; export SETTING; build.sh`。

## 環境

- ソースが取得できる。
    - SSHを使う場合、SSHキー等が設定されている。
- Xcodeが入っている。
    - 複数バージョンを入れている場合は`xcode-select`で事前に設定するか、ビルド前にスクリプトを実行する機能を利用して設定する。
- 必要なプロビジョニングプロファイルがXcodeに入っている。
- チームの証明書と鍵が参照対象のキーチェインに入っている。
    - ビルド前にスクリプトを実行する機能を利用してそのキーチェインをロック解除できる。
- ビルドでexportOptionsPlistに指定するplistファイルがどこかにある　（ソースに含まれている、又はどこかアクセス可能な固定のパスにある）。

## ベーススクリプト

```sh:build.sh
#!/bin/bash

# ===
# Copyright 2017 Runo Sahara
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ===

set -e

# === QUICK SETTINGS

#BUILD_USEQUICKSETTINGS="YES" # Uncomment this line if you want to use the quick settings below.

[ -z "$BUILD_USEQUICKSETTINGS" ] || {

# - Required settings.

# Source to build, specified by a git url and branch name (recommended),
BUILD_GIT_URL="https://github.com/rsahara/project.git"
BUILD_GIT_BRANCH="master"

# or directly by a script to deploy the source in $BUILD_SRC_DIR of the current directory.
#BUILD_DEPLOYSCRIPT='git clone -b "$BUILD_GIT_BRANCH" "$BUILD_GIT_URL" "$BUILD_SRC_DIR"'

# Xcode configuration (Debug, Release, etc...).
BUILD_XCODE_CONFIGURATION="Debug"

# Path to a plist file containing the export options, relative to the root of the repository.
BUILD_EXPORTOPTIONS_PATH="build/exportOptions.plist"

# The project files can be specified by the project name (recommended),
BUILD_PROJECTNAME="testproject"

# or with the actual file paths and scheme.
#BUILD_WORKSPACE_PATH="$BUILD_PROJECTNAME.xcworkspace"
#BUILD_ARCHIVE_PATH="$BUILD_PROJECTNAME.xcarchive"
#BUILD_IPA_PATH="$BUILD_PROJECTNAME.ipa"
#BUILD_XCODE_SCHEME="$BUILD_PROJECTNAME"

# - The output file. (Optional)

# #VERSION# will be replaced with the app version, #DATETIME# with the current datetime.
#BUILD_OUTPUT_FORMAT="${BUILD_PROJECTNAME}_#VERSION#_#DATETIME#.ipa"

# Path to the Info.plist file of the project. Required if #VERSION# is used in BUILD_OUTPUT_FORMAT.
#BUILD_INFOPLIST_PATH=""

# - Other settings. (Optional)

# Pre-build script to be executed right before the build command, in the source directory.
#BUILD_PREBUILDSCRIPT="pod update; security unlock-keychain -p password"

# Post-build script to be executed after the build is done, in the source directory. (${BUILD_SUCCEEDED} is set to "YES" if the build succeeded.)
#BUILD_POSTBUILDSCRIPT=""

# Verify that the correct version of Xcode is being used.
#BUILD_XCODE_VERSION="8.0"

# Additional parameter to be added to the build command line of xcodebuild.
#BUILD_XCODE_PARAM="DEBUG_TEST=1"

# Show the result in JSON dictionary like format.
#BUILD_JSONRESULT="YES"

# Print the settings and don't build.
#BUILD_PRINTSETTINGSONLY="YES"

# Specify the build directory, rather than letting the script use a random temporary directory.
#BUILD_DIR_ABSOLUTEPATH="/tmp/build"

# Specify the timeout in seconds. (Default: 1000 seconds)
#BUILD_TIMEOUT="1000"

}

# === LOAD SETTINGS

BUILD_JSONRESULTEMPTY="YES"
BUILD_SUCCEEDED="NO"
function build_print() {
	if [ "$BUILD_JSONRESULT" = "YES" ]; then
		if [ "$BUILD_JSONRESULTEMPTY" = "YES" ]; then
			printf "\"$1\":\"$2\""
			BUILD_JSONRESULTEMPTY="NO"
		else
			printf ",\n\"$1\":\"$2\""
		fi
	else
		echo "$1: $2"
	fi
}

function build_setting_require() {
	[ ! -z "${!1}" ] || { echo "$1 not set" >&2 && exit 1; }
}
function build_setting_default() {
	local default=$2
	[ ! -z "${!1}" ] || eval "$1"=\"\$default\"
}
function build_setting_print() {
	build_print "$1" "${!1}"
}

build_setting_default BUILD_JSONRESULT "NO"

if [ -z "$BUILD_GIT_URL" ]; then
	build_setting_require BUILD_DEPLOYSCRIPT
else
	build_setting_default BUILD_GIT_BRANCH "master"
	build_setting_default BUILD_DEPLOYSCRIPT 'git clone -b "$BUILD_GIT_BRANCH" "$BUILD_GIT_URL" "$BUILD_SRC_DIR"'
fi

build_setting_require BUILD_XCODE_CONFIGURATION
build_setting_require BUILD_EXPORTOPTIONS_PATH

build_setting_default BUILD_PREBUILDSCRIPT ""
build_setting_default BUILD_SRC_DIR "build"
[ ! -z "$BUILD_DIR_ABSOLUTEPATH" ] || BUILD_DIR_ABSOLUTEPATH=`mktemp -d`
BUILD_WORKINGDIR_ABSOLUTEPATH="$(pwd)"
build_setting_default BUILD_DATETIME $(date +"%Y%m%d_%H%M")
build_setting_default BUILD_INFOPLIST_PATH ""
build_setting_default BUILD_XCODE_PARAM ""
build_setting_default BUILD_BUILD_PROJECTNAME "projectname"
build_setting_default BUILD_XCODE_SCHEME "$BUILD_PROJECTNAME"
build_setting_default BUILD_WORKSPACE_PATH "$BUILD_PROJECTNAME.xcworkspace"
build_setting_default BUILD_ARCHIVE_PATH "$BUILD_PROJECTNAME.xcarchive"
build_setting_default BUILD_IPA_PATH "$BUILD_PROJECTNAME.ipa"
build_setting_default BUILD_OUTPUT_FORMAT "${BUILD_PROJECTNAME}_#VERSION#_#DATETIME#.ipa"
build_setting_default BUILD_TIMEOUT "1000"
build_setting_default BUILD_PRINTSETTINGSONLY "NO"

build_setting_print BUILD_DIR_ABSOLUTEPATH
build_setting_print BUILD_JSONRESULT
build_setting_print BUILD_WORKINGDIR_ABSOLUTEPATH
build_setting_print BUILD_DATETIME
[ -z "$BUILD_GIT_URL" ] || build_setting_print BUILD_GIT_URL
[ -z "$BUILD_GIT_BRANCH" ] || build_setting_print BUILD_GIT_BRANCH
build_setting_print BUILD_SRC_DIR
build_setting_print BUILD_XCODE_CONFIGURATION
build_setting_print BUILD_XCODE_PARAM
build_setting_print BUILD_INFOPLIST_PATH
build_setting_print BUILD_XCODE_SCHEME
build_setting_print BUILD_WORKSPACE_PATH
build_setting_print BUILD_ARCHIVE_PATH
build_setting_print BUILD_IPA_PATH
build_setting_print BUILD_EXPORTOPTIONS_PATH
build_setting_print BUILD_TIMEOUT

# === BUILD

BUILD_REMAININGTIME="$BUILD_TIMEOUT"

# Prepare build directory.
{
	[ "$BUILD_PRINTSETTINGSONLY" == "YES" ] || {
		rm -fr "$BUILD_DIR_ABSOLUTEPATH"
		rm -f "$BUILD_LOG_ABSOLUTEPATH"
	}

	dirname "$BUILD_LOG" | xargs mkdir -p
	mkdir -p "$BUILD_DIR_ABSOLUTEPATH"
	BUILD_LOG_ABSOLUTEPATH=`mktemp ${BUILD_DIR_ABSOLUTEPATH}/build.${BUILD_DATETIME}.XXXXXX`

} &> /dev/null

build_setting_print BUILD_LOG_ABSOLUTEPATH

# Build on another process.
BUILD_BEGINTIME=$(date +%s)
{
	[ -z "$BUILD_XCODE_VERSION" ] || {
		[ "Xcode $BUILD_XCODE_VERSION" = "`xcodebuild -version | head -n 1`" ] || { echo "Xcode version mismatch" >&2 && exit 1; }
	}

	[ "$BUILD_PRINTSETTINGSONLY" != "YES" ] || exit 0

	cd "$BUILD_DIR_ABSOLUTEPATH"
	eval "$BUILD_DEPLOYSCRIPT"

	cd "$BUILD_DIR_ABSOLUTEPATH/$BUILD_SRC_DIR"
	[ -z "$BUILD_PREBUILDSCRIPT" ] || eval "$BUILD_PREBUILDSCRIPT"

	cd "$BUILD_DIR_ABSOLUTEPATH/$BUILD_SRC_DIR"
	eval xcodebuild -workspace "$BUILD_WORKSPACE_PATH" \
-scheme "$BUILD_XCODE_SCHEME" \
-configuration "$BUILD_XCODE_CONFIGURATION" \
archive \
-archivePath "$BUILD_ARCHIVE_PATH" \
"$BUILD_XCODE_PARAM"

	eval xcodebuild -exportArchive \
-archivePath "$BUILD_ARCHIVE_PATH" \
-exportPath "$BUILD_DIR_ABSOLUTEPATH" \
-exportOptionsPlist "$BUILD_EXPORTOPTIONS_PATH" \
"$BUILD_XCODE_PARAM"

} >> "$BUILD_LOG_ABSOLUTEPATH" 2>&1 &

BUILD_WAITINGPROCESSID=$!
while [ $BUILD_REMAININGTIME -gt 0 ]; do
	sleep 1
	kill -0 $BUILD_WAITINGPROCESSID &> /dev/null || break
	BUILD_REMAININGTIME=$(($BUILD_REMAININGTIME - 1))
done

# Get build results.
if [ -f "$BUILD_DIR_ABSOLUTEPATH/$BUILD_IPA_PATH" ]; then

	{
		BUILD_VERSION="unknown"
		if [ ! -z "$BUILD_INFOPLIST_PATH" ]; then
			BUILD_INFOPLIST_ABSOLUTEPATH="$BUILD_DIR_ABSOLUTEPATH/$BUILD_SRC_DIR/$BUILD_INFOPLIST_PATH"
			BUILD_VERSION=$(defaults read "${BUILD_INFOPLIST_ABSOLUTEPATH%.plist}" CFBundleShortVersionString)
		fi

		BUILD_OUTPUT="$BUILD_OUTPUT_FORMAT"
		BUILD_OUTPUT="${BUILD_OUTPUT//#VERSION#/$BUILD_VERSION}"
		BUILD_OUTPUT="${BUILD_OUTPUT//#DATETIME#/$BUILD_DATETIME}"
		cp "$BUILD_DIR_ABSOLUTEPATH/$BUILD_IPA_PATH" "$BUILD_WORKINGDIR_ABSOLUTEPATH/$BUILD_OUTPUT"

		BUILD_SUCCEEDED="YES"
	} &> /dev/null

	build_setting_print BUILD_VERSION
	build_setting_print BUILD_OUTPUT

fi

# Post-build script on another process.
if [ $BUILD_REMAININGTIME -gt 0 ] && [ ! -z "$BUILD_POSTBUILDSCRIPT" ]; then

	{
		cd "$BUILD_DIR_ABSOLUTEPATH/$BUILD_SRC_DIR"
		eval "$BUILD_POSTBUILDSCRIPT"
	} >> "$BUILD_LOG_ABSOLUTEPATH" 2>&1 &

	BUILD_WAITINGPROCESSID=$!
	while [ $BUILD_REMAININGTIME -gt 0 ]; do
		sleep 1
		kill -0 $BUILD_WAITINGPROCESSID &> /dev/null || break
		BUILD_REMAININGTIME=$(($BUILD_REMAININGTIME - 1))
	done

fi

# Check timeout.
if [ ! $BUILD_REMAININGTIME -gt 0 ]; then
	kill -s SIGKILL $BUILD_WAITINGPROCESSID &> /dev/null
	echo "Timed out" >> "$BUILD_LOG_ABSOLUTEPATH"
fi

# === RESULT
build_setting_print BUILD_SUCCEEDED

BUILD_ENDTIME=$(date +%s)
BUILD_TIME=$(($BUILD_ENDTIME - $BUILD_BEGINTIME))
build_print "BUILD_TIME" "$BUILD_TIME"

[ "$BUILD_JSONRESULT" != "YES" ] || echo
```

Github：https://github.com/rsahara/iosbuild.git

## 派生スクリプト

ベーススクリプトから必要に応じて内容を特化した別スクリプトを派生できる。
例：developブランチをビルドし、成功したらAppStoreにアップロード、クラッシュ調査用のdSYMを処理。

```sh:refresh-appstore.sh
#!/bin/bash

BUILD_GIT_BRANCH="develop"

SCRIPT_ABSOLUTEPATH="$(cd $(dirname $0) && pwd)"
ALTOOL_ABSOLUTEPATH="$(xcode-select -p)/../Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool"

BUILD_GIT_URL="https://github.com/rsahara/project.git"
BUILD_XCODE_CONFIGURATION="Release"
BUILD_EXPORTOPTIONS_PATH="build/exportOptionsAppStore.plist"
BUILD_PROJECTNAME="myapp"
BUILD_OUTPUT_FORMAT="myapp_appstore_#VERSION#_#DATETIME#.ipa"
BUILD_INFOPLIST_PATH="myapp/Info.plist"
BUILD_DIR_ABSOLUTEPATH="/tmp/build/myapp"

BUILD_PREBUILDSCRIPT="pod update; security unlock-keychain -p XXXXXXXX ~/Library/Keychains/login.keychain"

BUILD_POSTBUILDSCRIPT='\
if [ $BUILD_SUCCEEDED = "YES" ]; then \
	echo "Uploading to Smartbeat..."; \
	${SCRIPT_ABSOLUTEPATH}/../upload_smartbeat.sh \
		"$BUILD_DIR_ABSOLUTEPATH/$BUILD_SRC_DIR/$BUILD_ARCHIVE_PATH/dSYMs/myapp.app.dSYM" || true; \
\
	echo "Uploading to App Store..."; \
	"${ALTOOL_ABSOLUTEPATH}" --upload-app \
		--file "$BUILD_DIR_ABSOLUTEPATH/$BUILD_IPA_PATH" \
		--username appleid@domain.jp \
		--password password || BUILD_SUCCEEDED="NO"; \
fi \
'

BUILD_JSONRESULT="YES"

echo {
source "$SCRIPT_ABSOLUTEPATH/../build.sh"
echo }
```

# 参照

- [security(1) Mac OS X Manual Page - Apple Developer](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/security.1.html)
- [Jenkinsでcodesignの失敗 - StackOverflow](http://stackoverflow.com/questions/16550594/jenkins-xcode-build-works-codesign-fails)
- [launchdにSessionCreateプロパティの存在 - StackOverflow](http://stackoverflow.com/a/9482707/4518606)
- [証明書に「常に信頼」問題 - StackOverflow](http://stackoverflow.com/a/30120228/4518606)