🐮
FlutterアプリのCDの備忘録
Firebaseでテストアプリを配布するためのCDをGitHub Actionsで構築したので備忘録としての記事です。Automatically manage signingに対応しています。
workflow
iOS用
name: "[DEV] Build and Publish iOS"
on:
push:
# developブランチへのpushがトリガー
branches: [develop]
jobs:
build:
runs-on: macos-latest
# buildが止まらなくなると困るので30分を指定
timeout-minutes: 30
# GitHubのシークレットの環境名
environment:
name: development
steps:
# repositoryをセットアップ
- name: Checkout repository
uses: actions/checkout@v4
- name: Extract App Store Connect API Private Key in ./private_keys
env:
IOS_API_KEY_ID: ${{ secrets.IOS_API_KEY_ID }}
IOS_API_AUTHKEY_P8_BASE64: ${{ secrets.IOS_API_AUTHKEY_P8_BASE64 }}
run: |
mkdir ./private_keys
echo -n "$IOS_API_AUTHKEY_P8_BASE64" | base64 --decode --output ./private_keys/AuthKey_$IOS_API_KEY_ID.p8
# flutterをセットアップ
- name: Flutter get
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: latest
cache: true
- name: Check version
run: flutter --version
# Packageをセットアップ
- name: Setup packages
run: |
flutter pub get
dart run build_runner build -d
# Firebaseをセットアップ
- name: Setup Firebase Project
env:
FIREBASE_PROJ_NAME: ${{ secrets.FIREBASE_PROJ_NAME }}
FIREBASE_AUTH_TOKEN: ${{ secrets.FIREBASE_AUTH_TOKEN }}
run: |
curl -sL https://firebase.tools | bash
dart pub global activate flutterfire_cli
# i=iOS a=Android m=macOS w=Web x=Windows (--platformsにプラットフォームを指定していても、-mや-xの指定もないとエラーになるため不要でも各プラットフォームごとのパッケージ名を入れる。
flutterfire configure -p $FIREBASE_PROJ_NAME -y --platforms "ios" -i "com.example.example-app" -a "com.example.example-app" -m "com.example.example-app" -w "1:XXX:web:YYY" -x "1:XXX:web:YYY" -t $FIREBASE_AUTH_TOKEN -f > null
- name: Run flutter build
id: build
run: flutter build ipa --release --no-codesign --dart-define-from-file=lib/flavors/json/${{ secrets.FLAVOR_ENV_NAME }}.json --build-number=$GITHUB_RUN_NUMBER
# Automatically manage signing でアーカイブ
- name: Archive by xcodebuild
env:
IOS_API_ISSURE_ID: ${{ secrets.IOS_API_ISSURE_ID }}
IOS_API_KEY_ID: ${{ secrets.IOS_API_KEY_ID }}
run: xcodebuild archive CODE_SIGNING_ALLOWED=NO -workspace ./ios/Runner.xcworkspace -scheme Runner -configuration Release -archivePath ./build/ios/Runner.xcarchive
# IPAをbuild
- name: Export by xcodebuild
env:
IOS_API_ISSURE_ID: ${{ secrets.IOS_API_ISSURE_ID }}
IOS_API_KEY_ID: ${{ secrets.IOS_API_KEY_ID }}
# ローカルでarchiveしたときに一緒に生成されるExportOptions.plistの中身をbuildに使用する。
# 手動サインインをしたときのExportOptionsにしないとCD中にエラーが出るため注意。
EXPORT_OPTIONS: ${{ secrets.EXPORT_OPTIONS }}
run: |
echo $EXPORT_OPTIONS > ios/Runner/ExportOptions.plist
xcodebuild -exportArchive -archivePath ./build/ios/Runner.xcarchive -exportPath ./build/ios/ipa -exportOptionsPlist ./ios/Runner/ExportOptions.plist -allowProvisioningUpdates -authenticationKeyIssuerID $IOS_API_ISSURE_ID -authenticationKeyID $IOS_API_KEY_ID -authenticationKeyPath `pwd`/private_keys/AuthKey_$IOS_API_KEY_ID.p8
# macos上ではFirebase配布のActionを実行できないためipaファイルをartifacts storageに一時保存する
- name: Collect ipa artifacts
uses: actions/upload-artifact@v2
with:
name: release-ipa
path: build/ios/ipa/*.ipa
release:
name: Release ipa to Firebase
needs: [build]
runs-on: ubuntu-latest
timeout-minutes: 30
environment:
name: development
steps:
- uses: actions/checkout@v4
# artifacts storageからipaファイルをダウンロード
- name: Get release-ipa from artifacts
uses: actions/download-artifact@v2
with:
name: release-ipa
# Firebase Distributionにアップロード
- name: Upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
# firebaseプロジェクトのID
appId: ${{ secrets.FIREBASE_IOS_ID }}
# firebaseのサービスユーザーのcredential json
serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
# firebaseテスターのグループ
groups: developer
file: ${{ secrets.FLAVOR_ENV_NAME }}.ipa
# マージしたブランチ名をリリースノートに設定
releaseNotes: ${{ github.ref_name }}
# 詳細なログ出力
debug: true
Android
name: "[DEV] Build and Publish Android"
on:
push:
branches: [develop]
jobs:
build:
runs-on: ubuntu-latest
# buildが止まらなくなると困るので30分を指定
timeout-minutes: 30
# GitHubのシークレットの環境
environment:
name: development
steps:
# repositoryをセットアップ(actionsを使う場合は必須)
- name: Setup repository
uses: actions/checkout@v4
# 実装時点のjavaの最新ver
- uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17.x"
# flutterをセットアップ
- name: Setup flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: latest
cache: true
- name: Check version
run: flutter --version
# Packageをセットアップ
- name: Setup packages
run: |
flutter pub get
dart run build_runner build -d
# Firebase Projectをセットアップ
- name: Setup Firebase Project
env:
FIREBASE_PROJ_NAME: ${{ secrets.FIREBASE_PROJ_NAME }}
FIREBASE_AUTH_TOKEN: ${{ secrets.FIREBASE_AUTH_TOKEN }}
run: |
curl -sL https://firebase.tools | bash
dart pub global activate flutterfire_cli
# i=iOS a=Android m=macOS w=Web x=Windows (--platformsにプラットフォームを指定していても、-mや-xの指定もないとエラーになるため不要でも各プラットフォームごとのパッケージ名を入れる。
flutterfire configure -p $FIREBASE_PROJ_NAME -y --platforms "ios, android" -i "com.example.example-app" -a "com.example.example-app" -m "com.example.example-app" -w "1:XXX:web:YYY" -x "1:XXX:web:YYY" -t $FIREBASE_AUTH_TOKEN > null
# key.propertiesを出力
- name: Create key.properties
run: |
mkdir -p android/app/keystore/${{ secrets.FLAVOR_ENV_NAME }}
echo ${{ secrets.ANDROID_KEY_JKS }} | base64 -d > android/app/keystore/${{ secrets.FLAVOR_ENV_NAME }}/release.jks
echo 'storeFile=keystore/${{ secrets.FLAVOR_ENV_NAME }}/release.jks' >> android/app/keystore/${{ secrets.FLAVOR_ENV_NAME }}/key.properties
echo 'storePassword=${{ secrets.ANDROID_STORE_PASSWORD }}' >> android/app/keystore/${{ secrets.FLAVOR_ENV_NAME }}/key.properties
echo 'keyPassword=${{ secrets.ANDROID_ALIAS_PASSWORD }}' >> android/app/keystore/${{ secrets.FLAVOR_ENV_NAME }}/key.properties
echo 'keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}' >> android/app/keystore/${{ secrets.FLAVOR_ENV_NAME }}/key.properties
cat android/app/keystore/${{ secrets.FLAVOR_ENV_NAME }}/key.properties
# apkファイルを生成
- name: Build APK
# ローカルではflavorでbuildしているため
run: flutter build apk --release --build-number=$GITHUB_RUN_NUMBER --dart-define-from-file=lib/flavors/json/${{ secrets.FLAVOR_ENV_NAME }}.json
# Firebase Distributionにアップロード
- name: Upload apk to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
# firebaseプロジェクトのID
appId: ${{ secrets.FIREBASE_ANDROID_ID }}
# firebaseのサービスユーザーのcredential json
serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
# firebaseテスターのグループ
groups: developer
file: ./build/app/outputs/flutter-apk/app-release.apk
releaseNotes: ${{ github.ref_name }}
# 詳細なログ出力
debug: true
Version up
name: bump
on:
workflow_dispatch:
inputs:
bump:
type: choice
description: Please Choice Bump Target
options:
- build
- patch
- minor
- major
env:
GIT_USER_EMAIL: '41898282+github-actions[bot]@users.noreply.github.com'
GIT_USER_NAME: 'github-actions[bot]'
permissions:
contents: write
jobs:
bump:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
# repositoryをセットアップ
- name: Checkout repository
uses: actions/checkout@v4
# flutterをセットアップ
- name: Flutter get
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: latest
cache: true
- name: Run flutter version
run: flutter --version
# Packageをセットアップ
- name: Setup packages
run: |
flutter pub get
dart run build_runner build -d
- name: Init git config
run: |
git config --local user.name $GIT_USER_NAME
git config --local user.email $GIT_USER_EMAIL
- name: Bump up version
run: |
echo choice: ${{ github.event.inputs.bump }}
flutter pub run cider bump ${{ github.event.inputs.bump }} --bump-build
echo "BUMP_VERSION=$(flutter pub run cider version)" >> $GITHUB_ENV
- name: Commit and push pubspec.yaml
run: |
git add -u pubspec.yaml
echo "Bumped version number to $BUMP_VERSION" | git commit --file=-
git push
各種環境変数一覧
環境変数名 | 対象OS | 説明 |
---|---|---|
ANDROID_ALIAS_PASSWORD | Android | Android エイリアスパスワード |
ANDROID_KEY_ALIAS | Android | Android keyエイリアス |
ANDROID_KEY_JKS | Android | base64エンコード済みAndroid key jks android/app/key.jks |
ANDROID_STORE_PASSWORD | Android | Android ストアパスワード |
CREDENTIAL_FILE_CONTENT | Android/iOS | base64エンコード済みfirebaseサービスユーザーcredential json |
DANGER_GITHUB_API_TOKEN | Android/iOS | Danger用のGit Hub APIトークン |
EXPORT_OPTIONS | iOS | ローカルでarchiveしたときに一緒に生成されるExportOptions.plistをbase64にエンコードし設置 |
FIREBASE_ANDROID_ID | Android | firebase プロジェクト設定のアプリ ID(1:から始まる値) |
FIREBASE_AUTH_TOKEN | Android/iOS | Firebaseのトークン情報 |
FIREBASE_IOS_ID | iOS | firebase プロジェクト設定のアプリ ID(1:から始まる値) |
FIREBASE_PROJ_NAME | Android/iOS | firebaseのプロジェクト名 |
FLAVOR_ENV_NAME | Android/iOS | buildしたい環境名(Flavorと環境名を統一しているため) |
IOS_API_AUTHKEY_P8_BASE64 | iOS | AppStoreConnectAPIで払い出したAPI情報(base64エンコード済みp8ファイル) |
IOS_API_ISSURE_ID | iOS | AppStoreConnectAPIで払い出したAPI情報(IssueID) |
IOS_API_KEY_ID | iOS | AppStoreConnectAPIで払い出したAPI情報(API key) |
参考記事
Discussion