GitHub ActionsとFastlaneを使ってReact Nativeアプリをデプロイする

2020-12-22 hit count image

GitHub ActionsとFastlaneを使ってReact Nativeで開発したアプリを自動でデプロイする

概要

React Nativeを使って趣味でアプリを開発してますが、アプリがどんどん多くなってアプリをデプロイする時、時間がかかる問題が発生しました。

  • 趣味で作ったアプリリスト: App List

それでReact Nativeで作ったアプリを自動でデプロイする方法でFastlaneと言うツールを使ってデプロイしています。

しかし、ローカルマシンでFastlaneでアプリを一つデプロイするには30分ほどかかって、アプリが20個なので、ローカルでデプロイをするにも、時間がかかりすぎました。

それでこのようなデプロイを効率的するため、GitHub Actionsを使ってデプロイシステムを考えてみました。

このブログポストではGitHub ActionsとFastlaneを使ってデプロイする方法について説明します。

もし、React Nativeのデプロイに関してよく知らない方は以前のブログポストを参考してください。

Fastlane準備

まず、以前のブログを参考してFastlaneでデプロイする準備をします。

しかし、以前のブログポストで使ったFastlaneはすぐ使えないです。なぜなら、以前のFastlaneはアプリのバージョンを上げって、上ったバージョンをGitHubで管理をしなきゃならないですが、GitHub Actionsサーバで変更した内容をコミットして保存することが難しいです。

したがって、バージョンはローカルで上げって、GitHub Actionsを使ってサーバで単純にデプロイだけ実行するようにFastlaneを修正する必要があります。

アンドロイドFastlane準備

アンドロイドのFastlaneは単純です。すでに認証キーを使ってデプロイをしてるので、特に設定することがありません。ただし、既存のFastlaneをバージョンを更新するFastlaneとGitHub Actionsで使うFastlaneで分ける必要があります。

  • 既存のFastlane
desc 'Deploy a new version to the Google Play'
lane :release do |options|
  updateVersion(options)

  gradle(task: 'clean bundleRelease')
  upload_to_play_store(
    skip_upload_metadata: true,
    skip_upload_changelogs: true,
    skip_upload_screenshots: true,
    skip_upload_images: true,
    skip_upload_apk: true
  )
end
  • 追加したFastlane
desc 'GitHub actions release'
lane :version do |options|
  updateVersion(options)
end

lane :github do |_options|
  gradle(task: 'clean bundleRelease')
  upload_to_play_store(
    skip_upload_metadata: true,
    skip_upload_changelogs: true,
    skip_upload_screenshots: true,
    skip_upload_images: true,
    skip_upload_apk: true
  )
end

既存のFastlaeはローカルでデプロイする場合もあるので、そのままにして、当該のFastlaneの機能をversiongithubというFastlaneを分けて追加しました。

GitHub Actionsを使う前にローカルでFastlaneのversionを使ってバージョンを更新した後、GitHub Actionsではgithubと言うFastlaneでアプリをデプロイする予定です。

iOS Fastlane準備

iOSでFastlaneは証明書、2FA認証など少し複雑です。

Certificate

一旦、ローカルで使ってる証明書をサーバでも使えるようにする必要があります。Keychain Accessを開いて現在使ってる証明書でマウス右クリックをしてExportメニューを選択します。

Export Certificate

メニューを選択してパスワードを入力する画面がでます。そのパスワードは後で、Fastlaneにも設定する必要があるので、覚えておきます。

このように保存したファイルをReact Nativeのプロジェクトのiosフォルダへコピーします。私は分かりやすくするため、ファイルの名前をdistribution.p12に変更しました。

Provisioning profile

サーバでiOSアプリをデプロイするためにはProvisioning profileが必要です。Provisioning profileファイルをダウンロードするため、アップル開発サイトへ移動します。

そしてGitHub Actionsを使ってデプロイしようと思ってるアプリのProvisioning profileファイルをダウンロードします。

Export Certificate

このように保存したファイルをReact Nativeプロジェクトのiosフォルダへコピーします。私は分かりやすくするためファイル名をdistribution.mobileprovisionにして保存しました。

Signing & Capabilities

