FLINTERS Engineer's Blog

FLINTERSのエンジニアによる技術ブログ

fastlaneの簡単な紹介と使用例

こんにちは、GANMA!の開発を行っているtakezawa(@to4iki)です。

今回は、fastlaneの紹介と導入方法・簡易的な使用例を紹介します。
また、ブログ内で使用しているサンプルコードは公開しているので良かったら参考にしてみて下さい。
Sandbox-iOS/FastlaneBox

fastlaneとは

fastlane/fastlane: The easiest way to automate building and releasing your iOS and Android apps
fastlaneは主にiOS/Androidアプリのビルド、テスト、デプロイを行うためのRuby製のタスクランナーであり、
アプリ開発の様々なフローにおける自動化をサポートしてくれます。
Twitter傘下のFabricに取り込まれており、また幾つかのCIサービスにも標準搭載されるなど今とても勢いのあるツールです。

action, lane

fastlaneではアクションと呼ばれる機能(タスクコマンド)を組み合わせたレーンにおいて自動化を実現します。

f:id:to4iki:20160907161228p:plain

主なアクションをfastlane/READMEから抜粋しました。

iOS
アクション 説明
deliver スクリーンショットメタデータ、アプリをApp Storeにアップロードする
snapshot 全デバイスを対象にアプリのスクリーンショット撮影を自動化する
frameit スクリーンショットを各デバイス画像にはめ込む
pem プッシュ通知用のプロファイルを自動生成したり更新する
sigh プロビジョニングプロファイルの生成、更新、修復する
produce 新しいアプリをiTunes ConnectやDev Portalで作成する
cert 証明書の作成と管理をする
spaceship Apple Dev CenterやiTunes Connectにアクセスする
pilot TestFlightのテスターを管理する
boarding TestFlightのbetaテスターを招待する
gym アプリをビルドする
match Gitを使って証明書とプロファイルを管理する
scan iOSアプリ、Macアプリのテストを実行する
Android
アクション 説明
supply アプリ、メタデータGoogle Playにアップロードする
screengrab 全デバイスを対象にアプリのスクリーンショット撮影を自動化する

この他、公式で提供しているアクションはActions - fastlane docsにて確認できます。

など痒いところに手が届くようなアクションも用意されているので、組み合わせの幅も広がりますね。

導入

faslaneをinstallしてみましょう(ここから先はiOSプロジェクトを例に説明します)。

versionを固定するためにBundlerを使用し、Gemfileに依存を定義。

source 'https://rubygems.org'
gem 'fastlane'

install

$ bundle install --path=vendor/bundle
$ bundle exec fastlane -v
fastlane 1.102.0

セットアップ

プロジェクトのルートでinitコマンドを実行し、雛形の設定ファイルを作成します。

$ bundle exec fastlane init

ターミナル上でApp Identifier, iTunes Connectへのログイン情報など幾つかの質問を答えます(Androidプロジェクトの場合も同様にGooglePlayの情報を入力します)。

完了すると、

  • ./fastlane/Fastfile: レーン定義を記述するための雛形ファイル
  • ./fastlane/Appfile: Developerに関する情報が記載されているファイル

が作成されます。

簡易的なレーン作成

雛形で生成されたFastfileをベースに少しだけいじってみます(RubyDSLを書いていきます)。
因みに$ bundle exec fastlane actionsでアクション一覧$ bundle exec fastlane listで現在のレーンの一覧が見れます。

今回はテストを実行 > Slackに成功/失敗を通知するだけのシンプルなフローを定義してみます。

Fastfile

require "yaml"

fastlane_version "1.102.0"
default_platform :ios

CONF = YAML.load_file('conf.yml')

platform :ios do
  before_all do
    ENV["SLACK_URL"] = CONF["slack"]["webhookurl"]
  end

  desc "Runs all the unit and ui tests"
  lane :test do
    # cocoapods
    # cathage
    scan(
      scheme: "FastlaneBox",
      clean: true
    )
  end

  after_all do |lane|
    slack(message: "Successfully")
  end

  error do |lane, exception|
    slack(
      message: exception.message,
      success: false
    )
  end
end

conf.yaml

slack:
  webhookurl: "https://hooks.slack.com/services/#{your_webhook_url_path}"

Slackのwebhookurlはconf.yamlファイルを作成しそちらに定義。
また、実運用の際はローカルで実行した場合にもSlackに通知が飛ぶのはやり過ぎなので、CI環境下で実行した場合にのみ結果を通知するよう設定した方が良いでしょう。

# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Actions.md#is_ci
if is_ci?
  scan(skip_slack: false)
else
  scan
end

では、実行してみます。

$ bundle exec fastlane test

f:id:to4iki:20160914000211p:plain 成功/失敗の件数が整形された状態で表示されました。
(テスト結果表示用JUnitのレポート形式のhtmlファイルが./fastlane/test_output/report.htmlに出力されています)

Slackにも良い感じに結果が表示されましたね! f:id:to4iki:20160914001547p:plain

Travis CIとの連携

Travis CI上でfastlene経由のテスト実行を試してみます。

まず、Travisから流すレーンをシェルスクリプトとして定義(実行scriptは肥大化する恐れがあるので、事前に別ファイル等に分割しておくのをお勧めします)

