[Flutter] Fastlaneを使ってデプロイを自動化する

2023-03-18 hit count image

Fastlaneを使ってFlutterで開発したアプリをデプロイする方法について説明します。

概要

Flutterでアプリを開発したら、このように開発したアプリをユーザが使えるようにデプロイをします。Flutterの公式ドキュメントにはFlutterで開発したアプリをデプロイする方法について説明をしております。これを参考するとFlutterで開発したアプリをデプロイすることができます。

Fastlaneはネーティブで開発したアプリもハイブリッドアプリ(Flutter, React Nativeなど)も簡単にデプロイできるように手伝ってくれるツールです。

今回のブログポストではFastlaneを使ってFlutterで開発したアプリをデプロイする方法について説明します。

Fastlane

fastlane is the easiest way to automate beta deployments and releases for your iOS and Android apps. It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing your application.

FastlaneはiOSとアンドロイドのテスト用のデプロイまたは、リリース用のデプロイを簡単に自動化してくれるツールです。デプロイだけではなく、スクリンショット、コードサイニング、アプリストア登録情報などを生成、管理することができるツールです。

今回のブログポストではスクリンショット、アプリストア登録情報などは登録されたと仮定して、テスト用・リリース用のデプロイを自動化する部分だけを扱う予定です。

スクリンショット、アプリストア登録情報生成など、他の機能も使いたい方は公式サイトを参考してください。

Flutterの公式サイトにもCI/CDのためFastlaneを使う方法について案内してますので、公式ドキュメントも参考してみてください。

Fastlaneのインストール

Fastlaneを使ってFlutterで開発したアプリをデプロイするためにはFastlaneをインストールする必要があります。次のコマンドを使ってFastlaneをインストールしてください。

# Using RubyGems
sudo gem install fastlane -NV

# Alternatively using Homebrew
brew cask install fastlane

公式サイトではHomebrewを使ってインストールする方法とRubyGemsを使ってインストールする方法を案内してます。

私は最初Homebrewを使ってインストールして、テストしてみましたが、うまく動作してない部分がありました。したがってRubyGemsを使ってインストールすることをお勧めします。もしHomebrewでうまく動作しなかったら、RubyGemsで再びインストールして試してみてください。

iOS

Flutterで開発したiOSアプリをFastlaneを使ってデプロイする方法について説明します。

iOSのためFastlaneの初期化

下記のコマンドを使ってiOSのためFastlaneを初期化します。

cd ios
fastlane init

このコマンドを実行すると下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - iOS初期化

今回のブログポストではTestflight用とアプリストアにデプロイするための設定について見る予定です。したがって2番または3番を選択して進めばいいです。

2. Automate beta distribution to TestFlight
3. Automate App Store distribution

ここではTestflight用デプロイをするため2番を選択して進めました。

Fastlaneを使ってFlutterアプリ自動デプロイ - iOSプロジェクト選択

2番を選択して進むと上のようにiOSのプロジェクトを選択する画面が確認できます。Flutterで開発したアプリをデプロイする予定なので、2番を選択して進めます。

Fastlaneを使ってFlutterアプリ自動デプロイ - Appleログイン

2番を選択して進むと、上のようにAppleログインのための画面が確認できます。iOSのアプリデプロイをするため使うApple store connectのログインIDを入力します。

Fastlaneを使ってFlutterアプリ自動デプロイ - iOS設定

私は既にFastlaneを使ってログインをしたことがあるので、上のような画面が表示されます。最初Fastlaneを設定する方は2段階認証の手続きが表示されます。

上のような画面以外にも何回Continue by pressing Enterを入力する画面が表示されます。Enterキーを押して進めて設定を完了させます。

iOS用Fastlaneフォルダやファイル

iOSの設定を完了するとFlutterのiosフォルダ下に下記のようなフォルダやファイルが生成されることが確認できます。

|- fastlane
|  |- Appfile
|  |- Fastfile
|- Gemfile
|- Gemfile.lock

各フォルダやファイルを詳しく見てみましょう。

  • fastlaneフォルダ: Fastlaneの設定や実行ファイルたちが入ってるフォルダです。
  • Gemfile, Gemfile.lock: FastlaneはRubyで開発されてます。このファイルたちはRubyでライブラリを管理するためのファイルたちです。