GitHub Actionsを使ってアプリをデプロイするためダウンロードしたProvisioning profileを設定してAutomatically manage signingを解除する必要があります。ios/[Your project name].xcworkspaceファイルを実行してxcodeを実行します。

signing and capabilities

そしてSigning & Capabilitiesへ移動して、Automatically manage signingをアンチェックします。あと、上でダウンロードしたProvisioning profileファイルを設定するためProvisioning Profileの項目の横にあるドロップダウンメニューを押してImport Profile...を選択して上でダウンロードしたファイルを設定します。

API key

Fastlaneでアプリをデプロイする時、アップルIDでログインして色んなことを実行します。しかし、アップル開発アカウントは2FAが設定されてサーバ(CI)を使ってデプロイする場合、ログインできない問題が発生します。

アップルはこの2FA認証の代わりで使えるAPI Keyを提供してます。API Keyを生成するためAppstoreconnectのUsers and Accessページへ移動します。

このページで追加ボタンを押してAPI Keyを生成します。色んな質問が出ますが、読んで答えると問題なく生成することができます。

このように生成したAPI KeyでIssuer IDKey IDそしてダウンロードしたキーファイルは後でFastLaneで設定して使います。ここでダウンロードしたファイルはReact Nativeプロジェクトのiosフォルダへコピーします。私は分かりやすくするためファイル名をdistribution.p8で変更して保存しました。

iOS Fastlane

デプロイをするため必要なファイルは全て準備しました。ここからFastlaneファイルを修正してデプロイを準備してみます。

desc 'GitHub actions release'
lane :version do |options|
  updateVersion(options)
  increment_build_number(xcodeproj: '[Your Project Name].xcodeproj')
end

lane :github do |_options|
  create_keychain(
    name: 'ios_app_keychain',
    password: 'XXXXXXXXX',
    timeout: 1800,
    default_keychain: true,
    unlock: true,
    lock_when_sleeps: false
  )
  import_certificate(
    certificate_path: 'distribution.p12',
    certificate_password: 'XXXXXXXXXXX',
    keychain_name: 'ios_app_keychain',
    keychain_password: 'XXXXXXXXX'
  )
  install_provisioning_profile(path: 'distribution.mobileprovision')
  update_project_provisioning(
    xcodeproj: '[Your Project Name].xcodeproj',
    target_filter: 'github',
    profile: 'distribution.mobileprovision',
    build_configuration: 'Release'
  )
  api_key = app_store_connect_api_key(
    key_id: 'XXXXXXXXXXXXx',
    issuer_id: 'XXXXXXX-XXXXXXXXXXXXX-XXXXXXXXXXX',
    key_filepath: 'distribution.p8'
  )

  build_app(workspace: '[Your Project Name].xcworkspace', scheme: '[Your Project Name]')
  upload_to_app_store(
    force: true,
    reject_if_possible: true,
    skip_metadata: false,
    skip_screenshots: true,
    languages: ['ko'],
    release_notes: {
      'default' => 'bug fixed',
      'ko' => 'bug fixed'
    },
    submit_for_review: true,
    precheck_include_in_app_purchases: false,
    automatic_release: true,
    submission_information: {
      add_id_info_uses_idfa: true,
      add_id_info_serves_ads: true,
      add_id_info_tracks_install: true,
      add_id_info_tracks_action: false,
      add_id_info_limits_tracking: true,
      export_compliance_encryption_updated: false
    },
    api_key: api_key
  )
end

アンドロイドと同じようにバージョンを更新するFastlaneとデプロイをするためのFastlaneで分けました。しかし、アンドロイドとは違ってデプロイするためのFastlaneを少し修正する必要があります。

まず、iOSアプリをデプロイするためCertificateを設定する必要があります。

create_keychain(
  name: 'ios_app_keychain',
  password: 'XXXXXXXXX',
  timeout: 1800,
  default_keychain: true,
  unlock: true,
  lock_when_sleeps: false
)
import_certificate(
  certificate_path: 'distribution.p12',
  certificate_password: 'XXXXXXXXXXX',
  keychain_name: 'ios_app_keychain',
  keychain_password: 'XXXXXXXXX'
)

Keychain Accessでダウンロードしたdistribution.p12ファイルを設定して、Exportする時入力したパスワードを設定します。create_keychainpasswordimport_certificatekeychain_passwordはCertificateをExportする時使ったパスワードとは関係ないですが、二つのパスワードに同じパスワードを設定してもいいです。

