iOS
CircleCI
fastlane

CircleCIでiOSアプリのCIを設定する

Circle CIでiOSプロジェクトのCIを設定した際のメモです

はじめに

  • iOSビルドは無料プランでは出来ません($39/m~)
  • 証明書などを設置するプライベートレポジトリが必要です

ドキュメント

Circle CI / Hello world
https://circleci.com/docs/2.0/hello-world/

Cicle CI / iOSプロジェクトチュートリアル
https://circleci.com/docs/2.0/ios-tutorial/

GitHub / circleci-demo-ios
https://github.com/CircleCI-Public/circleci-demo-ios/

Qiita / CircleCI 2.0 をlocalで動かす
circleci.comでのmacOSプランが有料なので、ローカルで試しました
https://qiita.com/selmertsx/items/45bd672c2c8ddab1981b

Fastlane概要

Circle CIでの作業を始める前に、Fastlaneの概要を把握する必要があります。
BitriseではWebコンソールでほとんどの作業ができましたが、CircleCIではFastlaneのコマンドをセットアップする必要があります。

Fastlane Document
Fastlane Document / アクション一覧

アクション名にエイリアスが設定された(Fastlane 2.68.0~)

かつてのgymやsighといったアクション名にエイリアスが設定され、
最新のドキュメントのサンプルでは、例えばgymはbuild_appといったようにエイリアスが使われていることがあります。

それらの対応はコマンドfastlane actionsのDescriptionで確認できます

fastlaneの便利な機能を徹底的に活用しよう / アクション名が変わる!?

Fastfile記述例

fastlane initを実行すると、fastlane/Fastfileが作成されます。

fastlane/Fastfile
# Fastfileサンプル

lane :beta do
  increment_build_number
  build_app
  upload_to_testflight
end

lane :release do
  capture_screenshots
  build_app
  upload_to_app_store
  slack
end

lane :{レーン名}
    {アクション}
end

レーンやアクションを1つずつ動作確認するには、以下のコマンドで実行できます。

#レーンを実行
fastlane {レーン名}

#アクションを実行
fastlane run {アクション名}

アクションのデフォルト値を分割したファイルに記述する

今回は1つのFastfileに記述しましたが、アクションごとに設定ファイルを分割できます
Circle CIのデモプロジェクトcircleci-demo-iosで、その機能が使われています

fastlaneにはFastfileの他に、
AppfileDeliverfileGymfileMatchfileScanfileSnapfile
といった、
***file
という名前のファイルがあります。

これらのファイルはアクションのオプションの設定を外部ファイル化したもので、
$ fastlane アクション名 init
で生成できます。
例えば、Deliverfileではdeliverアクションのオプションを設定できます。

そして、これらのファイルで設定した値はそれぞれのアクションのオプションで 上書き することができます。
つまり、これらのファイルで設定した値は アクションのデフォルト値 を設定していることと同じになります。

fastlaneの便利な機能を徹底的に活用しよう

以下のようにkey valueを設定するymlファイルです

fastlane/Gymfile
scheme "CCITrial_iOS"

sdk "iphoneos11.3"

clean(true)

output_directory "./"

各アクションで設定できるキーは、
ドキュメントを参照するか、
以下のコマンドから確認出来ます

fastlane actions {アクション名}

# 例. gymのパラメーターを確認する
fastlane actions gym

ローカルで実行する(Fastlane)

具体的なCircleCI向けのFastlane設定作業に入ります。
まず手元のFastlaneでTestFlightへのアップロードまでの動作を確認できるところまで設定します。
また、以下の作業に入る前に以下の作業を行って下さい

  • 対象のXcodeプロジェクトファイルを作成
  • iTunes Connect上でAppIDを取得
  • Circle CIウェブコンソールでプロジェクトを作成、mac OSを使えるプランを有効化(筆者は14日間限定の体験版を設定しました。)

Fastlaneファイルを作成

対象のプロジェクトディレクトリで以下のコマンドを実行します

fastlane init

実行後fastlane/Fastfileが作成されます

プロジェクトファイルをテスト

作成したXcodeプロジェクトをFastlaneからビルドしテストできるか確認

fastlane scan

Circle CIファイルを作成

CircleCI / Hello Worldを参考に.circleci/config.ymlをプロジェクトディレクトリに作成します

iOSプロジェクトチュートリアルにあるとおりにスキームの共有設定をしたり、

署名設定

Fastlane Match (エイリアス名 : sync_code_signing) を設定します

以下のドキュメントの手順に従い設定します
Circl CI / Setting Up Code Signing for iOS Projects

  • 環境変数FASTLANE_PASSWORDにApple IDのログインパスワードを設定しました。
.zprofile
export FASTLANE_PASSWORD={Apple IDパスワード}
  • match実行時に暗号化に使用したパスワードは、あとでCircle CIの環境変数MATCH_PASSWORDに設定しました。

  • 以下のコマンドでfaslane matchのためのプロビジョニングファイルが作成、iTC上に登録されます

match init
match appstore
match development
match adhoc

ビルド番号の自動更新を設定

Apple Generic Versioning Toolを設定し、
laneにアクション"increment_build_number"を追加しました。
AGVの設定は以下を参考にしました
Build Numberを自動設定する方法いろいろ

