1
/
5

fastlane を利用した iOS 継続的デリバリーの実践

Classi で iOS エンジニアをしている @star__hoshi と申します。

Classi 社には iOS エンジニアが 1 人しかいないのにアプリが 3 つあります。

iOS 開発では UDID の追加や証明書の更新など、非常に多くのちょっとしたタスクがあり、このようなアプリ3つ分の雑務ばかりしていれば本来やるべきことができません。

そのため、もろもろの雑務を fastlane の match, gym, deliver などで自動化しました。実際の開発フローの流れと、何をどう自動化したのかコードを含め書いていきます。

この記事では詳しい fastlane の使い方を述べたものではなく、 fastlane を使うことによる効能などの概念的な話が中心になります。fastlane の使い方に関しては docs.fastlane.tools という素晴らしいドキュメントがありますので、そちらを参照ください。

Classi の開発フロー

Classi では、クックパッド社の iOS ブランチ運用を参考にして開発フローを整備しています。

master ブランチを開発ブランチとし、リリース時には release ブランチを作成、リリースされたタイミングで master にマージしています。

クックパッド社 https://speakerdeck.com/morishin/cookpad-ios-release-flow?slide=14

このフローを回すのは難しくありませんが、いくつか手動作業が発生してしまいます。

master にマージされたときに beta 版配布

feature が master にマージされたときに beta 版配布をして動作確認を行います。

beta 版配布を手動でやると以下の作業が必要になります。

  1. UDID の追加があるかないか確認
    1. AppleDev にログインして UDID を追加
    2. UDID の追加に伴い証明書をアップデート
    3. 証明書をダウンロードしてローカルマシンにインストール
    4. Xcode で証明書が適切に設定されているか確認
    5. たいてい古い証明書が利用されてて更新がうまくできず revoke とかする
    6. (revoke すると他のメンバーがその証明書を使っていた場合それが使えなくなる)
  2. Archive Build
  3. Crashlytics Beta にアプリをアップロード
  4. Slack での変更内容の周知

UDID の追加がなければ 1.1〜1.6 はしなくて良いですが、追加があると特に大変ですよね。

この手順を踏むのになんやかんや 30 分くらいかかったりします😭 、ここを CI Server + fastlane に請け負ってもらいましょう。

UDID の追加

register_device の action を実行すると UDID の登録がコマンド1発で行えます。

Crashlytics から通知のメールがきたら手動でこれを実行しています。 (メールを hook して自動化できそうですね 😃 )

$ bundle exec fastlane run register_device name:"アイフォーン7" udid:1111111111111111111111111111

証明書の更新とベータ版の配布

$ bundle exec fastlane beta

beta lane を実行すると、ざっくり以下の手順を実行します。

  1. 証明書のダウンロード、インストール (UDID の追加があれば証明書を更新)
  2. build number を日付フォーマットで更新
  3. アプリアイコンに BETA の文字を載せる
  4. コンパイルして Crashlytics beta で配布
  5. Crashlytics に dSYM のアップロード
  6. 完了したことを slack 通知

beta 版配布で必要なことを一通り実行できます 😊

実際の Fastfile

  lane :beta do
    # 証明書のダウンロードとインストール、必要があれば証明書を更新
    match(type: "development", forcefor new_devices: true)

    # 日付フォーマットで build number を更新
    incrementbuild number(build_number: Time.now.strftime("%Y%m%d%H%M"))

    # アプリアイコンを加工し BETA の文字をアイコンに装飾する
    badge(shield: "#{getversion number}-#{getbuild number}-blue", dark: true)

    # Compile
    gym

    # ipa と dSYM を Artifacts に保存する
    if is_ci?
      sh "cp #{lane_context[SharedValues::IPAOUTPUT PATH]} $CIRCLEARTIFACTS"
      sh "cp #{lane context[SharedValues::DSYMOUTPUT PATH]} $CIRCLE_ARTIFACTS"
    end

    # Crashlytics beta でアプリを配布
    crashlytics(
      crashlytics_path: "Pods/Crashlytics/iOS/Crashlytics.framework",
      api_token: ENV['CRASHLYTICSAPI TOKEN'],
      build_secret: ENV['CRASHLYTICSBUILD SECRET'],
      ipa_path: lane_context[SharedValues::IPAOUTPUT PATH],
      notes: changelog,
      groups: "CLASSI_APP"
    )

    # dSYM を Crashlytics にアップロード
    uploadsymbols tocrashlytics

    # notify slack
    payload = {"Git Commit" => changelog}
    payload["Circle Artifacts Url"] = ENV["CIRCLE BUILDURL"] + "#artifacts/containers/0" if is ci?
    slack(
      message: ":crashlytics: Beta App successfully released!",
      payload: payload,
      default_payloads: default_payloads
    )
  end
アンダースコアで code が崩れてしまうので、こちらの Fastfile を参照ください

CI との連携

Classi では CircleCI を使っていますので、 Beta 配布を CI でやるようにしています。これで master にマージされるたびに Beta 最新版を利用できるようになります。