fastlane/travis.sh

#!/bin/sh
fastlane test

実行権限を付与

$ chmod a+x fastlane/travis.sh

.travis.yml に諸々定義(fastlaneは最新版にupdateしておく)

language: objective-c
osx_image: xcode7.3
env:
  global:
    - LC_CTYPE=en_US.UTF-8
install:
  - gem update fastlane --no-ri --no-rdoc --no-document
script:
  - ./fastlane/travis.sh

最後に、TravisからBuildする必要があるのでターゲットのスキームは公開しておいてください(Xcode > Manage Schemes… > Sharedチェックボックスをオン)。
これで、$ git pushのタイミングでfastlane経由のテストが走るようになりました。

f:id:to4iki:20160914155424p:plain

他にも、xcov用のアクションを組み合わせればカバレッジの計測ができるので良かったら試してみてください。

カスタムアクション

用意されたアクションの呼び出しだけではなく、独自のアクション定義も可能です。
次のコマンドを実行しカスタムアクションの雛形を生成します。

$ bundle exec fatlane new_action

現在時刻を標準出力するだけのsampleアクションを書いてみましょう。

actions/sample.rb

module Fastlane
  module Actions
    class SampleAction < Action
      def self.run(params)
        puts Time.now
      end

      # only iOS
      def self.is_supported?(platform)
        platform == :ios
      end
      ...
    end
end

./fastlane/actions/配下のファイルはfastlane実行時にロードされ、既存のアクションと同様に使用出来ます。

desc 'Custom action'
lane :my_action do
  sample
end

より具体的な実装例はfirefox-ios-build-tools/fastlane/actionsなどを参考にして見て下さい。
プロジェクト固有の設定/処理などはカスタムアクションを作成し、レーンで使い回すといった使い方が出来そうですね。

プラグイン

fastlaneにはプラグイン機構が存在します。

試しに、Xcodeのグループに合わせてファイル/ディレクトリ構造を同期してくれるsynxをアクションとして提供しているプラグインをinstallしてみます。

$ bundle exec fastlane add_plugin fastlane-plugin-synx

実行すると、gemfileライクな依存解決用のファイルを自動生成してくれます。

Pluginfile

# Autogenerated by fastlane
#
# Ensure this file is checked in to source control!

gem 'fastlane-plugin-synx'

Gemfileにもブリッジが定義されるので、$ bundle installで自動的にプラグインもinstallされます。

plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval(File.read(plugins_path), binding) if File.exist?(plugins_path)

これで、レーンからsynxアクションを呼び出すことが出来るようになりました。

desc "Runs synx to folderize the Xcode project"
lane :sync do
  synx
end

snapshot

次にfastlaneが提供するスクリーンショット作成用のアクションを試してみます。
fastlane/snapshot
XCUITextを利用してスクリーンショットを撮るので、プロジェクトにUITests用のビルドターゲットを新設しておきましょう。

準備

下記コマンドで、どのデバイス/言語をターゲットにしたスナップショットを撮影するか指定するための設定ファイル(Snapfile)の雛形を作成します。

$ bundle exec snapshot init

devicesに設定する名前は$ xcrun simctl listを実行して確認が出来ます。
検証用にiPhone6sの日本語環境下のみをターゲットにします。

Snapfile

devices([
  "iPhone 6s"
])

languages([
  "ja-JP"
])

自動生成されたSnapshotHelper.swiftはUITestsのターゲットに含めます。
あとは、UITests中の任意のタイミングでsetupSnapshot関数を呼び出しましょう。

override func setUp() {
    super.setUp()

    continueAfterFailure = false

    let app = XCUIApplication()
    setupSnapshot(app) // 起動時のスクリーンショットを撮影する
    app.launch()
}
実行

runコマンドでスクリーンショットの撮影を行います

$ bundle exec snapshot run

実行後はscreenshots/screenshots.htmlがブラウザで開かれ、スクリーンショットを一覧出来ます。

f:id:to4iki:20160913233909p:plain

またレーンとして定義も可能です。

desc "Creates new screenshots and uploads them to iTunes Connect"
lane :screens do
  snapshot
end

より実践的な使い方

  • iTunes Connectへアップロードするバイナリ生成のためのビルドやパッケージ化
  • プロビジョニングプロファイルの管理
  • テスト用のAdHoc配信(deploygateやcrashlyticsなど)
  • リリース前の外部テスト配信 in TestFlight
  • iTunes Connectのメタデータ更新

などリリースフローの自動化を始めとする実践的なfastlaneの使い方は試せていませんので、参考資料を貼らせて頂きます。

iOSアプリ開発に必要な証明書とプロファイルをGitHubのリポジトリで一括管理する
iOSアプリ申請を驚くほど簡単に!fastlaneではじめる自動化入門

まとめ

fastlaneの紹介と簡単な使い方を紹介しました。
リリースフローの自動化もそうですが、オレオレシェルスクリプトによる車輪の再開発を防げる、属人化しがちなビルドやテストなどの実行をfastlane内だけで完結することで保守性が高くなります。
皆さんもfastlaneを使って快適で安全なリリースフローを運用しましょう!

参考