Fastlaneを実行するため、設定内容が入ってるfastlane/Appfileファイルでコメントを消すと下記のようです。

app_identifier("io.github.dev-yakuza.kumoncho")
apple_id("[email protected]")

itc_team_id("119423059")
team_id("WFDJCJXQZ6")

AppfileファイルはiOSの自動デプロイのためのFastlane設定ファイルです。簡単なファイルなので、詳しい説明は省略します。

その次は実際アプリをデプロイするための実行ファイルであるfastlane/Fastfileファイルでコメントを消すと下記のようです。

default_platform(:ios)

platform :ios do
  desc "Push a new beta build to TestFlight"
  lane :beta do
    increment_build_number(xcodeproj: "kumoncho.xcodeproj")
    build_app(workspace: "kumoncho.xcworkspace", scheme: "kumoncho")
    upload_to_testflight
  end
end

ここで表示されたFastlaneを実行するためには次のコマンドを実行することができます。

# cd ios
fastlane beta

このようにFastlaneを実行するとiOSののbuild numberを上げて(increment_build_number)、アプリをビルドした後(build_app)、Testflight用でアップロードします。(upload_to_testflight)

iOS用実行ファイル修正

基本的に提供されるfastlaneファイルでは完璧にデプロイ自動化をすることができません。したがって、iOS用デプロイを自動化するためfastlane/Fastfileファイルを下記のように修正します。

# frozen_string_literal: true

default_platform(:ios)

platform :ios do
  def updateVersion(options)
    if options[:version]
      version = options[:version]
    else
      version = prompt(text: "Enter the version type or specific version\n(major, minor, patch or 1.0.0): ")
    end

    re = /\d+.\d+.\d+/
    versionNum = version[re, 0]

    if versionNum
      increment_version_number(
        version_number: versionNum
      )
    elsif version == 'major' || version == 'minor' || version == 'patch'
      increment_version_number(
        bump_type: version
      )
    else
      UI.user_error!('[ERROR] Wrong version!!!!!!')
    end
  end

  def certificate(options)
    if options[:type] == 'github'
      create_keychain(
        name: 'ios_app_keychain',
        password: '****************',
        timeout: 1800,
        default_keychain: true,
        unlock: true,
        lock_when_sleeps: false
      )
      import_certificate(
        certificate_path: 'distribution.p12',
        certificate_password: '****************',
        keychain_name: 'ios_app_keychain',
        keychain_password: '****************'
      )
    end
    install_provisioning_profile(path: 'distribution.mobileprovision')
    update_project_provisioning(
      xcodeproj: 'Runner.xcodeproj',
      target_filter: 'github',
      profile: 'distribution.mobileprovision',
      build_configuration: 'Release'
    )
    api_key = app_store_connect_api_key(
      key_id: '**************',
      issuer_id: '***********************',
      key_filepath: 'distribution.p8'
    )
    api_key
  end

  desc 'Update version'
  lane :version do |options|
    updateVersion(options)
    increment_build_number(xcodeproj: 'Runner.xcodeproj')
  end

  desc 'Submit review only'
  lane :submit_review do |_options|
    upload_to_app_store(
      submit_for_review: true,
      automatic_release: true,
      force: true,
      skip_metadata: true,
      skip_screenshots: true,
      skip_binary_upload: true
    )
  end

  desc 'Push a new beta build to TestFlight'
  lane :beta do |options|
    api_key = certificate(options)
    build_app(
      workspace: 'Runner.xcworkspace',
      scheme: 'Runner',
    )
    upload_to_testflight(api_key: api_key)
  end

  desc 'Push a new release build to the App Store'
  lane :release do |options|
    api_key = certificate(options)
    build_app(
      workspace: 'Runner.xcworkspace',
      scheme: 'Runner',
    )
    upload_to_app_store(
      force: true,
      reject_if_possible: true,
      skip_metadata: false,
      skip_screenshots: true,
      languages: ['en-US', 'ja','ko'],
      release_notes: {
        "default" => "bug fixed",
        "en-US" => "bug fixed",
        "ja" => "バグ修正",
        "ko" => "버그 수정"
      },
      submit_for_review: true,
      precheck_include_in_app_purchases: false,
      automatic_release: true,
      submission_information: {
        add_id_info_uses_idfa: false,
        export_compliance_encryption_updated: false,
        export_compliance_uses_encryption: false
      },
      api_key: api_key
    )
  end