install_provisioning_profile(path: 'distribution.mobileprovision')
update_project_provisioning(
  xcodeproj: '[Your Project Name].xcodeproj',
  target_filter: 'github',
  profile: 'distribution.mobileprovision',
  build_configuration: 'Release'
)

そして上のようにProvisioning profileファイルを設定します。そして次のようにAPI Keyを使うためapp_store_connect_api_key関数を呼び出してその結果をapi_key変数へ入れます。

api_key = app_store_connect_api_key(
  key_id: 'XXXXXXXXXXXXx',
  issuer_id: 'XXXXXXX-XXXXXXXXXXXXX-XXXXXXXXXXX',
  key_filepath: 'distribution.p8'
)

最後に以前作ったFastlaneを使ってアプリをデプロイするように設定します。ただし、API Keyを使ってデプロイするためupload_to_app_storeを次のように修正して設定する必要があります。

upload_to_app_store(
  ...
  precheck_include_in_app_purchases: false,
  ...
  api_key: api_key
)

上で作って貰ったapi_key変数を設定してprecheck_include_in_app_purchasesfalseで設定します。precheck_include_in_app_purchasesを設定しない場合デプロイする時エラーが発生します。

GitHub Actions

そしたら次はGitHub Actionsを使うためGtiHub Actionsへ必要な設定ファイルを生成する必要があります。React Nativeプロジェクトフォルへ.github/workflows/main.ymlファイルを生成して下記のように修正します。

name: Publish iOS and Android App to App Store and Play Store
on:
  push:
    tags:
      - "v*"
jobs:
  release-ios:
    name: Build and release iOS app
    runs-on: macos-latest
    steps:
      - uses: actions/[email protected]
      - uses: actions/[email protected]
        with:
          node-version: "10.x"
      - uses: actions/[email protected]
        with:
          ruby-version: "2.x"
      - name: Install Fastlane
        run: cd ios && bundle install && cd ..
      - name: Install packages
        run: yarn install
      - name: Install pods
        run: cd ios && pod install && cd ..
      - name: Execute Fastlane command
        run: cd ios && fastlane github
  release-android:
    name: Build and release Android app
    runs-on: ubuntu-latest
    steps:
      - uses: actions/[email protected]
      - uses: actions/[email protected]
        with:
          node-version: "10.x"
      - uses: actions/[email protected]
        with:
          ruby-version: "2.x"
      - name: Install Fastlane
        run: cd android && bundle install && cd ..
      - name: Install packages
        run: yarn install
      - name: Prebuild
        run: npm run prebuild-android
      - name: Execute Fastlane command
        run: cd android && fastlane github

まず、GitHub Actionsの名前を設定していつGitHub Actionsを実行するか設定します。

name: Publish iOS and Android App to App Store and Play Store
on:
  push:
    tags:
      - "v*"

私はvで始まるタグがpushされるとGitHub Actionsが実行されるように設定しました。

jobs:
  release-ios:
  release-android:

そして実際実行されるコマンドをアンドロイドとiOSを分けて設定しました。

iOS GitHub Actions

GitHub ActionsでiOSへ使うコマンドをみてみましょう。

jobs:
  release-ios:
    name: Build and release iOS app
    runs-on: macos-latest
    steps:
      - uses: actions/[email protected]
      - uses: actions/[email protected]
        with:
          node-version: "10.x"
      - uses: actions/[email protected]
        with:
          ruby-version: "2.x"
      - name: Install Fastlane
        run: cd ios && bundle install && cd ..
      - name: Install packages
        run: yarn install
      - name: Install pods
        run: cd ios && pod install && cd ..
      - name: Execute Fastlane command
        run: cd ios && fastlane github

まずiOSはruns-on: macos-latestを使ってマックOSでコマンドを実行するように設定します。

- uses: actions/[email protected]

そして現在のRepositoryのソースコードを持ってきた後、

- uses: actions/[email protected]
  with:
    node-version: "10.x"
- uses: actions/[email protected]
  with:
    ruby-version: "2.x"

ノードとルビをインストールします。

- name: Install Fastlane
  run: cd ios && bundle install && cd ..
- name: Install packages
  run: yarn install
