Travis CIで配布可能なIPAを作成して配布する

このドキュメントでは、Travis CIで配布可能なIPAを作成するための手順について説明します。
大まかな手順は以下の通りです。

* 配布用の証明書・Provisioning Profile等を暗号化してアップロードする
* IPAをビルドするためのコマンドを追加する
  * 証明書・Provisioning Profileのインストール
  * xcodebuildの実行
  * 証明書・Provisioning Profileのアンインストール
* IPAの配布サービスに応じてアップロードの設定を追加する

ネタ元は[こちら](http://www.objc.io/issue-6/travis-ci.html)。

# 事前準備
## 必要なリソース
### インストールしておくもの
以下のものをインストールしておく必要があります。

* Xcode + Xcode Command Line Tool
* git
* OpenSSL
* Ruby + gem(rake, travis)

### 必要なファイル一式
配布用のIPAを作成するため、以下のものを準備します。

* [Appleの証明書](http://developer.apple.com/certificationauthority/AppleWWDRCA.cer)
* 配布用の証明書（秘密鍵も）
* 配布用のProvisioning Profile

証明書はキーチェーンから書き出してください。

## 証明書などの暗号化
配布するための証明書やProvisioning ProfileはGithubに登録する必要があります。
ただ、何もせずに登録すると悪用される可能性がありますので暗号化した状態のファイルをアップロードしましょう。

この例では、<プロジェクトのルート>/script以下にcertsとprofilesというフォルダを作成し、そこに暗号化したファイルを保存することとします。

```zsh:証明書の暗号化
openssl aes-256-cbc -k "foo" -in scripts/profile/Sample.mobileprovision -out scripts/profile/Sample.mobileprovision.enc -a
openssl aes-256-cbc -k "foo" -in scripts/certs/cert.cer -out scripts/certs/cert.cer.enc -a
openssl aes-256-cbc -k "foo" -in scripts/certs/cert.p12 -out scripts/certs/cert.p12.enc -a

git add scripts/profile/Sample.mobileprovision.enc
git add scripts/certs/cert.cer.enc
git add scripts/certs/cert.p12.enc
git add scripts/certs/apple.cer
```

## Travisの環境をセットアップする
[公式のドキュメント](http://docs.travis-ci.com/user/getting-started/)を参考に、TravisでCIできる環境をセットアップしてください。

# Travis上でIPAをビルドする
## 証明書・Provisioing Profileを復号するパスワードを.travis.ymlに追加する
復号するためのパスワードは、.travis.ymlに環境変数として追加する必要があります。
このパスワードも、平文のままだと悪用されかねませんので、travisのgemを使って暗号化します。

```zsh:復号するためのパスワードを設定
travis encrypt "DECORD_CERTS=foo" --add
```

.travis.ymlのenv:global:セクションに以下のような行が追加されればOKです。

```yaml
env:
  global:
  - secure: xxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

## 証明書インストールに必要なパスワードを.travis.ymlに追加する
証明書のインストールに必要なパスワードも、暗号化して.travis.ymlに追加します。

```zsh:証明書をインストールするためのパスワードを設定
travis encrypt "CERTS_PASS=bar" --add
```

## 証明書をTravis上のキーチェーンにインストール・アンインストールする処理を追加する
この例では、証明書周りのインストールやアンインストールの処理をスクリプトで実行します。
あくまで例ですので、Rakefileなどに書いてもらっても構いません。

### インストール用スクリプトの追加
証明書やProvisioning Profileを復号化し、VM上のキーチェーンにインストールするスクリプトを追加します。

```zsh:install_certs.sh
#!/bin/sh

# 証明書・Provisioning Profileを復号
openssl aes-256-cbc -k $DECORD_CERTS -in scripts/profile/Sample.mobileprovision.enc -d -a -out scripts/profile/Sample.mobileprovision
openssl aes-256-cbc -k $DECORD_CERTS -in scripts/certs/cert.cer.enc -d -a -out scripts/certs/cert.cer
openssl aes-256-cbc -k $DECORD_CERTS -in scripts/certs/cert.p12.enc -d -a -out scripts/certs/cert.p12

# VM上にキーチェーンを作成
# なぜこんな手順を踏むかは↓を参照
# http://docs.travis-ci.com/user/common-build-problems/#Mac%3A-Code-Signing-Errors
security create-keychain -p travis ios-build.keychain
security default-keychain -s ios-build.keychain
security unlock-keychain -p travis ios-build.keychain
security set-keychain-settings -t 3600 -l ~/Library/Keychains/ios-build.keychain

# キーチェーンに証明書を追加する
security import ./scripts/certs/apple.cer -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
security import ./scripts/certs/cert.cer -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
security import ./scripts/certs/cert.p12 -k ~/Library/Keychains/ios-build.keychain -P $CERTS_PASS -T /usr/bin/codesign

# Provisioning Profileを保存する
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp "./scripts/profile/Sample.mobileprovision" ~/Library/MobileDevice/Provisioning\ Profiles/
```

もちろん```chmod a+x```で実行できるようにしておきましょう。

### アンインストール用スクリプトの追加
アンインストール用のスクリプトも追加しましょう。

```zsh:uninstall_certs.sh
#!/bin/sh
security delete-keychain ios-build.keychain
rm -f "~/Library/MobileDevice/Provisioning Profiles/Sample.mobileprovision"
```
### IPAをビルドするスクリプトを追加する
masterブランチにコミットしたときだけIPAを作成するよう、スクリプトを追加します。

```zsh:build_ipa.sh
#!/bin/sh
if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then
  exit 0
fi
if [[ "$TRAVIS_BRANCH" != "master" ]]; then
  exit 0
fi

rm -rf ./build/*
xcodebuild -project Sample.xcodeproj -scheme Sample -sdk iphoneos -configuration Release CODE_SIGN_IDENTITY='iPhone certribution: Your Name' archive -archivePath ./build/Sample.xcarchive
xcodebuild -exportArchive -exportFormat IPA -archivePath ./build/Sample.xcarchive -exportPath ./build/Sample.ipa -exportProvisioningProfile 'Sample'
```
### .travis.ymlに呼び出す処理を追加
もろもろのスクリプトが準備できたら、.travis.ymlから呼び出すよう変更します。

```yaml:.travis.yml
before_script:
- ./scripts/install_certs.sh
script:
- zsh:build_ipa.sh
after_success:
after_script:
- ./scripts/uninstall_certs.sh
```

ここまでの変更をGithubにPushすると、VM上の```<プロジェクトのルートディレクトリ>/build/```に```Sample.ipa```が保存されます。

# ビルドしたIPAを配布する
IPAが作成できても、このままでは使えないので外部サービスにアップロードします。

## TestFlightにアップロードする

### TestFlightのAPI Token、Team Tokenを.travis.ymlに追加する
TestFlightにアップロードするためにはAPI TokenとTeam Tokenが必要です。
例によって暗号化して追加しておきます。

```zsh:TestFlightのアップロード準備
travis encrypt "TESTFLIGHT_API_TOKEN=hoge" --add
travis encrypt "TESTFLIGHT_TEAM_TOKEN=fuga" --add
```

### TestFlightにアップロードするスクリプトを追加する

```zsh:upload_to_testflight.sh
#!/bin/sh
curl http://testflightapp.com/api/builds.json \
  -F file="@build/Sample.ipa" \
  -F dsym="@build/Sample.app.dSYM.zip" \
  -F api_token="$TESTFLIGHT_API_TOKEN" \
  -F team_token="$TESTFLIGHT_TEAM_TOKEN" \
  -F certribution_lists='Internal' \
  -F notes="Sample Upload"
```

```upload_to_testflight.sh``` は、```.travis.yml``` の ```after_success:``` あたりに呼び出す処理を追加しましょう。

他のツールやサービスを使いたいという場合は、そのリファレンスを参考に書いてみてください。

# 参考にしたもの
[Objc ↑↓: Travis CI for iOS](http://www.objc.io/issue-6/travis-ci.html)
## 参考にしたTravis CIの公式ドキュメント
[Building an Objective-C Project](http://docs.travis-ci.com/user/languages/objective-c/)
[The Build Enviornment - Environment common to all VM images](http://docs.travis-ci.com/user/ci-environment/#Environment-common-to-all-VM-images)
[Encrypting Files](http://docs.travis-ci.com/user/encrypting-files/)
[Mac: Code Signing Errors](http://docs.travis-ci.com/user/common-build-problems/#Mac%3A-Code-Signing-Errors)