end

ユーザが入力したバージョンに合わせて、バージョンを修正する関数を定義しました。

platform :ios do
  def updateVersion(options)
    ...
  end
  ...
  desc 'Update version'
  lane :version do |options|
    updateVersion(options)
    increment_build_number(xcodeproj: 'Runner.xcodeproj')
  end
  ...
end

Fastlaneコマンドを使ってデプロイするアプリのバージョンをアップデートすることができるversionと言うコマンドを作りました。このコマンドは次のように実行してアプリのバージョンをアップデートすることができます。

# fastlane version version:1.0.0
# fastlane version version:major
# fastlane version version:minor
fastlane version version:patch

もし、パラーメータがを入力してない場合、ユーザの入力を待つようにしました。

def updateVersion(options)
  if options[:version]
    version = options[:version]
  else
    version = prompt(text: "Enter the version type or specific version\n(major, minor, patch or 1.0.0): ")
  end
...

Fastlaneを使ってデプロイするためには認証書(Certification)とプロビジョニングファイル(Provisioning)、そしてアプリストアコネクションAPIキー(App store connect API key)が必要です。

このファイルたちが用意できたら次のようにcertificate関数を使ってファイルを登録して、APIキーを返すようにして必要なところで使えるように作りました。

# frozen_string_literal: true

default_platform(:ios)

platform :ios do
  ...
  def certificate(options)
    if options[:type] == 'github'
      create_keychain(
        name: 'ios_app_keychain',
        password: '****************',
        timeout: 1800,
        default_keychain: true,
        unlock: true,
        lock_when_sleeps: false
      )
      import_certificate(
        certificate_path: 'distribution.p12',
        certificate_password: '****************',
        keychain_name: 'ios_app_keychain',
        keychain_password: '****************'
      )
    end
    install_provisioning_profile(path: 'distribution.mobileprovision')
    update_project_provisioning(
      xcodeproj: 'Runner.xcodeproj',
      target_filter: 'github',
      profile: 'distribution.mobileprovision',
      build_configuration: 'Release'
    )
    api_key = app_store_connect_api_key(
      key_id: '**************',
      issuer_id: '***********************',
      key_filepath: 'distribution.p8'
    )
    api_key
  end
  ...
end

このように作ったAPIキーは次のようにTestflightやアプリストアへデプロイする時活用されます。

# frozen_string_literal: true

default_platform(:ios)

platform :ios do
  ...
  desc 'Push a new beta build to TestFlight'
  lane :beta do |options|
    api_key = certificate(options)
    build_app(
      workspace: 'Runner.xcworkspace',
      scheme: 'Runner',
    )
    upload_to_testflight(api_key: api_key)
  end

  desc 'Push a new release build to the App Store'
  lane :release do |options|
    api_key = certificate(options)
    build_app(
      workspace: 'Runner.xcworkspace',
      scheme: 'Runner',
    )
    upload_to_app_store(
      force: true,
      reject_if_possible: true,
      skip_metadata: false,
      skip_screenshots: true,
      languages: ['en-US', 'ja','ko'],
      release_notes: {
        "default" => "bug fixed",
        "en-US" => "bug fixed",
        "ja" => "バグ修正",
        "ko" => "버그 수정"
      },
      submit_for_review: true,
      precheck_include_in_app_purchases: false,
      automatic_release: true,
      submission_information: {
        add_id_info_uses_idfa: false,
        export_compliance_encryption_updated: false,
        export_compliance_uses_encryption: false
      },
      api_key: api_key
    )
  end
end

Testflight用のデプロイスクリプトを見ると、認証書を登録した後、アプリをビルどして、Fastlaneが提供するupload_to_testflight関数を使ってデプロイすることが確認できます。

