LCL Engineers' Blog

バス比較なび・格安移動・バスとりっぷを運営する LCLの開発者ブログ

Bitrise,fastlane,CrashlyticsでiOSアプリのテスト配布を自動化する

先日、Crashlyticsを利用したテスト配布について紹介しましたが、CIサービス + fastlane を利用して自動化にも対応しました。

fastlaneについては各所で紹介されていますので、本記事では比較的情報の少ないCIサービス(Bitrise)を中心に紹介します。

techblog.lclco.com

fastlane

fastlaneは、iOSアプリ(Androidも)における各プロセスを自動化するためのコマンドラインツールです( Java でいう、Ant, Maven, Gradleのようなものと理解しています)。

標準搭載されている機能が非常に豊富なので、iOSアプリのリリースプロセスの自動化は、よほど特殊な要件がない限りfastlaneでまかなえると思います。

CIサービスの選定

CicleCI, TravisCIなどが有名ですが、弊社の現在の状況においてはオーバースペック気味だと感じたので、次の理由からBitriseを選定しました。

  • 費用が比較的安い。 50$ / month
  • ビルドの制限がゆるい。無償でも 200回/month で、有償だと無制限
  • Xcode のバージョンアップの追随に早い(らしい)
  • fastlaneとの連携が簡単

※ 無償だとビルド時間が10分までという制限が少しきつい。

www.bitrise.io

fastlaneを使っていれば、CIサービスへの依存度は下げられるため、将来的には必要に応じて他CIサービスへの移行も検討しています。

Bitriseを利用したiOSアプリのテスト配布の手順

ここからBitriseを利用したiOSアプリのテスト配布の方法を説明したいと思います。前提として、ローカル環境でのfastlaneとCrashlyticsを利用したテスト配布は完了しているものとします。(Web上に記事が多数あるため、本記事では割愛します。)

説明に利用する環境

  • Xcode 7.3
  • fastlane 1.80
  • GitHub プライベートリポジトリ

事前準備

Bitrise上でビルドするためにはいくつか事前準備が必要です。 この対応をしていないと、ローカルではビルドが成功するが、Bitrise上はエラーになる・・という状況になります。

XcodeのSchemeの共有 ( Share )

Xcode上で、ビルドに利用するSchemeの共有設定をしておく必要があります。

f:id:lcl-engineer:20160508165102p:plain

f:id:lcl-engineer:20160508165125p:plain

保存すると、下記のファイルが生成されるので、コミット & PUSHしておきます。

.xcworkspace/xcshareddata/xcschemes/SchemeName.xcscheme

証明書をリポジトリに追加

Bitrise上でビルドするためには、2つの証明書をリポジトリへ登録しておく必要があります。Bitriseの管理画面からアップロードしておくこともできそう(未検証)ですが、Bitriseへの依存度を下げるためにリポジトリへ登録する方法を採用しています。

Appleの証明書のダウンロード

WWDRCA (Apple Worldwide Developer Relations Certificate Authority)という証明書を以下のサイトからダウンロードします。(わかりづらいですが、renewed certificate というリンクからダウンロードできます)

WWDR Intermediate Certificate Expiration - Support - Apple Developer

配布用証明書のExport

キーチェーンから配布用証明書もExportします。

「iPhone Distribution XXXX」の証明書を右クリックして、書き出しを選択します。

f:id:lcl-engineer:20160508215244p:plain

個人情報交換(.p12)を形式を選択して保存を選択します。

f:id:lcl-engineer:20160508215143p:plain

任意のパスワードを設定します。

f:id:lcl-engineer:20160508215152p:plain

キーチェーンのパスワードを入力し、許可をクリックするとExport完了です。

f:id:lcl-engineer:20160508215200p:plain

リポジトリへの追加

証明書をプロジェクト配下の任意場所に配置し、コミット & プッシュします。 場所に制約はないですが、fasltaneの配下にディレクトリを切って配置するのが管理しやすいです。

./fastlane/certificate/AppleWWDRCA.cer
./fastlane/certificate/dist.p12

fastlaneの定義

Bitrise上でビルドするためには、上記で準備した証明書を毎回ビルド時にimportをする必要があります。 以下の様な、private laneを準備します。

 private_lane :import_certificates do

    # キーチェーン、証明書のパスワード。CERT_PASSWORDはBitriseから環境変数で設定したほうがよい。
    ENV["KEYCHAIN_NAME"] ="[キーチェンの名称。任意]"
    ENV["KEYCHAIN_PASSWORD"] = "[キーチェンのパスワード。任意]"
    ENV['CERT_PASSWORD'] = "[export時に設定した、証明書のパスワード]"

    # キーチェーンを作成する
     create_keychain(
      default_keychain: true,
      unlock: true,
      timeout: 3600,
      lock_when_sleeps: true
    )

    # 証明書をimport 。リポジトリのパスを指定
    import_certificate certificate_path: "./fastlane/certificate/AppleWWDRCA.cer"
    import_certificate certificate_path: "./fastlane/certificate/dist.p12", certificate_password: ENV['CERT_PASSWORD']
end