以下のコマンドでビルド番号が更新されればOK

fastlane run increment_build_number

Testflightへのアップロードを確認

以下のドキュメントを参考にTestflightへのアップロードを設定します
iOS Beta deployment using fastlane

fastlane deliver --ipa "CCITrial_iOS.ipa"

あるいは

fastlane beta

Fastlaneのレーンを実行

ここまでで以下のようなFastfileとconfig.ymlを設定しました

fastlane/Fastfile
default_platform :ios

platform :ios do
  before_all do
    #   CI 環境で実行するときのみ Apple Developer Portal 上の Certificate や
    #   Provisioning Profile に対して変更を行わないように (readonly モード) する
    setup_circle_ci
  end

  desc "Build and run tests"
  lane :test do
    scan
  end

  desc "ビルド番号をインクリメントする"
  lane :increment_number do
    increment_build_number
  end

  desc "Distribution build"
  desc "Testflightへアップロードする"
  lane :build_and_testflight do
    sync_code_signing(type: "appstore")
    build_app(export_method: "app-store", output_directory: "./build")
    testflight(username:"ymmtyuhei@gmail.com", ipa: "./build/ccitrialios2.ipa", skip_waiting_for_build_processing: true)
  end

end

.circleci/config.yml
# iOS CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/ios-migrating-from-1-2/ for more details
#
version: 2
jobs:
  build:

    # Specify the Xcode version to use
    macos:
      xcode: "9.3.0"

    steps:
      - checkout

      # # Install CocoaPods
      # - run:
      #     name: Install CocoaPods
      #     command: pod install

      # Build the app and run tests
      - run:
          name: Build and run tests
          command: fastlane build_and_testflight
          environment:
            SCAN_DEVICE: iPhone 8
            SCAN_SCHEME: ccitrialios2

      # Collect XML test results data to show in the UI,
      # and save the same XML files under test-results folder
      # in the Artifacts tab
      - store_test_results:
          path: test_output/report.xml
      - store_artifacts:
          path: /tmp/test-results
          destination: scan-test-results
      - store_artifacts:
          path: ~/Library/Logs/scan
          destination: scan-logs
      - store_artifacts:
          path: build
          destination: build
workflows:
  version: 2
  build_and_test:
    jobs:
      - build

Fastlaneのレーンを実行しここまでの動作を確認します

# fastlane/Fastfileに基づいたビルドを実行
fastlane build_and_testflight

良ければ circleci buildを実行(Circle CI CLI)し、
こちらも期待通りに動作するか確認します

# .circleci/config.ymlに基づいたビルドを実行
circleci build

Circle CIでビルドとデプロイ

ローカルでビルドできたので、次はCircle CI上でビルドしてみます。

ただ先程から何度か言及しているiOSプロジェクトチュートリアルの通りです。

そこにないこととしては、以下を設定しました

  • Circle CIのプロジェクトページのBuild Settings > Environment Variableに以下設定しました
FASTLANE_PASSWORD {Apple IDのパスワード}
MATCH_PASSWORD {match developmentなどのときに設定したパスワード}

Tips

以下メモです

fastlane match時にエラー

証明書が最大数に達したとエラー

fastlane match development

 …

[!] Could not create another Development certificate, reached the maximum number of available Development certificates.

以下、証明書、Provisioning Profileの削除を実行したら解決しました

fastlane match nuke
fastlane match nuke development
fastlane match nuke distribution

Gym(build_app)でエラー

以下でクリーンを実行することで解決するエラーがあった

fastlane gym --workspace "CCITrial_iOS.xcworkspace" --scheme "CCITrial_iOS" --clean

match, gym 単体で成功したのに、fastlane ios adhocコマンドで失敗する

以下のように beta-reports-active entitlementが含まれていないというようなエラーが発生。

fastlane ios adhoc

…

doesn't include the beta-reports-active entitlement.,
…
** EXPORT FAILED **
[19:20:12]: Exit status: 70

これはXcode9.3の問題
Xcode 9.4 as of Beta 2 で解決したらしい
https://github.com/fastlane/fastlane/issues/12228

Ad-Hocプロビジョニングのipaをアップロードすると、処理後になかったことになる


Ad-Hocプロビジョニングのipaをアップロードすると、処理後になかったことになる
iTunes ConnectのActivityに(処理中)のビルドが追加されるが、
しばらくすると消える。

→アプリアイコンを設定していないことが原因でした...Missing Info.plist value -を警告するメールが来ていました

プライベートGitレポジトリとしてbitbucketを使ったとき

FastlaneやCircleCIの問題ではないのですが、
証明書などを保存するプライベートレポジトリとして、Bitbucketを使いました。
その時、
CircleCIがgit pushする時のキーを、Bitbucketに追加し忘れていたためgit pushに失敗していた
以下の記事のとおりですが、UIやURLが変わっている
https://personal.loudandproud.me/bitbucket-ssh-read-only/

以下の セキュリティ/SSH鍵 から書き込みに使う鍵を追加します
https://bitbucket.org/account/user/{ユーザ名}/ssh-keys/