...
platform :ios do
  ...
  desc 'Push a new beta build to TestFlight'
  lane :beta do |options|
    api_key = certificate(options)
    build_app(
      workspace: 'Runner.xcworkspace',
      scheme: 'Runner',
    )
    upload_to_testflight(api_key: api_key)
  end
  ...
end

アプリストア用でデプロイするコードもTestflight用と同じように認証書を登録した後、アプリをビルドします。その後、upload_to_app_store関数を使ってアプリをデプロイするようにしました。

...
platform :ios do
  ...
  desc 'Push a new release build to the App Store'
  lane :release do |options|
    api_key = certificate(options)
    build_app(
      workspace: 'Runner.xcworkspace',
      scheme: 'Runner',
    )
    upload_to_app_store(
      force: true,
      reject_if_possible: true,
      skip_metadata: false,
      skip_screenshots: true,
      languages: ['en-US', 'ja','ko'],
      release_notes: {
        "default" => "bug fixed",
        "en-US" => "bug fixed",
        "ja" => "バグ修正",
        "ko" => "버그 수정"
      },
      submit_for_review: true,
      precheck_include_in_app_purchases: false,
      automatic_release: true,
      submission_information: {
        add_id_info_uses_idfa: false,
        export_compliance_encryption_updated: false,
        export_compliance_uses_encryption: false
      },
      api_key: api_key
    )
  end
end

upload_to_app_store関数で使ったオプションは次のようです。

  • force: Fastlaneが生成するHTML reportを生成されないようにします。
  • reject_if_possible: 審査待機中バージョンがある場合、キャンセルします。
  • skip_metadata: アプリストアの情報を登録するか決めます。自動デプロイする時、バージョンの修正内容を作成する必要があるので、情報を登録するように設定します。
  • skip_screenshots: 私は既にデプロイしたアプリについてデプロイ自動化をしています。なので、スクリンショットを再びアップロードする必要はないです。
  • languages: 現在ストアで登録されたアプリのローカライズを設定します。使える言語はar-SA, ca, cs, da, de-DE, el, en-AU, en-CA, en-GB, en-US, es-ES, es-MX, fi, fr-CA, fr-FR, he, hi, hr, hu, id, it, ja, ko, ms, nl-NL, no, pl, pt-BR, pt-PT, ro, ru, sk, sv, th, tr, uk, vi, zh-Hans, zh-Hantで、詳しい内容は公式サイトを参考してください。(公式サイト)
  • release_notes: iOSはアプリを再びデプロイする時、Release notesを必ず作成する必要があります。私が使ってるスクリプトは3カ国語をサポートするアプリなので、defaultと3カ国語のRelease notesを作成するようにしました。
  • submit_for_review: アプリ審査に提出するようにします。
  • automatic_release: 審査後、アプリを自動デプロイするように設定します。この値が設定されないと、アプリ審査が通った後、開発者が手動でデプロイする必要があります。
  • submission_information: デプロイ前、暗号化、広告があるかどうかなどを尋ねるオプションを設定します。

これ以外にもたくさんのオプションがあります。詳しい内容は公式サイトを参考してください。

iOS用Fastlaneを実行してTestflightへデプロイ

iOS用のFastlaneを使って自動でデプロイする準備が終わりました。次はFastlaneを使ってアプリを自動でデプロイしてみましょう。

下記のコマンドを使ってFlutterで作成したアプリをTestflightへデプロイします。

# cd ios
fastlane beta version:patch

デプロイが終わるまで、かなり時間がかかります。デプロイが終わったら下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - iOS Testflightデプロイ

もちろんApp store connectのTestflightでも上手くデプロイされたことが確認できます。

iOS用Fastlaneを実行してアプリストアへデプロイ

次は下記のFastlaneコマンドを使ってFlutterで開発したアプリをアプリストアへデプロイしてみましょう。

# cd ios
fastlane release version:patch

デプロイが終わったら下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - iOSアプリデプロイ

またApp store connectにも上手くデプロイされたことが確認できます。

アンドロイド

次はFlutterで開発したアンドロイドアプリをFastlaneを使ってデプロイを自動化してみます。

API accessのためService Account生成