crashlyticsのlaneから、上記laneを呼ぶ。

  lane :crashlytics do

    # CI環境で実行の場合のみimport_certificatesを実行。
    import_certificates if Helper.is_ci?

    sigh(adhoc: true)

    # xcodebuildの設定をしないと、ビルドエラーとなる。
    xcodebuild_args = {
      PROVISIONING_PROFILE: lane_context[SharedValues::SIGH_UDID],
      PRODUCT_BUNDLE_IDENTIFIER: "xxxx.xxxx.xxxx"
    }

    xcodebuild_args = xcodebuild_args.map do |k,v|
      "#{k.to_s.shellescape}=#{v.shellescape}"
    end.join ' '

    gym(
        clean: true,
        xcargs: xcodebuild_args,
        scheme: "bitrise-test"
    ) 

    crashlytics(
      crashlytics_path: "./Pods/Crashlytics/iOS/Crashlytics.framework",
      api_token: "[api_token]",
      build_secret: "[build_secret]",
      groups: "xxxxx-group" 
    )

  end

Bitriseのセットアップ

サインアップは省略します。

アプリの追加

まずビルド対象のアプリを追加します。

f:id:lcl-engineer:20160508235317p:plain

ビルド対象のリポジトリ選択を選択します。(GitHubの例)

f:id:lcl-engineer:20160509011428p:plain

BitriseがGitHubへアクセスするためのSSH keyを追加します。

f:id:lcl-engineer:20160509011508p:plain

ビルド対象のブランチを選択します。

f:id:lcl-engineer:20160509011538p:plain

Projectのファイルパス、schemeを入力します。

f:id:lcl-engineer:20160509011623p:plain

最後に、Webhookの設定をして完了です。(スキップもできます)

f:id:lcl-engineer:20160509011711p:plain

WorkFlowの設定

Bitriseではビルド手順をWorkFlowという形で定義します。

手順の一つ一つを「Step」と呼びます。

f:id:lcl-engineer:20160509011828p:plain

デフォルトのStepで不要なものを削除します。 Git Clone以外のStepは不要なので、各 Stepを選択してゴミ箱ボタンで削除します。

f:id:lcl-engineer:20160509011854p:plain

fastlaneのStepを追加するため、「+」ボタンを押下します。

f:id:lcl-engineer:20160509011953p:plain

fastlaneを検索して追加します。

f:id:lcl-engineer:20160509012027p:plain

iOS Dev Centerのログインパスワードを環境変数で設定します。 「Manage Env vars」ボタンを押下します。

f:id:lcl-engineer:20160509012142p:plain

変数名をFASTLANE_PASSWORDとして、パスワードを設定します。

f:id:lcl-engineer:20160509012158p:plain

Saveボタンを押下して完了です。

f:id:lcl-engineer:20160509012526p:plain

「Start a build 」をクリックすることでビルドが実行され、Crashlytics経由でテスト配布されます。 ビルドトリガーを時間起動や、Git HubのWebhookなどにすることで、テスト配布の完全自動化もできますね。

おまけ Bitrise環境で遭遇したはまりどころ

sighコマンドで、「There are no local code signing identities found.」が出る

以下のエラーが発生する場合は、証明書のimportができていない可能性があります。

[01:12:59]: There are no local code signing identities found. You can run `security find-identity -v -p codesigning` to get this output. This Stack Overflow thread has more information: http://stackoverflow.com/q/35390072/774. (Check in Keychain Access for an expired WWDR certificate: http://stackoverflow.com/a/35409835/774 has more info.)
[01:12:59]: Certificate for Provisioning Profile 'xxx.xxxx.xx AdHoc xxxxxxx' not available locally: xxxxxxxx
[01:12:59]: No existing profiles found, that match the certificates you have installed locally! Creating a new provisioning profile for you

gymコマンドで「Couldn't find specified scheme 'xxxx'」が出る

以下のエラーが発生する場合は、schemeの共有 (share)ができていない可能性があります。

[19:35:29]: Installing provisioning profile...
[19:35:29]: xcrun xcodebuild -list -workspace './xxxx.xcworkspace'
[19:35:30]: Couldn't find specified scheme 'xxxx'.
[19:35:30]: Multiple schemes found but you haven't specified one.
[19:35:30]: Since this is a CI, please pass one using the `scheme` option

gymコマンドで「Code Sign error: Provisioning profile does not match bundle identifier」

以下のエラーが発生する場合は、gym時のパラメータとしてxcargs 「PRODUCT_BUNDLE_IDENTIFIER」を指定すると解消されました。

[23:15:08]: ▸ ❌  Code Sign error: Provisioning profile does not match bundle identifier: The provisioning profile specified in your build settings (“xxxxxx”) has an AppID of “xxxxxx” which does not match your bundle identifier “org.cocoapods.xxxxx”.

まとめ

Bitriseもよいサービスですが、何よりもfastlaneが素晴らしいと感じてます。fastlaneのおかげて、iOSアプリのビルド回りで苦労していた点がかなり解消されるのではないでしょうか。fastlaneは、ビルド以外にも色々できるので、積極的に活用してまた紹介したいと思います。