[iOS] GitHub Actionsでfastlaneのmatchを使わずにAdHoc書き出しをしてからFirebase App Distributionにアップロードする

2020.01.25

こんにちは!きんくまです。

今回は「GitHub Actionsでfastlaneのmatchを使わずにAdHoc書き出しをしてからFirebase App Distributionにアップロードする」です!(長いっ)

作ったGitHub Acitonsのワークフロー

  1. GitHubでプルリクを作ってから、マージされたイベントをトリガーにする
  2. macOSを立ち上げる
  3. fastlaneを使う
  4. テストする。失敗したらSlackに通知
  5. AdHocビルドする。 その際、証明書とプロビジョニングファイルはGitHubのsecretsに登録したものを使用する 登録するファイルはbase64化したもの
  6. Firebase App Distributionにアップロードする
  7. Slackに通知

参考にした神情報のみなさま

先に申し上げますと、さきほど「作った」と書いてしまったのですが、先人のみなさまの情報を元に組み合わせて作成しました。 ありがとうございます!

Gemfile

fastlaneだけ書いてます。

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "fastlane", "2.139.0"

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

fastalneにFirebase App Distributionのプラグイン追加

fastlane add_plugin firebase_app_distribution

参考

このコマンドを打つと fastalne/Pluginfile が追加されます。これもGitにコミットしてください。

ワークフローファイル

2020/02/11修正 Carthageのif文追加しました。

adhoc.yml

name: AdHoc Distribution

on:
pull_request:
branches: [master]
types: [closed]

jobs:
build:

runs-on: macos-latest

steps:
- uses: actions/checkout@v2

# Firebaseのため
- uses: actions/setup-node@v1
with:
node-version: '10.x'
- name: Bundle Install
run: bundle install

# Xcode 11.2.1 を使う
- name: Select Xcode version
run: sudo xcode-select -s '/Applications/Xcode_11.2.1.app'

- name: Show Xcode version
run: xcodebuild -version

- name: Keychain.p12
run: |
echo "${{ secrets.P12_BASE64 }}" > ios_distribution.p12.txt
base64 --decode ios_distribution.p12.txt > ios_distribution.p12

- name: ProvisioningProfile
run: |
echo "${{ secrets.PROVISIONING_BASE64 }}" > adhoc.mobileprovision.txt
base64 --decode adhoc.mobileprovision.txt > adhoc.mobileprovision

- name: list files
run: ls -l

- name: Cache Carthage
uses: actions/cache@v1.1.2
id: cache-carthage
with:
path: Carthage
key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
restore-keys: |
${{ runner.os }}-carthage-

- name: Carthage
if: steps.cache-carthage.outputs.cache-hit != 'true'
run: carthage bootstrap --platform iOS --no-use-binaries --cache-builds

- name: Tests
env:
SLACK_URL: ${{ secrets.SLACK_URL }}
run: |
bundle exec fastlane tests

- name: Upload Tests Result
uses: actions/upload-artifact@v1
with:
name: test-results
path: fastlane/test_output/report.html

- name: Adhoc
env:
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
SLACK_URL: ${{ secrets.SLACK_URL }}
CERT_PASSWORD: ${{ secrets.CERT_PASSWORD }}
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
run: |
npm install -g firebase-tools
bundle exec fastlane adhoc

Cacheについて

2020/02/11追記

Carthageのキャッシュ設定を上のyamlでは入れているのですが、この設定だと残念ながらできません。

[warning]No scopes with read permission were found on the request.

というメッセージが実行時に出力されます。

調べてみると、Cacheが使えるのはpushとpull_requestのみです。 ただしpull_requestにtypesを指定すると使えなくなりました、、、。 上のyamlでは、typesにclosedを指定しています。これはプルリクをマージしたときのイベントです。 pull_requestのデフォルトのtypeは opened, synchronize, reopenedとなっていて、何も指定しないとこのイベントでワークフローが走ります。ですが、今現在はこれ以外を指定するとダメだというだと思います。

