iOS アプリの継続ビルドを CircleCI に変更した
iOS アプリの継続ビルドを CircleCI に変更した
長瀬 敦史
2015-03-23 21:40
今まで Travis CI で設定していた iOS アプリのビルドを CircleCI に変更しました。
現在、iOS ビルドの機能は Experimental Settings として提供されています。
https://circleci.com/mobile
TOC
環境変数
件のアプリのソースコードは、GitHub 上の公開リポジトリで管理しているため、鍵やプロビジョニングファイルは、バージョン管理に追加したくありませんでした。
その為、各種設定を Dashboard の環境設定 (Project Settings > Environment variables ) から追加しました。
Name
Description
APPLE_AUTHORITY_BASE64
Apple Worldwide Developer Relations Certification Authority の Base64
DEPLOYGATE_API_TOKEN
Deploy Gate の アカウント API Key
DEPLOYGATE_USERNAME
Deploy Gate のユーザー名
DEVELOPER_NAME
開発者名 (= Distribution 証明書の Common Name) 例: iPhone Distribution: LittleApps Inc. (3Y8APYUG2G)
DISTRIBUTION_CERTIFICATE_BASE64
Distribution 証明書 Base64 エンコード
DISTRIBUTION_KEY_BASE64
Distribution 鍵 Base64 エンコード
ITUNES_CONNECT_ACCOUNT
iTunes Connect のログイン ID (Email)
ITUNES_CONNECT_PASSWORD
iTunes Connect のパスワード
KEY_PASSWORD
Distribution 鍵のパスワード
ONAIRLOG802_DEPLOYGATE_DISTRIBUTION_KEY
Deploy Gate のアプリ側 API Key (802 用)
ONAIRLOG802_PROFILE_UUID
プロビジョニングファイル UUID (802 用)
ONAIRLOG813_DEPLOYGATE_DISTRIBUTION_KEY
Deploy Gate のアプリ側 API Key (813 用)
ONAIRLOG813_PROFILE_UUID
プロビジョニングファイル UUID (813 用)
ONAIRLOG_BITLY_ACCESS_TOKEN
Bitly のアクセストークン
依存ライブラリのインストール
bundle install
と pod install
は CircleCI が検知して、設定せずとも実行してくれます。
鍵と証明書の読み込み
前途の通り、証明書と鍵は Base64 エンコードして環境変数に設定し、dependency.post
でデコード、ファイル書き込み、キーチェーンへの追加を行っています。
自身の証明書と Apple Worldwide Developer Relations Certification Authority を Keychain Access.app で検索し、右クリックでエクスポートします。
以下のコマンドで Base64 エンコードしたコンテンツをクリップボードにコピーし、CircleCI の Project Settings に追加します。
cat ~/Desktop/Certificates.cer|base64|pbcopy
取り込み側のスクリプトです
DIR = tmp/certs
KEYCHAIN = $HOME /Library/Keychains/ios-build.keychain
KEYCHAIN_PASSWORD = ` openssl rand -base64 48`
rm -rf $DIR
mkdir -p $DIR
echo $APPLE_AUTHORITY_BASE64 | base64 -D > $DIR /apple.cer
echo $DISTRIBUTION_KEY_BASE64 | base64 -D > $DIR /dist.p12
echo $DISTRIBUTION_CERTIFICATE_BASE64 | base64 -D > $DIR /dist.cer
security create-keychain -p " $KEYCHAIN_PASSWORD " ios-build.keychain
security import $DIR /apple.cer -k $KEYCHAIN -T /usr/bin/codesign
security import $DIR /dist.cer -k $KEYCHAIN -T /usr/bin/codesign
security import $DIR /dist.p12 -k $KEYCHAIN -T /usr/bin/codesign -P " $KEY_PASSWORD "
security list-keychain -s $KEYCHAIN
security unlock-keychain -p " $KEYCHAIN_PASSWORD " $KEYCHAIN
rm -rf $DIR
プロビジョニングファイルのダウンロード
プロビジョニングのダウンロードには nomad シリーズの cupertino を使います。
bundle exec ios profiles:download:all --type distribution -u " $ITUNES_CONNECT_ACCOUNT " -p " $ITUNES_CONNECT_PASSWORD " > /dev/null 2>&1
mkdir MobileProvisionings
mv * .mobileprovision MobileProvisionings
以下のスクリプトで UUID のファイル名に変更し、Library
ディレクトリに移動します。
BASE = ~/Library/MobileDevice/Provisioning\ Profiles
mkdir -p " $BASE "
for file in MobileProvisionings/* .mobileprovision; do
uuid = ` grep UUID -A1 -a " $file " | grep -io "[-A-Z0-9] \{ 36 \} " `
extension = " ${ file ##*. } "
echo " $file -> $uuid "
cp -f " $file " " $BASE / $uuid . $extension "
done
ls -lsa " $BASE "
環境変数のエクスポート
Bitly のアクセストークンなど、アプリ固有の、バージョン管理に追加したくない変数は、環境変数から Environment.swift
ファイルに書き出します。
# Rakefile
namespace :env do
desc 'Generate Environment.swift'
task :export => :dotenv do
prefix = " #{ APP_NAME . upcase } _"
code = ''
ENV . each { | k , v |
if k . start_with? ( prefix )
code += %Q{let #{ k . sub prefix , '' } = " #{ v } " \n }
end
}
file = File . join __dir__ , APP_NAME , 'Environment.swift'
File . write file , code
end
end
bundle exec rake env :export
テスト実行
XCODE_WORKSPACE
, XCODE_SCHEME
だけを環境変数に設定して、CircleCI 既定のテストコマンドを実行しています。
# circle.yml 抜粋
machine :
environment :
XCODE_SCHEME : OnAirLogTests
XCODE_WORKSPACE : OnAirLog.xcworkspace
AdHoc ビルド
ビルドとデプロイには、nomad シリーズの shenzhen を使います。
shenzhen と cupertino で、依存している commander のバージョンがコンフリクトしていたので、フォークして修正したものを使っています。
# Gemfile
gem 'cupertino' , github: 'ngs/cupertino' , branch: 'fix-conflict-commander'
gem 'shenzhen' , '0.13.1'
参照: Fix conflicting commender version with shenzhen #193 on nomad/cupertino
複数のアプリをビルドするので、circle.yml のビルドプロセス定義のところで、個別に変数名を設定します。
- /bin/bash Scripts/build-adhoc.sh :
environment :
APPNAME : OnAirLog813
DEPLOYGATE_DISTRIBUTION_KEY : $ONAIRLOG813_DEPLOYGATE_DISTRIBUTION_KEY
- /bin/bash Scripts/build-adhoc.sh :
environment :
APPNAME : OnAirLog802
DEPLOYGATE_DISTRIBUTION_KEY : $ONAIRLOG802_DEPLOYGATE_DISTRIBUTION_KEY
shenzhen の ipa build
コマンドで --embed
引数で AdHoc 用プロビジョニングファイルを指定して、ビルドします。
bundle exec ipa build \
--workspace " $XCODE_WORKSPACE " \
--scheme " $APPNAME " \
--configuration Release \
--destination Distribution/AdHoc \
--embed MobileProvisionings/${ APPNAME } AdHoc.mobileprovision \
--identity " $DEVELOPER_NAME "
DeployGate へデプロイ
shenzhen の ipa distribute:deploygate
コマンドでデプロイします。
bundle exec ipa distribute:deploygate \
--file Distribution/AdHoc/${ APPNAME } .ipa \
--api_token $DEPLOYGATE_API_TOKEN \
--distribution_key $DEPLOYGATE_DISTRIBUTION_KEY \
--release_note $RELEASE_NOTE \
--visibility public \
--user_name $DEPLOYGATE_USERNAME
Release ビルド作成
shenzhen の ipa build
コマンドで --embed
引数で Distribution 用プロビジョニングファイルを指定して、ビルドします。
bundle exec ipa build \
--workspace " $XCODE_WORKSPACE " \
--scheme " $APPNAME " \
--configuration Release \
--destination Distribution/Release \
--embed MobileProvisionings/${ APPNAME } Distribution.mobileprovision \
--identity " $DEVELOPER_NAME "
iTunes Connect へデプロイ (WIP)
最後に、master
ブランチへのマージを契機に、iTunes Connect への配布を行おうとしました。
しかし、日本時間 2015-03-24 02:50 まで iTunes Connect の障害でメールが届かなかった ので、CI 用のアカウントを作成できず、断念していました。
ローカルで shenzhen の ipa distribute:itunesconnect
コマンドで通信できることを確認しました。
bundle exec ipa distribute:itunesconnect \
--warnings --errors \
--file Distribution/Release/${ APPNAME } .ipa \
--account $ITUNES_CONNECT_ACCOUNT \
--password $ITUNES_CONNECT_PASSWORD \
--apple-id $APPLE_ID
もう一つ問題があり、既にリリース済みのバージョンの場合、 The train version '2.1.0' is closed for new build submissions
というエラーレスポンスが返ってきます。
Package Summary:
1 package(s) were not uploaded because they had problems:
/Users/ngs/src/onairlog-ios/Package.itmsp - Error Messages:
ERROR ITMS-90189: "Redundant Binary Upload. There already exists a binary upload with build '157' for version '2.1.0'"
ERROR ITMS-90186: "Invalid Pre-Release Train. The train version '2.1.0' is closed for new build submissions"
ERROR ITMS-90062: "This bundle is invalid. The value for key CFBundleShortVersionString [2.1.0] in the Info.plist file must contain a higher version than that of the previously approved version [2.1.0]."
Build 番号が同じである、There already exists a binary upload with build '157' for version '2.1.0'
というエラーについては、
CircleCI のビルド番号 $CIRCLE_BUILD_NUM
を使う様にタスクを追加する予定です。
解決案として、新バージョンリリース後、すぐに次バージョンの準備を iTunes Connect 側で行い、Info.plist のバージョンも上げる運用にしようかと思います。
2015/04/05 追記
上記のとおり、設定すると iTunes Connect に配布できました。
Xcode 6.2
OnAirLog は Apple Watch 対応の準備をしました。
watch #15 on ngs/onairlog-ios
しかし、CircleCI の Xcode は、まだ 6.1 の様です。
故に、エラーでビルドは終了します。
target specifies product type 'com.apple.product-type.application.watchapp', but there's no such product type for the 'iphonesimulator' platform
https://circleci.com/gh/ngs/onairlog-ios/30
画面右下の問い合わせアイコンから、いつ対応すんの?って聞いたら、明確なリリース日は決まってないとの返信を頂きました。
気長に待とうと思います。
所感
OSS なので、Travis CI でも、.org
で無料で問題なく使わせて頂いていました。
ただ、CircleCI に移行したことで、以下の様な点で、メリットがありました。
会社で使っているので知見が生かせる
キューが回ってくるのを待つ必要があったのが無くなった
キャッシュが使える
Build Artifacts が使える (これが大きい)
これで味をしめたので、他のアプリにも設定していこうと思います。
TODOs
参考にしたページ