React Nativeアプリのリリース負荷を劇的に減らす!GitHub Actions入門
はじめに
こんにちは!React Native開発者の皆さん、こんな経験ありませんか?
「あー、またリリースか...」
- iOSとAndroid、両方ビルドして...
- 証明書の期限切れチェックして...
- ストアにアップロードして...
- メタデータ更新して...
- あれ、バージョン番号間違えた...
1回のリリースに2時間かかって、しかも人的エラーで何度もやり直し...
Github ActionsとFastlane(次回内容)を使えば、リリース作業を大幅に短縮できます。
React Native開発におけるリリースの地獄
手動リリースの現実
React Nativeアプリのリリースって、結構大変じゃないですか?
# 典型的な手動リリースの流れ
$ # 1. コードの準備
$ git checkout main
$ git pull origin main
$ npm install
# 2. バージョン更新
$ # package.jsonを手動編集
$ # app.jsonのversionCodeを手動編集
$ # iOSのInfo.plistを手動編集
# 3. Androidビルド
$ cd android
$ ./gradlew clean
$ ./gradlew assembleRelease
$ # あれ、keystoreのパスワード何だっけ?
$ # 3回目で成功...
# 4. iOSビルド
$ cd ios
$ pod install
$ # 証明書の期限切れ??
$ # プロビジョニングプロファイル更新...
$ xcodebuild archive
$ # 1時間後...
# 5. ストアアップロード
$ # Google Play Consoleにログイン
$ # 手動でAABアップロード
$ # メタデータ入力...
$ # App Store Connectにログイン
$ # 手動でIPAアップロード
$ # スクリーンショット更新...
# 合計時間: 2時間
なんでこんなに大変なの?
React Native特有の問題:
- 2つのプラットフォーム: iOSとAndroid、両方対応が必要
- 複雑な署名: 証明書、プロビジョニングプロファイル、keystore
- 複数のビルドツール: Xcode、Gradle、CocoaPods
- 異なるストア: App Store、Google Play、それぞれ異なる手順
- バージョン管理: package.json、build.gradle、Info.plistの同期
人的エラーが発生しやすい:
- バージョン番号の不一致
- 証明書の期限切れ
- 環境変数の設定ミス
- ストアのメタデータ入力ミス
GitHub Actionsでリリースを自動化
自動化後の理想的な流れ
# 開発者の作業
$ git push origin main
# あとは自動で...
# ✅ 両プラットフォーム同時ビルド
# ✅ 証明書の自動管理
# ✅ ストアへの自動アップロード
# ✅ リリースノートの自動生成
# ✅ チームへの通知
# 合計時間: 10分から15分程度
GitHub Actionsの基本概念
GitHub Actionsは、コードをプッシュしたら自動で何かしてくれる仕組みです。
React Native開発では:
- コードプッシュ → 自動でビルド
- ブランチマージ → 自動でリリース
ワークフロー設定の基本構造
React Native用の基本的なワークフロー
# .github/workflows/release.yml
name: React Native Release
# mainブランチにプッシュされた時に実行
on:
push:
branches:
- main
jobs:
release:
# ビルドに使うOSを選択(今回は実機を使用 ※後述)
runs-on: [self-hosted, macOS, ARM64]
steps:
- name: コードをチェックアウト
uses: actions/checkout@v4
- name: Node.jsをセットアップ
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: 依存関係をインストール
run: npm ci
- name: iOS依存関係をインストール
run: |
cd ios
pod install
- name: Androidビルド
run: |
cd android
./gradlew assembleRelease
- name: iOSビルド
run: |
cd ios
xcodebuild archive -workspace MyApp.xcworkspace -scheme MyApp
#fastlaneでゴニョゴニョしてストアへアップロード
各セクションの説明
1. トリガー条件の設定
on:
push:
branches:
- main
React Native開発でよく使うトリガー:
on:
# mainブランチプッシュ時(リリース用)
push:
branches: ['main']
# 特定ブランチプッシュ時(ベータ版用)
push:
branches: ['develop']
# 手動実行(緊急時用)
workflow_dispatch:
2. 実行環境の選択(泣く泣くセルフホストを選んだ理由)
jobs:
release:
runs-on: [self-hosted, macOS, ARM64]
macOSランナーだと無料枠が爆速で消える問題:
最初は「GitHubのmacOSランナー使えば楽だよね〜」と思って設定したんですが、
# 最初の設定(失敗)
runs-on: macos-latest
# 結果:
# - 1回のビルドで25分
# - プライベートリポジトリの無料枠は月3000分
# - 月120回ビルドで無料枠を使い切る
# - 実際は月10-15回のリリースでも、テストやCIで制限に達する
macOSランナーの実行時間の倍率:
GitHub Actionsでは、ランナーの種類によって実行時間の倍率が異なります。
| オペレーティングシステム | 倍率 |
|---|---|
| Linux | 1倍 |
| Windows | 2倍 |
| macOS | 10倍 |
つまり、macOSランナーで25分ビルドすると、実際の使用量は250分として計算されます。これが無料枠を早く使い切る原因です。
macOSランナーの問題点:
| 項目 | macOSランナー | セルフホスト | 改善効果 |
|---|---|---|---|
| 使用制限 | 3000分/月 | 無制限 | 制限なし |
| 速度 | 25分/ビルド | 10分/ビルド | 2.5倍高速 |
| 安定性 | 時々謎失敗(正直これが一番辛い) | 安定 | エラー激減 |
| 制御 | 制限あり | 完全制御 | カスタマイズ自由 |
無料枠を気にしながら開発するのも嫌だし、万が一無料枠超えてしまったら稟議出さないとだし...
そこでセルフホストという選択をしました。
セルフホストを選んだ理由:
- 無料枠を使い切った: 月3000分では足りない
- ビルド遅すぎ: 25分 → 10分で完了
- 時々謎の失敗: セルフホストは安定
セルフホストランナーの設定:
セルフホステッドランナーの設定
※Github側の管理画面で設定が必要です。
セルフホスト導入の手順(簡単):
# 1. Mac mini M4を購入(約10万円)
# 2. GitHub Actionsランナーをインストール
$ curl -o actions-runner-osx-arm64-2.311.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-osx-arm64-2.311.0.tar.gz
$ tar xzf ./actions-runner-osx-arm64-2.311.0.tar.gz
# 3. 設定
$ ./config.sh --url https://github.com/your-org/your-repo --token YOUR_TOKEN
# 4. 起動
$ ./run.sh
# 結果:使用制限なしで高速ビルド!
環境変数とSecretsの使い方
React Native開発で必要なSecrets
# よく使うSecrets
env:
# Android用
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
# iOS用
APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
FASTLANE_TEAM_ID: ${{ secrets.FASTLANE_TEAM_ID }}
# アプリ用
API_URL: ${{ secrets.API_URL }}
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
環境別の設定管理
# 環境別の設定例
- name: 環境設定を準備
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "ENV=production" >> .env
echo "API_URL=${{ secrets.PROD_API_URL }}" >> .env
else
echo "ENV=staging" >> .env
echo "API_URL=${{ secrets.STAGING_API_URL }}" >> .env
fi
ワークフローファイルを読んでみよう
シンプルなReact Nativeリリースワークフロー
name: React Native Release
on:
push:
branches: ['main']
jobs:
release:
runs-on: [self-hosted, macOS, ARM64]
steps:
- name: コードをチェックアウト
uses: actions/checkout@v4
- name: Node.jsをセットアップ
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: 依存関係をインストール
run: npm ci
- name: iOS依存関係をインストール
run: |
cd ios
pod install
- name: Androidビルド
run: |
cd android
./gradlew clean assembleRelease
- name: iOSビルド
run: |
cd ios
xcodebuild archive \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-archivePath MyApp.xcarchive
- name: ビルド成果物をアップロード
uses: actions/upload-artifact@v4
with:
name: release-builds
path: |
android/app/build/outputs/apk/release/
ios/MyApp.xcarchive/
このワークフローの解説
- ブランチベースの実行: mainブランチへのプッシュでリリース
- 並行ビルド: AndroidとiOSを同時にビルド
- キャッシュ活用: npmの依存関係をキャッシュ
- 成果物保存: ビルド結果をアーティファクトとして保存
- 使用制限回避: セルフホストランナーで制限なし
よくある設定ミスとその対処法
1. 証明書の管理ミス
- name: iOSビルド
run: xcodebuild archive # 証明書が見つからないエラー
正解:
- name: 証明書をセットアップ
run: |
# 証明書をキーチェーンに追加
security create-keychain -p "" build.keychain
security import certificate.p12 -k build.keychain -P ${{ secrets.CERTIFICATE_PASSWORD }}
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
- name: iOSビルド
run: xcodebuild archive
2. 環境変数の設定ミス
- name: アプリをビルド
run: npm run build # 環境変数が設定されていない
正解:
- name: アプリをビルド
run: npm run build
env:
API_URL: ${{ secrets.API_URL }}
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
3. バージョン管理のミス
# package.jsonとbuild.gradleのバージョンが不一致
# package.json: "1.0.0"
# build.gradle: versionCode 2
正解:
- name: バージョンを同期
run: |
# package.jsonからバージョンを取得
VERSION=$(node -p "require('./package.json').version")
# Androidのbuild.gradleを更新
sed -i "s/versionName \".*\"/versionName \"$VERSION\"/" android/app/build.gradle
# iOSのInfo.plistを更新
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" ios/MyApp/Info.plist
4. ビルド成果物の管理ミス
# ビルド成果物を保存していない
- name: ビルド
run: npm run build
# 成果物が失われる...
正解:
- name: ビルド
run: npm run build
- name: 成果物をアップロード
uses: actions/upload-artifact@v4
with:
name: build-${{ github.run_number }}
path: |
android/app/build/outputs/
ios/build/
retention-days: 30
まとめ
今回はGitHub Actionsを使ったReact Nativeアプリのリリース自動化の基本について学びました:
- 手動リリースの問題点と自動化のメリット
- GitHub Actionsの基本概念と設定方法
- macOSランナーの無料枠制限問題とセルフホストの必要性
- React Native開発に必要な環境とSecrets
- 実際のワークフローファイルの読み方
- よくあるミスと対処法
リリース時間と使用制限の比較:
- 手動: 2時間 + 人的エラーリスク
- GitHub Actions (macOS): 25分 + 月3000分制限
- GitHub Actions (セルフホスト): 10分 + 制限なし(泣く泣く導入したけど結果オーライ)
セルフホストランナーの導入効果:
- 2.5倍高速化: 25分 → 10分
- 使用制限なし: 月3000分制限から解放
- 完全制御: 必要なツールを事前インストール
- 導入は大変だったけど、結果的に大正解
次回は、さらに高度な自動化ツールFastlaneについて詳しく見ていきます!
Fastlaneを使えば、証明書管理、バージョンの設定やストアへのアップロードまでさらに高度に自動化できます!
次回内容: 「Fastlaneでモバイルアプリの配信を自動化」- ツール編
- Fastlaneとは何か、なぜ使うのか
- Android用Fastfileの詳細解説
- iOS用Fastfileの詳細解説
- 証明書管理の仕組み
- ストア配信の自動化
お疲れ様でした!
Discussion