第7章

Firebase HostingでWebアプリを公開する

FlutterのWebアプリをビルドし、Firebase Hostingで公開・更新する手順を学びます。

この章で学ぶこと

  • FlutterのWeb版を公開用ファイルに変換する方法
  • Firebase Hostingの初期設定とデプロイ方法
  • 公開後の動作確認と、修正したアプリの更新方法

「Firebaseでデータを保存・読み込みする」の章で作ったFirebaseカウンターを、URLから開けるWebアプリとして公開します。ここで使うのはFirebase Hostingです。Android・iOSアプリをストアへ配信する手順は別になります。

ビルドとデプロイの違い

ビルドはDartのコードなどをブラウザーで動かせるファイルに変換すること、デプロイはそのファイルを公開先へ送ることです。

Flutterのコード(lib/main.dartなど)
       ↓ flutter build web
公開用ファイル(build/web)
       ↓ firebase deploy --only hosting
Firebase Hosting
       ↓ URLへアクセス
利用者のブラウザー

Hostingが配るのは画面やアプリのプログラムです。ログインはAuthentication、カウンターの保存はRealtime Databaseが引き続き担当します。Hostingへのデプロイだけでは、DatabaseのルールやCloud Functionsは更新されません。

1. 公開前の準備をする

カウンターの実習で使ったhello_appフォルダで作業します。Firebase CLIとFlutterFire CLIが導入済みで、lib/firebase_options.dartが生成されていることを確認してください。

公開先のプロジェクトを確認する

firebase login
firebase projects:list
firebase use

projects:listに出るProject IDを確認します。この章のコマンドに出てくるYOUR_PROJECT_IDは、そのIDに置き換えてください。プロジェクトの表示名とは区別します。

カウンターの実習で設定した.firebasercには、CLIが使うプロジェクト情報があります。一方、firebase_options.dartはアプリの接続先を決めます。公開先とデータの接続先は別々の設定なので、この実習では両方を同じ学習用プロジェクトにそろえます。

エミュレーター接続を公開用に切り替える

カウンターの実習のmain()には、エミュレーターへ接続する2行がありました。そのまま公開すると、閲覧者のPCのlocalhostへ接続しようとしてしまいます。

その2行を、次のブロックに置き換えます。場所はFirebase.initializeApp()の直後、認証やデータベースを使う前です。

const useEmulators = bool.fromEnvironment(
  'USE_FIREBASE_EMULATOR',
  defaultValue: false,
);

if (useEmulators) {
  await FirebaseAuth.instance.useAuthEmulator('localhost', 9099);
  FirebaseDatabase.instance.useDatabaseEmulator('localhost', 9000);
}

これ以降、Chromeでローカルのエミュレーターを使うときは、明示的に指定します。

flutter run -d chrome --web-port=7357 --dart-define=USE_FIREBASE_EMULATOR=true

指定しない場合はクラウドへ接続します。この切り替えは上のコードで実装している動作であり、Flutterが自動で行うものではありません。

クラウド側の認証とルールを準備する

Firebaseコンソールで、学習用プロジェクトのAuthenticationの匿名認証が有効になっていることと、Realtime Databaseが作成されていることを確認します。

カウンターの実習のdatabase.rules.jsonには、counters/{uid}を本人だけが読み書きできるルールがあります。その内容と、firebase.jsonのdatabase.rulesがこのファイルを指していることを確認し、クラウドへ反映します。

firebase deploy --only database --project YOUR_PROJECT_ID

この操作は対象プロジェクトのデータベースルールを更新します。既存の共同開発プロジェクトのルールを学習用カウンターのルールで上書きせず、自分の学習用プロジェクトを指定してください。

エミュレーターのアカウントや保存値はクラウドへ移りません。公開URLでは新たな匿名ユーザーになり、最初はカウンターが0でも正常です。

2. Hostingを設定する(初回のみ)

pubspec.yamlがあるhello_appのルートで実行します。

firebase init hosting --project YOUR_PROJECT_ID

質問には次のように答えます。CLIのバージョンによって文言や順序が変わることがあります。

質問 回答
使用するプロジェクト カウンターの実習と同じ学習用プロジェクト
公開ディレクトリ(public directory) build/web
シングルページアプリとして設定するか Yes
GitHubで自動ビルド・デプロイを設定するか No(今回は手動で公開)
既存のindex.htmlを上書きするか No

Flutterではflutter build webがbuild/web/index.htmlを生成します。Hostingの初期化でひな形が作られた場合も、後のFlutterビルドで生成し直します。Firebase Hostingの初期設定ガイド

firebase.jsonのhosting部分が、次の内容になっていることを確認します。

