Zenn
🔼

React NativeのAndroid用アプリをいい感じに(EASのクラウドを使わず)GitHub Actionsでビルドする方法

2025/03/24に公開

TL;DR

これコピペしていい感じにセットアップすれば動く

経緯

現在、React Native のビルドは EAS という expo の提供するクラウドサービスの使用が推奨されています。EAS を用いることで Android と iOS のアプリをフルマネージドでビルドしてもらえるので、正直楽ではあるのですが、無料枠とかを考えると正直コストが無視できるものではありません。

そこで、GitHub Actions を使用したビルドスクリプトを簡単にご紹介します。

なお、今回のスクリプトは Android 向けアプリの開発過程で作成したものです。 iOS については今後追記または別記事にてご紹介できればと思います。

やること

  • EAS の CLI を使ってローカルビルド
    • EAS は使いませんが、これの CLI を用いたローカルビルドが可能なので、eas の cli だけは使用します。
  • そこから何だかんだ生成される apk をいい感じにリリースに乗っけてダウンロード可能にする
    • eas では aab が生成されるので、これを buildtool を用いて apks にし、そこから apk を取り出します。

書いたもの

on:
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write
  issues: write

jobs:
  draft-release:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
    steps:
      - name: 🏗 Setup repo
        uses: actions/checkout@v4
      - name: Create Version from DateTime
        id: version
        shell: bash
        run: |
          echo "version=v$(date +%Y.%m.%d-%H%M%S)" >> $GITHUB_OUTPUT
        env:
          TZ: Asia/Tokyo
      - name: Create Draft Release with gh command
        shell: bash
        run: |
          gh release create ${{ steps.version.outputs.version }} \
            --title "Release ${{ steps.version.outputs.version }}" \
            --generate-notes \
            --prerelease \
            --target main
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  build-android:
    needs: draft-release
    runs-on: ubuntu-latest
    steps:
      - name: 🏗 Setup repo
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: volta-cli/action@v4
        with:
          node-version: 22

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 10

      - name: Get pnpm store directory
        shell: bash
        run: |
          echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

      - name: Setup pnpm cache
        uses: actions/cache@v4
        with:
          path: ${{ env.STORE_PATH }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          java-version: 21.0.2
          java-package: jdk
          distribution: microsoft

      - name: Setup EAS
        uses: expo/expo-github-action@v8
        with:
          eas-version: latest
          packager: npm
          token: ${{ secrets.EXPO_TOKEN }}

      - name: Prebuild
        run: pnpm exec expo prebuild --clean

      - name: 🚀 Build Android
        run: eas build --platform android --profile production --local --no-wait

      - name: aabファイルを特定
        id: aab
        run: |
          echo "aab=$(ls -l build-*.aab | awk '{print $9}')" >> $GITHUB_OUTPUT

      - name: Install Bundletool
        run: |
          curl -L https://github.com/google/bundletool/releases/download/1.18.1/bundletool-all-1.18.1.jar -o bundletool.jar
          chmod +x bundletool.jar

      - name: Create Pagerkey
        run: |
          echo ${{ secrets.ANDROID_KEYSTORE }} | base64 -d > pagerkey.jks

      - name: Convert with Bundletool
        id: convert_aab
        run: |
          java -jar bundletool.jar build-apks --bundle=${{ steps.aab.outputs.aab }} --output=output.apks --ks=pagerkey.jks --ks-pass=pass:${{secrets.ANDROID_KEYSTORE_PASSWORD}} --ks-key-alias=key0 --key-pass=pass:${{secrets.ANDROID_KEY_PASSWORD}} --mode=universal

      - name: Unzip apks
        run: |
          unzip output.apks

      - name: 📦 Attach Android Build
        uses: actions/upload-artifact@v4
        with:
          name: android-build.apks
          path: universal.apk
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Upload release
        run: |
          gh release upload ${{ needs.draft-release.outputs.version }} \
            universal.apk \
            --clobber \
            --repo ${{ github.repository }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Publish release
        run: |
          gh release edit ${{ needs.draft-release.outputs.version }} \
            --latest \
            --prerelease=false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Prerelease を用いて build が release にアップロードされるようにする

Release を Prerelease 状態で作成しておくことにより、リリースにファイルをアップロードしながらリリースを作成していくことができます。

現在は Android アプリのみですが、将来的に iOS のビルドなども自動化する場合によいでしょう。

Android 向けのビルドと署名

ビルドコマンド

eas build --platform android --profile production --local --no-wait のコマンドにより、Android 向けのアプリがローカルでビルドされます。ここで aab ファイルが作成されるので、これに署名してアプリを公開していきます。

署名 keystore の作成

署名の作成にあたっては、keystore を作成するため Android Studio でキーを作成した上で、これの base64 エンコードしたもの、keystore のパスワード、これの key のパスワード、key の alies を GitHub Actions に突っ込みました。(Public Archive になってるので Action 内部では使用しませんでしたが、これ)を参考にしました。

署名・apk の取り出し

ここから署名ファイルのローカルでの生成と buildtool での処理により apks が生成されます。apks はフォーマット的には zip ファイルとなっています。

buildtool での署名時、universal モードにすることで apk ファイルを生成可能です。apks ファイル(zip ファイル)の中に、universal.apk というファイルが生成されるので、これを使用してインストールすることができるようになります。

実機インストール

以上で生成された release からスマホに apk をダウンロードしましょう。私の手元環境ではリリースできました。

まとめ

React Native アプリのビルド・リリース方法に関するメモでした。GitHub Actions の枠は余らせているが EAS に課金したくない、あるいは自前の環境でビルドしたいという方は参考にしてください。(了)

Discussion

ログインするとコメントできます