wheatandcatの開発ブログ

React Nativeで開発しているペペロミア & memoirの技術系記事を投稿してます

GitHub ActionsでAndroidアプリをビルドしてFirebase App Distribution にデプロイする

前回、GitHub ActionsでiOSアプリをビルドしてFirebase App Distribution にデプロイする方法を紹介したので、今回はAndroidの方を紹介

www.wheatandcat.me

PR

github.com

使用

実装

①. Keystoreを作成

以下のコマンドで Keystoreを作成

$ keytool -genkey -v -keystore key.jks -alias *** -keyalg RSA -validity 10000

***は適当な文字列でOK(後で使用するのでメモしておく)

コマンド実行する以下の入力が始まるので、自身の情報を入力

Enter keystore password:
Re-enter new password:  // パスワードは後で使用するのでメモしておく
What is your first and last name?
  [Unknown]:  Your Name
What is the name of your organizational unit?
  [Unknown]:  Development
What is the name of your organization?
  [Unknown]:  Your Company Name
What is the name of your City or Locality?
  [Unknown]:  Shinjuku
What is the name of your State or Province?
  [Unknown]:  Tokyo
What is the two-letter country code for this unit?
  [Unknown]:  JP
Is CN=John Doe, OU=Development, O=MyCompany, L=Tokyo, ST=Tokyo, C=JP correct?
  [no]:  yes

上記で key.jksファイルが作成されるのでandroid/key.jksに配置

②. android/app/build.gradleにKeystoreの設定を追加

local.propertiesに ①で作成したKeystore を設定を追加

■ android/local.properties

storeFile=key.jks
storePassword=****  // ①で入力したパスワード
keyPassword=****   // ①で入力したパスワード
keyAlias=****     // ①で入力した alias

android/app/build.gradleに以下の設定を追加

■ android/app/build.gradle

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

(略)

android {
(略)
    signingConfigs {
      release {
          keyAlias localProperties['keyAlias']
          keyPassword localProperties['keyPassword']
          storeFile rootProject.file(localProperties['storeFile'])
          storePassword localProperties['storePassword']
      }
    }
}

③. SHA-1 フィンガープリント取得

Firebaseを使用している場合、SHA-1 フィンガープリントをコンソールで設定する必要がある。
以下のコマンドで SHA-1 フィンガープリントを取得

$ cd android
$ ./gradlew signingReport

出力の中からConfig: releaseの値を確認して、SHA1の値を確認

Variant: release
Config: release
Store: ***/android/key.jks
Alias: ***
MD5: ***
SHA1:  ***
SHA-256:  ***
Valid  ****

④. 作成したファイルをGitHub Actions の secrets に設定

①と②で作成したkey.jkslocal.propertiesはビルド時に使用するので以下のコマンドでbase 64に変換してGitHub Actions の secrets に設定

$ base64 -i ./android/key.jks | pbcopy
$ base64 -i ./android/local.properties | pbcopy

⑤. fastlaneでFirebase App Distribution にデプロイ

以下のfastlaneのファイルを作成

dart/app/android/fastlane/Fastfile

default_platform(:android)

platform :android do
  desc "Upload an apk to Firebase App Distribution"
  lane :distribution do

    # Firebase App Distributionにアップロード
    firebase_app_distribution(
      app: ENV['REVIEW_ANDROID_FIREBASE_APP_ID'],
      firebase_cli_token: ENV['REVIEW_FIREBASE_CLI_TOKEN'],
      android_artifact_type: "APK",
      android_artifact_path: "build/app/outputs/app-release.apk",
      groups: "testers",
    ) 
  end
end

appfirebase_cli_tokenの値は以下のページを参考に取得

firebase.google.com

⑥. GitHub Actionsでデプロイできるようにする

以下のyamlファイルを作成することでCI上でデプロイできる

.github/workflows/depoly_android_app_review.yaml

name: レビュー環境のAndroidアプリをFirebase App Distributionにデプロイする

on:
  push:
    branches:
      - main
env:
  REVIEW_ANDROID_FIREBASE_APP_ID: ${{ secrets.REVIEW_ANDROID_FIREBASE_APP_ID }}
  REVIEW_FIREBASE_CLI_TOKEN: ${{ secrets.REVIEW_FIREBASE_CLI_TOKEN }}
  REVIEW_GOOGLE_SERVICE_JSON: ${{ secrets.REVIEW_GOOGLE_SERVICE_JSON }}
  REVIEW_DART_FIREBASE_OPTIONS: ${{ secrets.REVIEW_DART_FIREBASE_OPTIONS }}
  REVIEW_JKS: ${{ secrets.REVIEW_JKS }}
  REVIEW_ANDROID_PROPERTIES: ${{ secrets.REVIEW_ANDROID_PROPERTIES }}
jobs:
  deploy:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: dart/app

    steps:
      - name: Checkout repository
        uses: "actions/checkout@v4"

      - uses: actions/setup-java@v4
        with:
          distribution: "temurin"
          java-version: "11.x"

      - name: Create google-services.json
        run: echo $REVIEW_GOOGLE_SERVICE_JSON | base64 --decode > ./android/app/google-services.json

      - name: Create key.jks
        run: echo $REVIEW_JKS | base64 --decode > ./android/key.jks

      - name: Create local.properties
        run: echo $REVIEW_ANDROID_PROPERTIES | base64 --decode > ./android/local.properties

      - name: Create lib/firebase_options.dart
        run: echo $REVIEW_DART_FIREBASE_OPTIONS | base64 --decode > ./lib/firebase_options.dart

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: "2.7"

      - name: Cache Flutter dependencies
        uses: actions/cache@v4
        with:
          path: |
            ${{ env.FLUTTER_HOME }}/.pub-cache
            **/.flutter-plugins
            **/.flutter-plugin-dependencies
            **/.dart_tool/package_config.json
          key: ${{ runner.os }}-flutter-${{ hashFiles('dart/app/pubspec.lock') }}
          restore-keys: |
            ${{ runner.os }}-flutter-

      - name: Cache Bundler dependencies
        uses: actions/cache@v4
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-bundler-${{ hashFiles('dart/app/android/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-bundler-

      - name: Set up Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: stable
          cache: true

      - name: check version
        run: flutter --version

      - name: Install Flutter dependencies
        run: flutter pub get

      - name: Install dependencies
        run: |
          cd android
          bundle install

      - name: build apk
        run: |
          BUILD_NUMBER=$(date +%s)
          echo "Current build number is $BUILD_NUMBER"
          flutter build apk --release --build-number=$BUILD_NUMBER

      - name: mv apk
        run: |
          mkdir -p android/build/app/outputs
          mv ./build/app/outputs/flutter-apk/app-release.apk ./android/build/app/outputs/app-release.apk

      - name: distribution apk
        run: |
          cd android
          bundle exec fastlane distribution
        env:
          RUBYOPT: "-rostruct"

.gitignoreしているファイルが結構あるので、除外しているファイルをGitHub Actions の secrets 経由で生成してCIで実行

CIが正常に動作すれば以下みたいな感じでFirebase App Distributionからアプリをダウンロードできるようになる