なので、types設定を削除すれば、上のyamlでもCacheが使えるようになります! そのうちclosedでも使えるようになれるといいなー

Fastfile

Fastfile

default_platform(:ios)

platform :ios do

desc "Unit Tests"
lane :tests do
scan(
scheme: "スキーム名",
device: "iPhone 11",
clean: true,
slack_message: "テストが完了しました!",
slack_url: ENV["SLACK_URL"],
slack_only_on_failure: true
)
end

desc "Import Certificates and Provisioning Profile"
private_lane :import_certificates_and_provisioning_profile do
create_keychain(
name: "mykeychain",
password: ENV["KEYCHAIN_PASSWORD"],
timeout: 1800
)
import_certificate(
certificate_path: "ios_distribution.p12",
certificate_password: ENV["CERT_PASSWORD"],
keychain_name: "mykeychain",
keychain_password: ENV["KEYCHAIN_PASSWORD"]
)
install_provisioning_profile(path: "adhoc.mobileprovision")
end

desc "Archive AdHoc and send to Firebase"
lane :adhoc do
import_certificates_and_provisioning_profile
build_app(project: "プロジェクト名.xcodeproj",
scheme: "スキーム名",
configuration: "Configuration名",
clean: true,
export_options: {
method: "ad-hoc"
})
firebase_app_distribution(
app: "Firebaseプロジェクトから取得したApp ID (AppleのBundle IDではない)",
groups: "developer",
release_notes: "ベータ版配信",
firebase_cli_path: `which firebase`.strip()
)
slack(
message: "ベータ版が配信されました\nhttps://appdistribution.firebase.dev/app_distro/projects",
slack_url: ENV["SLACK_URL"]
)
end

end

CocoaPods使っているときは、projectじゃなくて、workspace指定してくださいまし。

firebase_app_distributionのappのところだけ補足

設定ページのここです。

GitHubのSecretsに登録するもの

Secretsは、GitHubの画面上のSettingsタブ > 画面左のSecretsメニュー から見れます。 ただし、権限がないと見れないかも

キー 何するもの?
P12_BASE64 base64化されたAcHoc用のp12証明書
PROVISIONING_BASE64 base64化されたプロビジョニングプロファイル
SLACK_URL 投稿したいチャンネル情報のWebhook URL
KEYCHAIN_PASSWORD 適当なキーチェーン用パスワード(一時的なものなのでわからなそうなやつであればなんでも)
CERT_PASSWORD キーチェーンから証明書を書き出した際に使用したパスワード
FIREBASE_TOKEN firebaseをCIから利用するときのトークン

ファイルをbase64化する

キーチェーンからp12ファイル形式で書き出したAdHoc用証明書と、プロビジョニングファイルはbase64化します。

コマンド例

openssl base64 -in cert.p12 -out cert_base64.txt

base64化すれば、バイナリファイルがテキストファイルに変換できるのでsecrets内に登録することができます。 それをワークフロー内でbase64デコードしてバイナリファイルに戻してあげて使用します。

FIREBASE_TOKEN

firebase login:ci

を実行すると、こんな感じになります。

Waiting for authentication...

✔ Success! Use this token to login on a CI server:

ここにトークンが書いてあります

fastalneから書き出されたテスト結果ファイル

ここにあります。

まとめ

ここではfastlaneを使いました。ですが、yaml内のrunにコマンドを書けば、xcodebuildコマンドでもいけるみたいです。 あと、acitions/checkoutは@v2が出ていたので、そちらにしました。

あと、チームのみんなと料金表見ていたのですが、macランナーはLinuxランナーに対して10倍のポイント分(と呼べばよいのか?)を消費するみたいなので、少し気をつけた方が良いかもしれないです。

ただ、普段使っているGitHubでCI/CDが使えるというのはとても便利だと思いました! ではでは。