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

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

今回は「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だけ書いてます。

1
2
3
4
5
6
7
8
9
10
# frozen_string_literal: true
 
 
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のプラグイン追加

1
fastlane add_plugin firebase_app_distribution

参考

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

ワークフローファイル

adhoc.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
      with:
        path: Carthage
        key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
        restore-keys: |
          ${{ runner.os }}-carthage-
 
    - name: Carthage
      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

Fastfile

Fastfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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化します。

コマンド例

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

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

FIREBASE_TOKEN

1
firebase login:ci

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

1
2
3
4
5
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が使えるというのはとても便利だと思いました!
ではでは。

PR満足度98%