Fastlaneを使ってアンドロイドをデプロイする時、グーグルのAPIを使うのでGoogle Developer Service Accountを生成する必要があります。

Google Developer Service Accountを生成するため、下記のリンクを使ってグーグルプレイコンソール(Google Play Console)へ移動します。

グーグルプレイコンソールへ移動すると下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - グーグルプレイコンソール

左メニューのSettingsを選択します。そしてDeveloper account下にあるAPI accessメニューを選択します。

Fastlaneを使ってFlutterアプリ自動デプロイ - グーグルプレイコンソール api access メニュー

上のような画面が見えたら、CREATE NEW PROJECTボタンを押して、新しいプロジェクトを生成します。

Fastlaneを使ってFlutterアプリ自動デプロイ - グーグルプレイコンソール api access, service account

新しいプロジェクトが生成されたら、上のような画面が確認できます。下にあるCREATE SERVICE ACCOUNTボタンを選択すると、下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - グーグルプレイコンソール api access, how to create service account

上のような画面でGoogle API Consoleリンクを選択します。選択したら、下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - Google API Console

上にあるCREATE SERVICE ACCOUNTボタンを選択します。選択したら下記のように新しいService accountを生成する画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - Google API Console, service account 生成

上のような画面で、Service account nameに名前を入力して、CREATEボタンを押してService accountを生成します。(私はService account nameにgoogle-play-fastlane-deploymentを入力しました。)

Fastlaneを使ってFlutterアプリ自動デプロイ - Google API Console, service account 役割設定

上のような画面が見えたら、Roleを選択してService Account Userを検索して選択します。RoleでService Account Userを設定したら、下にあるCONTINUEボタンを押して次に進みます。

Fastlaneを使ってFlutterアプリ自動デプロイ - Google API Console, service account キー生成

上のような画面が見えたら、下にあるCREATE KEYを選択してJSONが選択された状態でCREATEボタンを押してキーを生成します。

Fastlaneを使ってFlutterアプリ自動デプロイ - Google API Console, service account JSON キー生成

CREATEボタンを押してキーを生成したらJSON形でファイルが自動でダウンロードされます。このファイルをFlutterプロジェクトのandroidフォルダの中にコピーします。最後にDONEボタンを押してService Accountを生成します。

そして元の画面に戻って右下にあるDONEボタンを押してService Account生成を終了します。

Fastlaneを使ってFlutterアプリ自動デプロイ - グーグルプレイコンソール api access, how to create service account

そしたら以前と違って下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - グーグルプレイコンソール Service Account 生成完了

次は権限を与えるため、右下のGRANT ACCESSボタンを選択します。

Fastlaneを使ってFlutterアプリ自動デプロイ - グーグルプレイコンソール Service Account 権限設定

上のような画面が出たら下にスクロールしてADD USERを選択してユーザを登録します。

アンドロイドのためFastlaneの初期化

次はアンドロイド用のFastlaneを生成しててみましょう。下記のコマンドを実行してアンドロイド用のFastlaneを生成します。

cd android
fastlane init

上のコマンドを実行したら下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - アンドロイド初期化: package name

アンドロイドプロジェクトのPackage Nameを入力します。(ex> io.github.dev.yakuza.kumoncho)そしたら、次のようにJSONファイルのパスを入力する画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - アンドロイド初期化: JSON path

Service Accountを生成した時、ダウンロードしたJSONファイルをandroidフォルダへコピーしました。ここではこのパスを指定します。(ex> app-xxx.json)

Fastlaneを使ってFlutterアプリ自動デプロイ - アンドロイド初期化: ダウンロード metadata

次はアンドロイドをデプロイする時、登録したストア情報(metadata)をダウンロードするかどうかを聞いてくれます。私は既にデプロイしたアプリを自動化してるので、ストアの情報を更新する必要がないです。したがって、nを入力してストア情報をダウンロードしないようにしました。

上のような画面以外にも何回もContinue by pressing Enterを入力する画面が表示されます。Enterキーを押して進めて設定を完了します。

アンドロイド用Fastlaneのフォルダやファイル