deployment:
  master:
    branch: master
    commands:
      - brew install imagemagick
      - brew install graphicsmagick
      - bundle exec fastlane beta --verbose

release ブランチ

アプリのリリース作業を手動でやると、15分〜30分くらいかかってしまいますね 😢

  1. Archive Build
  2. Organizer で iTunes Connect にアップロード
    1. build number の更新を忘れ再度 Build が必要に...
  3. Submit 完了するまで数分待つ

この流れも CI でできるようにしてしまいましょう。

iTunes Connect へのアップロード

$ bundle exec fastlane release

release lane を実行すると、ざっくり以下の手順を実行します。

  1. 証明書のダウンロード、インストール (UDID の追加があれば証明書を更新)
  2. build number を日付フォーマットで更新
  3. コンパイルして iTunes Connect にアップロード
  4. Crashlytics に dSYM のアップロード
  5. release version で git tag を打つ
  6. 完了したことを slack 通知

これで iTunes Connect にアプリをアップロードできます。 deliver の説明文管理などは利用せず、 iTunes Connect の画面でやっています。

実際の Fastfile

  lane :release do
    # 証明書のダウンロードとインストール
    match(type: "appstore")

    # 日付フォーマットで build number を更新
    incrementbuild number(build_number: Time.now.strftime("%Y%m%d%H%M"))

    # Compile
    gym(scheme: "Release")

    # ipa と dSYM を Artifacts に保存する
    if is_ci?
      sh "cp #{lane_context[SharedValues::IPAOUTPUT PATH]} $CIRCLE_ARTIFACTS"
      sh "cp #{lane context[SharedValues::DSYMOUTPUT PATH]} $CIRCLEARTIFACTS"
    end

    # iTunes Connect に Upload
    deliver

    # dSYM を Crashlytics にアップロード
    upload symbolsto crashlytics

    # git のリリースタグを打つ
    # 同じバージョンで再申請する場合があるので、 force push してタグをうわがく
    addgit tag(
      tag: "v#{getversion number}",
      message: "build_number: #{getbuild number} by fastlane\n\n#{changelog}",
      force: true
    )
    pushgit tags(force: true)

    # notify slack
    payload = {"Git Commit" => changelog}
    slack(
      message: ":itunesconnect: Successfully uploaded a new App Store build",
      payload: payload,
      default_payloads: default_payloads
    )
  end
アンダースコアで code が崩れてしまうので、こちらの Fastfile を参照ください

CI との連携

release ブランチに変更があったら、自動で release lane が実行されるようにしています。これで、 release ブランチを作成して Push するだけで iTunes Connect へアップロードが完了します。

deployment:
  release:
    branch: /release.*/
    commands:
      - bundle exec fastlane release --verbose

release ブランチの作成

release ブランチを Push すれば自動で iTunes Connect にアップロードされるのですが、その release ブランチの作成や Git Push も fastlane でやってしまいましょう。

$ bundle exec fastlane release_branch version:1.0.1

release_branch lane では以下を実行してくれます。

  1. 引数に release version があるか確認
  2. master ブランチを最新に更新
  3. 引数の release version を Info.plist に反映
  4. git commit, push, pull request の作成

実際の Fastfile

  lane :release_branch do |options|
    # 引数に release version が指定されていることを確認する
    UI.user error!("Required release version. ex: fastlane release_branch version:1.0.0") unless options[:version]
    branch = "release/#{options[:version]}"

    # リリースブランチを作成
    sh("git checkout master && git pull origin master")
    sh("git checkout -b #{branch}")

    # 引数で指定した version に Info.plist を更新
    incrementversion number(version_number: options[:version])
    commitversion bump(
      message: "Create #{branch} branch.",
      xcodeproj: "classi.xcodeproj"
    )

    # git push し PR を作成
    pushto gitremote
    create pull_request(
      repo: "classi/classiios app",
      title: "#{branch}",
      body: "release v#{options[:version]}"
    )
  end
アンダースコアで code が崩れてしまうので、こちらの Fastfile を参照ください

これでアプリのバージョンの更新やプルリクエストの作成もコマンド1つで実行できるようになりました。

release ブランチが Push されるため release lane が動き、 iTunes Connect へアップロードまで流れで行えます 😊

まとめ

証明書の更新から beta 版の配布や iTunes Connect へのアップロードなど、今まで手動で実施していた様々なことを自動化することができました。

Beta 版の配布は1日に何度も必要だったりして、特に効率が良いです。まだ fastlane を利用していない人は是非利用を検討してみてください 💪

classi/fastlane-example

classi/fastlane-example
fastlane-example - fastlane example by Classi Corp.
https://github.com/classi/fastlane-example

本記事で紹介した Fastfile だけでなく、 Appfile や Matchfile なども公開しています。疑問点などあれば @star__hoshi にご連絡ください✉️

Classi株式会社's job postings
11 Likes
11 Likes

Weekly ranking

Show other rankings
Like Kensuke Hoshikawa's Story
Let Kensuke Hoshikawa's company know you're interested in their content