- name: Install pods
  run: cd ios && pod install && cd ..

その後、Fastlane、ノードパッケージ、そしてPodライブラリをインストールします。

- name: Execute Fastlane command
  run: cd ios && fastlane github

最後に私たちが作ったFastlaneのgithubを実行します。

アンドロイドGitHub Actions

GitHub Actionsでアンドロイドで使うコマンドをみてみましょう。

jobs:
  release-android:
    name: Build and release Android app
    runs-on: ubuntu-latest
    steps:
      - uses: actions/[email protected]
      - uses: actions/[email protected]
        with:
          node-version: "10.x"
      - uses: actions/[email protected]
        with:
          ruby-version: "2.x"
      - name: Install Fastlane
        run: cd android && bundle install && cd ..
      - name: Install packages
        run: yarn install
      - name: Prebuild
        run: npm run prebuild-android
      - name: Execute Fastlane command
        run: cd android && fastlane github

まず、アンドロイドはruns-on: ubuntu-latestを使ってubuntuサーバでコマンドを実行するように設定します。

- uses: actions/[email protected]

そして現在のRepositoryのソースコードを持ってきて、

- uses: actions/[email protected]
  with:
    node-version: "10.x"
- uses: actions/[email protected]
  with:
    ruby-version: "2.x"

ノードとルビをインストールします。

- name: Install Fastlane
  run: cd ios && bundle install && cd ..
- name: Install packages
  run: yarn install

その後、Fastlaneとノードパッケージをインストールします。

- name: Prebuild
  run: npm run prebuild-android

そしてアンドロイドデプロイファイルを生成するためprebuild-androidを実行します。このコマンドは私が個人的にpackage.jsonscriptsへ設定したコマンドで下記のようです。

...
"scripts": {
  ...
  "prebuild-android": "npx jetify && react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle",
  ...
}
...

最後に私たちが作ったFastlaneのgithubを実行します。

- name: Execute Fastlane command
  run: cd android && fastlane github

スクリプト

このように作ったFastlaneとGitHub Actionsを使うために下記のようなコマンドを使います。

VERSION=$1

cd android
fastlane version version:$VERSION
cd ..
cd ios
fastlane version version:$VERSION
cd ..

git add .
git commit -m 'update version'
git push origin main

git tag -a v$VERSION -m 'add verstion tag' -f
git push origin v$VERSION -f

アンドロイドフォルダとiOSフォルダへ移動して上で作ったFastlaneのversionを使ってローカルでデプロイするアプリのバージョンを変更します。

cd android
fastlane version version:$VERSION
cd ..
cd ios
fastlane version version:$VERSION
cd ..

このように変更したバージョンをGitで管理するためCommitとPushをやっておきます。

git add .
git commit -m 'update version'
git push origin main

最後にTagを設定してPushをしてGitHub Actionsを実行します。

git tag -a v$VERSION -m 'add verstion tag' -f
git push origin v$VERSION -f

このように作ったスクリプトファイルをReact Nativeプロジェクトフォルダへrelease.sh名前で保存します。そしてGitHub Actionsを使ってアプリをデプロイしたい時下記のようにコマンドを実行します。

# sh ./release.sh 3.3.1
# sh ./release.sh major
# sh ./release.sh minor
sh ./release.sh patch

完了

これでGitHub ActionsとFastlaneを使ってアプリをデプロイする方法についてみてみました。資料があまりなくって作る時結構くろしました。この資料が誰かに少しても役に立てたら嬉しいです。

私はiOSで色んなエラーがでって結構くろしました。また無料ユーザはGitHub Actionsを使う時間が1ヶ月で2,000分でマックOSを使うとLinuxサーバを使う時間より10倍で計算する問題があります。普通のiOSアプリを1つデプロイするには30分ぐらいがかかるので1回デプロイすると300分の時間を使うことになります。したがって、無料で1ヶ月にデプロイする回数は8回ぐらいですね。アンドロイドは10分しかかからなくてLinuxサーバなので、10分、そのまま計算されますので、問題ないですが、マックOSは少し気になります。もし他のGitHub Actionsを使ってる方はこの時間に注意する必要があります。

今度は、皆さんもGitHub Actionsを使って効率的アプリをデプロイしてみてください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

Posts