アンドロイドの設定を完了したらFlutterのandroidフォルダ下に下記のようなフォルダやファイルが生成されることが確認できます。

|- fastlane
|  |- Appfile
|  |- Fastfile
|- Gemfile
|- Gemfile.lock

各フォルダやファイルを詳しく見てみましょう。

  • fastlaneフォルダ: Fastlaneの設定や実行ファイルが入ってるフォルダです。
  • Gemfile, Gemfile.lock: FastlaneはRubyで開発されてます。このファイルたちはRubyでライブラリを管理するためのファイルたちです。

Fastlaneを実行するため設定内容が入ってるfastlane/Appfileファイルでコメントを消して確認すると下記のようです。

json_key_file("api-xxx.json")
package_name("io.github.dev.yakuza.kumoncho")

私たちが設定したPacakge NameとJSONファイルのパスが設定されたことが確認できます。次は、実際アプリをデプロイするための実行ファイルであるfastlane/Fastfileファイルでコメントを消すと下記のようです。

default_platform(:android)

platform :android do
  desc "Runs all the tests"
  lane :test do
    gradle(task: "test")
  end

  desc "Submit a new Beta"
  lane :beta do
    gradle(task: "clean assembleRelease")
    crashlytics
  end

  desc "Deploy a new version to the Google Play"
  lane :deploy do
    gradle(task: "clean assembleRelease")
    upload_to_play_store
  end
end

iOSとは違ってbetadeploy、二つのlaneが生成されたことが確認できます。このFastlaneも下記のようなコマンドで実行できます。

# cd android
fastlane beta
fastlane deploy

しかし、完璧な自動化のためにはFastfileを修正する必要があります。

アンドロイド用実行ファイル修正

基本的提供されるfastlaneファイルでは完璧に自動化をすることができないです。したがって、アンドロイド用デプロイを自動化するためfastlane/Fastfileファイルを下記のように修正します。

# frozen_string_literal: true

default_platform(:android)

platform :android do
  def increment_version_code
    path = '../app/build.gradle'
    re = /versionCode\s+(\d+)/

    s = File.read(path)
    versionCode = s[re, 1].to_i
    s[re, 1] = (versionCode + 1).to_s

    f = File.new(path, 'w')
    f.write(s)
    f.close
  end

  def increment_version_number(bump_type: nil, version_number: nil)
    path = '../app/build.gradle'
    re = /versionName\s+("\d+.\d+.\d+")/
    s = File.read(path)
    versionName = s[re, 1].gsub!('"', '').split('.')

    major = versionName[0].to_i
    minor = versionName[1].to_i
    patch = versionName[2].to_i

    if bump_type == 'major'
      major += 1
      minor = 0
      patch = 0
    elsif bump_type == 'minor'
      minor += 1
      patch = 0
    elsif bump_type == 'patch'
      patch += 1
    end

    s[re, 1] = if version_number
                 "\"#{version_number}\""
               else
                 "\"#{major}.#{minor}.#{patch}\""
               end

    f = File.new(path, 'w')
    f.write(s)
    f.close
    increment_version_code
  end

  def updateVersion(options)
    version = options[:version] || prompt(text: "Enter the version type or specific version\n(major, minor, patch or 1.0.0): ")

    re = /\d+.\d+.\d+/
    versionNum = version[re, 0]

    if versionNum
      increment_version_number(
        version_number: versionNum
      )
    elsif %w[major minor patch].include?(version)
      increment_version_number(
        bump_type: version
      )
    else
      UI.user_error!('[ERROR] Wrong version!!!!!!')
    end
  end

  desc 'Update version'
  lane :version do |options|
    updateVersion(options)
  end

  desc 'Submit a new Beta'
  lane :beta do |_options|
    gradle(task: 'clean bundleRelease')
    upload_to_play_store(
      skip_upload_metadata: true,
      skip_upload_screenshots: true,
      skip_upload_images: true,
      skip_upload_apk: true,
      track: 'internal',
      aab: '../build/app/outputs/bundle/release/app-release.aab'
    )
  end

  desc 'Deploy a new version to the Google Play'
  lane :release do |_options|
    gradle(task: 'clean bundleRelease')
    upload_to_play_store(
      skip_upload_metadata: true,
      skip_upload_screenshots: true,
      skip_upload_images: true,
      skip_upload_apk: true,
      aab: '../build/app/outputs/bundle/release/app-release.aab'
    )
  end