{
  "hosting": {
    "public": "build/web",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

この例はHosting部分だけを示しています。カウンターの実習のdatabaseやemulatorsがある場合は残し、hostingを同じ階層に追加します。ファイル全体をこの例で置き換えないでください。

publicは公開するフォルダです。rewritesは、ファイルが見つからないURLでもFlutterの入口であるindex.htmlを返す設定です。アプリ内の画面へ直接アクセスする場合に使います。アプリ内のルーティング自体はFlutter側で実装します。

3. 公開用ファイルをビルドする

flutter pub get
flutter build web --release --dart-define=USE_FIREBASE_EMULATOR=false

完了したら、build/web/index.htmlなどが作られていることを確認します。libやソース全体を公開するのではなく、このビルド結果を配信します。Flutter公式のWeb公開ガイド

公開前にブラウザーで確認する

firebase emulators:start --only hosting --project YOUR_PROJECT_ID

ターミナルに表示されたHostingのローカルURLを開きます。既定のポートは5000ですが、表示されたURLを使ってください。

この確認はHostingの配信だけをローカルで再現します。今回のビルドではエミュレーター接続を無効にしたため、認証とカウンターの保存先はクラウドの学習用プロジェクトです。

画面が開き、「1増やす」と「リセット」が動くことを確認します。確認が終わったらCtrl+Cで停止できます。

4. Firebase Hostingへデプロイする

ビルドした内容を、指定したプロジェクトの公開サイトへ送ります。

firebase deploy --only hosting --project YOUR_PROJECT_ID

完了すると、ターミナルにHosting URLが表示されます。そのURLをブラウザーで開きましょう。この章は、学習用プロジェクトのデフォルトのHostingサイト一つを使う前提です。

コマンド 更新するもの
flutter build web PC上の公開用ファイル
firebase deploy --only hosting Hostingで配信するファイルと設定
firebase deploy --only database Realtime Databaseのルール

firebase deployだけでは設定済みの他サービスも対象になります。何を更新するかを--onlyで指定する習慣をつけましょう。Firebase CLIの部分デプロイ

5. 公開したアプリを確認する

  1. ターミナルに表示された公開URLでカウンター画面を開く。
  2. 「1増やす」を押して、値が変わることを確認する。
  3. FirebaseコンソールのAuthenticationとDatabaseで、ユーザーとcounters/{uid}の値を見る。
  4. 同じブラウザー・同じ公開URLで再読み込みし、回数が残ることを確認する。
  5. スマートフォンなど別の端末でURLを開き、画面表示と操作を確認する。

匿名認証なので、別の端末や別のドメインでは別ユーザーになり、カウンターも別になります。ローカル確認用URLと公開URLで値が違っていても、それだけで保存失敗とは限りません。

Hostingへのアップロードが成功したことと、認証・保存まで動くことは別です。必ず公開URLでも操作してみましょう。

修正したアプリを更新する

たとえば画面のタイトルを変えたら、もう一度ビルドしてからデプロイします。

flutter build web --release --dart-define=USE_FIREBASE_EMULATOR=false
firebase deploy --only hosting --project YOUR_PROJECT_ID

Dartのコードを直すだけではbuild/webは更新されません。再ビルドを忘れると、古いファイルを再度公開することになります。Hostingの初期設定をやり直す必要はありません。

公開サイトを更新する前に共有して確認する

必要ならプレビューチャネルにアップロードし、一時的なURLで確認できます。先に上記と同じビルドを済ませます。

firebase hosting:channel:deploy lesson-check --expires 1d --project YOUR_PROJECT_ID

この操作では通常の公開サイトを置き換えず、期限付きの確認用URLが発行されます。ただし、アプリの接続先はビルドに含まれる設定のままなので、確認用URLでも同じクラウドのDatabaseにアクセスします。データベースまで複製・分離されるわけではありません。プレビューと公開の公式ガイド

うまく動かないとき

症状 確認すること
Firebaseの初期ページが表示される hosting.publicがbuild/webか、初期設定後にFlutterをビルドしたか
build/webが見つからない プロジェクトのルートでビルドし、成功したか
ローカルでは動くが公開先で起動に失敗する useAuthEmulator・useDatabaseEmulatorが公開ビルドで実行されていないか
permission-deniedで保存できない 正しいプロジェクトにルールを反映したか、uidと保存先が一致しているか
匿名ログインができない 接続先のAuthenticationで匿名認証を有効にしたか
別のプロジェクトのデータが変わる firebase_options.dartの接続先とCLIの--projectを照合する
デプロイ権限のエラー firebase loginのアカウントと対象プロジェクトの権限を確認する
変更が反映されない 再ビルドしたか、正しい公開URLかを確認し、ブラウザーを再読み込みする

古い表示が残るときは、シークレットウィンドウでも確認するとキャッシュの切り分けになります。ただし、匿名ユーザーは変わるので、カウンターの値ではなく変更した見出しなどで確認してください。

やってみよう

  1. カウンターを公開し、スマートフォンで公開URLを開く。
  2. 画面のタイトルを変更し、再ビルド・再デプロイで反映する。
  3. 「アプリの公開」「データの保存」「データベースのルール更新」を、それぞれどのサービスやコマンドが担当するか説明する。

Firebase Hostingへの公開は、公開用の接続設定を確認し、ビルドし、その結果をデプロイする流れです。公開後はURLが開くだけでなく、ログインと保存まで確認しましょう。