【Flutter】fastlaneでGooglePlayの内部テストを配信する

2024/06/01に公開

タイトル通り、fastlane で GooglePlay の内部テストを配信できるようにしていきます。


はじめに

fastlane の導入方法等については、この記事では記載しません。
fastlane の導入方法等は、こちらの記事も参照してください。
https://docs.flutter.dev/deployment/cd#fastlane
https://zenn.dev/ncdc/articles/fastlane_match#fastlane-match-の導入


全体像

使用するフォルダ構成
project(root)
└─ android
   └─ fastlane
       ├─ Appfile
       ├─ Fastfile
       └─ <key>.json
Appfile
# 1.keyやpackageNameの設定
json_key_file("<jsonKey path>") # Path to the json secret file
package_name("<package名>") # e.g. com.krausefx.app
Fastfile
default_platform(:android)

platform :android do
  desc "buildとGooglePlay(内部テスト)へのアップロード"
  lane :upload_play_store do
    # 2.実行ブランチ設定
    # 特定のbranch以外で実行された場合はエラーを出力。
    current_branch = `git rev-parse --abbrev-ref HEAD`.strip
    if current_branch != "<branch名>"
      UI.user_error!("This lane can only be run from the '<branch名>' branch.")
    end

    # 3.local.propertiesからバージョン名を取得
    properties_path = "../local.properties"
    version_name = ""

    if File.exist?(properties_path)
      File.open(properties_path, 'r') do |file|
        file.each_line do |line|
          if line.include?('flutter.versionName')
            # flutter.versionName の値を取得
            version_name = line.split('=')[1].strip
          end
        end
      end
    else
      UI.error("local.properties ファイルが見つかりません。パスを確認してください。")
    end

    # 4.GooglePlayにアップロードされている最新のビルド番号を取得してインクリメント
    previous_build_number = google_play_track_version_codes(
      track: "internal", # internal(内部テスト)を指定
    )[0]
    new_version_code = previous_build_number + 1

    # 5.flutterビルド
    sh( "fvm","flutter","clean" )
    sh( "fvm","flutter","build","appbundle","--dart-define-from-file=dart_defines/dev.json","--build-number=#{new_version_code}" )

    # 6.ビルドされたaabファイルをGooglePlay(内部テスト)にアップロード
    upload_to_play_store(
      track: 'internal', # internal(内部テスト)を指定
      version_name: "#{new_version_code}(#{version_name})",
      aab: "../build/app/outputs/bundle/release/app-release.aab",
      release_status: "draft", # draft(下書き状態)を指定
      skip_upload_apk: true,
      skip_upload_metadata: true,
      skip_upload_images: true,
      skip_upload_screenshots: true
    )
  end
end


各処理の詳細、補足

1.store の共通設定

AppFile に key 情報やパッケージ名などの共通設定を記載しておくと、Fastfile で fastlane の関数を呼び出す際に毎回指定しなくて済むようになります。

jsonKey に関しては、GoogleCloud のコンソールで API の設定をして jsonKey を取得し、取得した json ファイルパスを指定します。
GoogleCloud コンソールでの設定方法はドキュメント参照。
https://docs.fastlane.tools/actions/upload_to_play_store/


2.実行ブランチ設定

開発途中のブランチとかで間違って実行しないよう、特定のブランチでしか実行できないようにしました。
主にはproductiondevelopブランチとかになるのかと思います。


3.local.properties からバージョン名を取得

内部テストにアップロードする際の「リリース名」を、手動でアップロードする時と同じ形式にしたかったため、local.propertiesからバージョン名を取得する処理をいれました。

upload_to_play_storeのデフォルト設定だとバージョン名だけの表示(ex.0.1.0)となるので、添付のようにビルド番号(バージョン名)としたかったため。


4.ビルド番号設定

latest_testflight_build_number: Doc
ビルド番号は、GooglePlay の内部テスト にアップロードされている最新のビルド番号を取得して、インクリメントするようにしました。

【補足】
trackの値の違い。
参照:Google Play Developer API

  • internal:内部テスト
  • alpha:クローズドテスト
  • beta:オープンテスト
  • production:製品版リリース

ビルド番号の管理方法について、色々と考え用はありそうなのでお好みでです。

【参考記事】


5.flutter ビルド

flutter コマンドをshで実行します。

【補足】
fastlane のアクションのgradleと、flutter コマンドのビルドとの違いがよく分からず。。。

gradleアクションだと--dart-define-from-fileがうまく適用させることができなかったので、shで flutter コマンドを実行するようにしました。
うまいことやればgradleアクションでも適用させれるるかもです。。。

--dart-define-from-fileは Flutter3.17 以降で非推奨(無効?廃止?)となっているので、今後は別の方法で対応する方がいいのかもしれない。(が、調べた感じベストプラクティスがまだ無さそう?)
https://github.com/flutter/flutter/issues/138793


6.GooglePlay にアップロード

作成された aab ファイルを GooglePlay にアップロードする処理です。
ドキュメントには他にもプロパティの記載があるので、必要に応じて設定してください。
https://docs.fastlane.tools/actions/upload_to_play_store/


【注意】
現状の記載だと、release_statusdraft以外だと以下のエラーになる。
= 内部テストが下書き状態でしかリリースできない。

[!] Google Api Error: Invalid request - Only releases with status draft may be created on draft app.

原因が不明。自動化したいための fastlane だが、なぜか TestFlight のように配信までが fastlane コマンドから実施できない。最後まで自動化する方法がわからない。

https://support.google.com/googleplay/android-developer/thread/240224208/google-play-api-how-can-i-make-a-draft-release-available-to-internal-testers?hl=en

https://github.com/fastlane/fastlane/discussions/18293

初期アルファ版を Play ストアコンソールで直接リリースしていないことを意味します。

初期リリースもしてるはずだけど、エラーは消えない。

https://jonathancardoso.com/en/blog/automated-release-publish-deployment-react-native-android-apps-using-fastlane-part-1-play-store/#sending-alpha-version-to-the-play-store-using-fastlane

→ 引き続き調査。


【備考】


備考

  • fastlane を実行する際に、java のバージョンで怒られることがあります。Java と Gradle のバージョンが違うと。
    私はSDKMANというツールで java のバージョン管理をして解決しました。
    参考:
    「mac で SDKMAN を使って Java のバージョンを管理する」
    「AndroidStudio Java のバージョンによるエラーの解決法」

    ┌─ Flutter Fix ─────────────────────────────────────────────────────────────────────────────────┐
    │ [!] Your project's Gradle version is incompatible with the Java version that Flutter is using │
    │ for Gradle.                                                                                   │
    │                                                                                               │
    │ To fix this issue, first, check the Java version used by Flutter by running `flutter doctor   │
    │ --verbose`.                                                                                   │
    
  • 今回使用した fastlane 提供の関数はエイリアスが提供されているので、そちらを使用しても問題なく実行できます。

    • upload_to_play_storesupplyに変更しても同じ結果となります。
    • ドキュメント的にはエイリアスされた方がメイン?の記載になっているので、エイリアス版を使用する方が良いかもです。
  • android の gradle におけるassemblebundleの違い

    • assemble: apk ファイルを生成する
    • bundle: aab ファイルを生成する
  • fastlane supply initが実施しようとすると失敗する。

TestFlight 版の fastlane 構築についても軽くまとめてます。よければ参考にしてください。
https://zenn.dev/ncdc/articles/fastlane_testflight




参考記事

【参考記事】
GitHubで編集を提案
NCDCエンジニアブログ

Discussion