end

追加した内容を詳しく見てみましょう。アンドロイドはiOSとは違ってアプリのバージョンをアップデートする機能を提供してないです。(私が見つけてないかもしれないです。もし、してる方はフィードバックお願いします。)したがって、アンドロイドのversionCodeとversionNameをアップデートする機能を実装しました。

platform :android do
  def increment_version_code
    ...
  end

  def increment_version_number(bump_type: nil, version_number: nil)
    ...
  end

  def updateVersion(options)
    ...
  end
  ...
end

バージョンをアップデートするupdateVersion関数はiOSで説明したので、詳しい説明は省略します。

ンドロイドのテスト用Fastlane

テスト用でアプリをデプロイするためのFastlaneを見てみましょう。

platform :android do
  ...
  desc 'Submit a new Beta'
  lane :beta do |_options|
    gradle(task: 'clean bundleRelease')
    upload_to_play_store(
      skip_upload_metadata: true,
      skip_upload_screenshots: true,
      skip_upload_images: true,
      skip_upload_apk: true,
      track: 'internal',
      aab: '../build/app/outputs/bundle/release/app-release.aab'
    )
  end
  ...
end

アンドロイドはGradleのcleanbundleReleaseでアプリをビルドするようにしました。(assembleReleaseではない)また、upload_to_play_storeの関数でtrack: 'internal'を使ってinternal test用でデプロイするようにしました。

アンドロイドはiOSと違ってRelease notes(change log)を作成する必要がないので、スタアに関数流全ての機能はskipするように設定しました。

最後にbundleReleaseを使ってaabファイルを生成してアップロードする予定なので、skip_upload_apktrueで設定しました。

アンドロイドのグーグルプレイストア用Fastlane

次はグーグルストアへデプロイするためのFastlaneコードを見てみましょう。

...
platform :android do
  ...
  desc 'Deploy a new version to the Google Play'
  lane :release do |_options|
    gradle(task: 'clean bundleRelease')
    upload_to_play_store(
      skip_upload_metadata: true,
      skip_upload_screenshots: true,
      skip_upload_images: true,
      skip_upload_apk: true,
      aab: '../build/app/outputs/bundle/release/app-release.aab'
    )
  end
end

iOSと同じようにするためlane :deploylane :releaseに名前を変更しました。upload_to_play_store関数のtrackパラメータがないこと以外にはbeta用と同じなので詳しい説明は省略します。

アンドロイド用Fastlaneの実行

Fastlaneを使ってアンドロイドで自動でデプロイする準備が終わりました。次はFastlaneを使ってアプリを自動デプロイしてみましょう。

下記のコマンドを使ってFlutterで作成したアプリをinternal testへデプロイしてみます。

# cd android
fastlane beta version:patch

デプロイが完了されるまで、少し時間が掛かります。デプロイが完了されると下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - アンドロイドinternal testデプロイ

もちろんPlay store consoleでもinternal testへ上手くデプロイされたことが確認できます。

そして次のコマンドを実行して実際デプロイをしてみます。

# cd android
fastlane release version:patch

デプロイが完了されたら下記のような画面が確認できます。

Fastlaneを使ってFlutterアプリ自動デプロイ - アンドロイドアプリストアデプロイ

また、Google Play storeでも上手くデプロイされたことが確認できます。

gitignore

Fastlaneを使ってデプロイをすると、それによるファイルたちが生成されます。このファイル中でGitで管理する必要がないファイルたちを.gitignoreファイルを開いて下記のように追加します。

...
# fastlane
ios/*.mobileprovision
ios/*.cer
ios/*.dSYM.zip
android/fastlane/README.md
ios/fastlane/README.md

完了

これでFastlaneを使ってFlutterで作成したアプリを自動でデプロイする方法について見てみました。今回のブログポストで説明した内容はもちろんNativeで開発したアプリでも活用できるので多くの方にお役に立つと思います。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。

Posts