AngularFire ウェブ Codelab

1. 概要

この Codelab では、AngularFire を使用して、Firebase のプロダクトとサービスを使用してチャット クライアントを実装およびデプロイし、ウェブ アプリケーションを作成する方法を学習します。

ユーザーが Firebase について話し合うチャットアプリ

学習内容

  • Angular と Firebase を使用してウェブアプリを作成します。
  • Cloud Firestore と Cloud Storage for Firebase を使用してデータを同期する。
  • Firebase Authentication を使用してユーザーを認証します。
  • Firebase App Hosting にウェブアプリをデプロイします。
  • Firebase Cloud Messaging を使用して通知を送信する。
  • ウェブアプリのパフォーマンス データを収集します。

必要なもの

  • GitHub アカウント
  • Firebase プロジェクトを Blaze 料金プランにアップグレード可能
  • 任意の IDE/テキスト エディタ(WebStormSublimeVS Code など)
  • パッケージ マネージャー npm(通常 Node.js に付属)
  • ターミナル/コンソール
  • 任意のブラウザ(Chrome など)
  • Codelab のサンプルコード(コードを取得する方法については、Codelab の次のステップをご覧ください)

2. サンプルコードを取得する

GitHub リポジトリを作成する

Codelab のソースは https://github.com/firebase/codelab-friendchat-web にあります。リポジトリには、複数のプラットフォーム用のサンプル プロジェクトが含まれています。ただし、この Codelab では angularfire-start ディレクトリのみを使用します。

angularfire-start フォルダを独自のリポジトリにコピーします。

  1. ターミナルを使用して、パソコン上に新しいフォルダを作成し、新しいディレクトリに移動します。
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. giget npm パッケージを使用して、angularfire-start フォルダのみを取得します。
    npx giget@latest gh:firebase/codelab-friendlychat-web/angularfire-start#master . --install
    
  3. git を使用してローカルで変更を追跡する
    git init
    
    git add .
    
    git commit -m "codelab starting point"
    
    git branch -M main
    
  4. 新しい GitHub リポジトリを作成します: https://github.com/new任意の名前を付けます。
    1. GitHub から、https://github.com/[user-name]/[repository-name].git または git@github.com:[user-name]/[repository-name].git のような新しいリポジトリ URL が提供されます。この URL をコピーします。
  5. ローカルでの変更を新しい GitHub リポジトリに push します。次のコマンドを実行します。your-repository-url プレースホルダは、実際のリポジトリ URL に置き換えます。
    git remote add origin your-repository-url
    
    git push -u origin main
    
  6. GitHub リポジトリにスターター コードが表示されます。

3. Firebase プロジェクトを作成して設定する

Firebase プロジェクトを作成する

  1. Firebase コンソールにログインします。
  2. Firebase コンソールで [プロジェクトを追加] をクリックし、Firebase プロジェクトに「friendChat」という名前を付けます。Firebase プロジェクトのプロジェクト ID を覚えておいてください。
  3. [このプロジェクトの Google アナリティクスを有効にする] チェックボックスをオフにします。
  4. [プロジェクトを作成] をクリックします。

これから作成するアプリケーションでは、ウェブアプリで利用可能な Firebase プロダクトを使用します。

  • ユーザーがアプリに簡単にログインできるようにする Firebase Authentication
  • 構造化されたデータをクラウドに保存し、データが変更されたときに即座に通知を受け取る Cloud Firestore
  • ファイルをクラウドに保存する Cloud Storage for Firebase
  • Firebase App Hosting: アプリを構築、ホスト、提供します。
  • プッシュ通知を送信し、ブラウザのポップアップ通知を表示する Firebase Cloud Messaging
  • Firebase Performance Monitoring: アプリのユーザー パフォーマンス データを収集します。

これらのプロダクトの一部は、特別な構成を必要とするか、Firebase コンソールを使用して有効にする必要があります。

Firebase 料金プランをアップグレードする

App Hosting を使用するには、Firebase プロジェクトが Blaze お支払いプラン、つまり Cloud 請求先アカウントに関連付けられている必要があります。

  • Cloud 請求先アカウントには、クレジット カードなどのお支払い方法が必要です。
  • Firebase と Google Cloud を初めて使用する場合は、$300 分のクレジットと無料トライアル用の Cloud 請求先アカウントの利用条件をご確認ください。

プロジェクトを Blaze プランにアップグレードする手順は次のとおりです。

  1. Firebase コンソールで、プランのアップグレードを選択します。
  2. ダイアログで Blaze プランを選択し、画面上の手順に沿ってプロジェクトを Cloud 請求先アカウントに関連付けます。
    Cloud 請求先アカウントを作成する必要がある場合は、Firebase コンソールのアップグレード フローに戻ってアップグレードを完了する必要があります。

Firebase ウェブアプリをプロジェクトに追加する

  1. ウェブアイコン 58d6543a156e56f9.png をクリックして、新しい Firebase ウェブアプリを作成します。
  2. フレンドリー チャットというニックネームでアプリを登録します。[このアプリの Firebase Hosting も設定します] のチェックボックスはオンにせず、[アプリを登録] をクリックします。
  3. 次のステップで構成オブジェクトが表示されます。今のところは必要ありません。[コンソールに進む] をクリックします。

ウェブアプリの登録のスクリーンショット

Authentication を設定する

ユーザーが Google アカウントでウェブアプリにログインできるようにするには、Google のログイン方法を使用します。

  1. Firebase コンソールで [認証] に移動します。
  2. [Get started] をクリックします。
  3. [その他のプロバイダ] 列で、[Google] > [有効にする] をクリックします。
  4. [プロジェクトの一般公開名] テキスト ボックスに、覚えやすい名前(My Next.js app など)を入力します。
  5. [プロジェクトのサポートメール] プルダウンから、メールアドレスを選択します。
  6. [保存] をクリックします。

Cloud Firestore を有効にする

このウェブアプリは、Cloud Firestore を使用して、チャット メッセージの保存と新しいチャット メッセージの受信を行います。

Cloud Firestore を有効にする必要があります。

  1. Firebase コンソールで Firestore に移動します。
  2. [データベースを作成] > [次へ] > [テストモードで開始] > [次へ] をクリックします。
    この Codelab の後半では、データを保護するためのセキュリティ ルールを追加します。データベースのセキュリティ ルールを追加せずに、アプリを配布または公開しないでください。
  3. デフォルトのロケーションを使用するか、任意のロケーションを選択します。
    実際のアプリでは、ユーザーに近いロケーションを選択します。このロケーションは後で変更することはできません。また、自動的にデフォルトの Cloud Storage バケットのロケーションにもなります(次のステップ)。
  4. [完了] をクリックします。

Cloud Storage を有効にする

このウェブアプリは、Cloud Storage for Firebase を使用して画像を保存、アップロード、共有します。

Cloud Storage を有効にする必要があります。

  1. Firebase コンソールで [ストレージ] に移動します。
  2. [使ってみる] > [テストモードで開始] > [次へ] をクリックします。
    この Codelab の後半では、データを保護するためのセキュリティ ルールを追加します。Storage バケットのセキュリティ ルールを追加せずに、アプリを配布または公開しないでください。
  3. バケットのロケーションはすでに選択されています(前のステップで Firestore を設定したため)。
  4. [完了] をクリックします。

4. Firebase コマンドライン インターフェースをインストールする

Firebase コマンドライン インターフェース(CLI)では、Firebase Hosting を使用してウェブアプリをローカルで提供したり、Firebase プロジェクトにウェブアプリをデプロイしたりできます。

  1. 次の npm コマンドを実行して CLI をインストールします。
npm -g install firebase-tools@latest
  1. 次のコマンドを実行して、CLI が正しくインストールされていることを確認します。
firebase --version

Firebase CLI のバージョンが vv13.9.0 以降であることを確認します。

  1. 次のコマンドを実行して、Firebase CLI を承認します。
firebase login

これで、アプリのローカル ディレクトリ(Codelab で前にクローンを作成したリポジトリ)から Firebase Hosting のアプリ構成を pull するようにウェブアプリ テンプレートを設定できました。ただし、構成を取得するには、アプリを Firebase プロジェクトに関連付ける必要があります。

  1. コマンドラインがアプリのローカル angularfire-start ディレクトリにアクセスしていることを確認します。
  2. 次のコマンドを実行して、アプリを Firebase プロジェクトに関連付けます。
firebase use --add
  1. プロンプトが表示されたら、プロジェクト ID を選択し、Firebase プロジェクトにエイリアスを指定します。

エイリアスは、複数の環境(本番環境、ステージング環境など)がある場合に役立ちます。ただし、この Codelab では default のエイリアスを使用します。

  1. コマンドラインの残りの手順に沿って操作します。

5. AngularFire をインストールする

プロジェクトを実行する前に、Angular CLI と AngularFire が設定されていることを確認します。

  1. コンソールで、次のコマンドを実行します。
npm install -g @angular/cli
  1. 次に、コンソールの angularfire-start ディレクトリで、次の Angular CLI コマンドを実行します。
ng add @angular/fire

これにより、プロジェクトに必要な依存関係がすべてインストールされます。

  1. プロンプトが表示されたら、Space キーで [ng deploy -- hosting] チェックボックスをオフにします。矢印キーと Space キーを使用して、次の機能を選択します。
    • Authentication
    • Firestore
    • Cloud Messaging
    • Cloud Storage
  2. enter を押して、残りのメッセージに沿って操作します。
  3. 「Install AngularFire」という commit メッセージ付きの commit を作成し、GitHub リポジトリに push します。

6. App Hosting バックエンドを作成する

このセクションでは、App Hosting バックエンドを設定して、Git リポジトリのブランチを監視します。

このセクションを終えると、App Hosting バックエンドが GitHub のリポジトリに接続され、main ブランチに新しい commit を push するたびに、アプリの新しいバージョンが自動的に再ビルドされてロールアウトされます。

  1. Firebase コンソールの [App Hosting] ページに移動します。

[使ってみる] ボタンが表示されている App Hosting コンソールのゼロ状態

  1. [開始] をクリックしてバックエンド作成フローを開始します。バックエンドを次のように構成します。
  2. 最初のステップのプロンプトに従い、先ほど作成した GitHub リポジトリを接続します。
  3. デプロイを設定します。
    1. ルート ディレクトリを / のままにしておきます。
    2. ライブブランチを main に設定します。
    3. 自動ロールアウトを有効にする
  4. バックエンドに friendlychat-codelab という名前を付けます。
  5. [Firebase ウェブアプリを作成または関連付ける] で、[既存の Firebase ウェブアプリを選択] プルダウンから、先ほど構成したウェブアプリを選択します。
  6. [完了してデプロイ] をクリックします。しばらくすると新しいページが表示され、新しい App Hosting バックエンドのステータスを確認できます。
  7. 公開が完了したら、[ドメイン] で無料のドメインをクリックします。DNS の伝播のため、処理が開始されるまでに数分かかることがあります。

これで、最初のウェブアプリがデプロイされました。GitHub リポジトリの main ブランチに新しい commit を push するたびに、Firebase コンソールで新しいビルドとロールアウトが開始され、ロールアウトが完了するとサイトが自動的に更新されます。

[使ってみる] ボタンが表示されている App Hosting コンソールのゼロ状態

フレンドリー チャット アプリのログイン画面が表示されますが、これはまだ機能していません。

現時点では何もできませんが、ユーザーの助けを借りれば、すぐに使えるようになります。

それでは、リアルタイム チャットアプリを作成してみましょう。

7. Firebase をインポートして構成する

Firebase を構成する

使用している Firebase プロジェクトを示すように Firebase SDK を構成する必要があります。

  1. Firebase コンソールのプロジェクト設定に移動します。
  2. [アプリ] カードで、構成オブジェクトが必要なアプリのニックネームを選択します。
  3. [Firebase SDK スニペット] ペインで [構成] を選択します。

環境ファイル /angularfire-start/src/environments/environment.ts が生成されています。

  1. 構成オブジェクト スニペットをコピーして、angularfire-start/src/firebase-config.js に追加します。

environment.ts

export const environment = {
  firebase: {
    apiKey: "API_KEY",
    authDomain: "PROJECT_ID.firebaseapp.com",
    projectId: "PROJECT_ID",
    storageBucket: "PROJECT_ID.appspot.com",
    messagingSenderId: "SENDER_ID",
    appId: "APP_ID",
  },
};

AngularFire の設定を表示する

コンソールで選択した機能が /angularfire-start/src/app/app.config.ts ファイルに自動的に追加されていることがわかります。これにより、アプリで Firebase の機能を使用できるようになります。

8. ユーザー ログインを設定する

これで、AngularFire は app.config.ts にインポートされ、初期化されたため、使用できるようになりました。次に、Firebase Authentication を使用してユーザーのログインを実装します。

承認済みドメインを追加します

Firebase Authentication は、自身が管理する一連のドメインからのログインのみを許可します。無料の App Hosting ドメインをドメインのリストに追加します。

  1. [App Hosting] に移動します。
  2. バックエンドのドメインを指定します。
  3. [認証設定] に移動します。
  4. [承認済みドメイン] タブを選択します。
  5. [ドメインを追加] をクリックし、App Hosting バックエンドのドメインを貼り付けます。

Google ログインでユーザーを認証する

アプリでユーザーが [Sign in with Google] ボタンをクリックすると、login 関数がトリガーされます。この Codelab では、Firebase が Google を ID プロバイダとして使用することを承認します。ここではポップアップを使用しますが、Firebase では他にもいくつかの方法を使用できます。

  1. サブディレクトリ /src/app/services/ で、chat.service.ts を開きます。
  2. 関数 login を見つけます。
  3. 関数全体を次のコードに置き換えます。

chat.service.ts

// Signs-in Friendly Chat.
login() {
    signInWithPopup(this.auth, this.provider).then((result) => {
        const credential = GoogleAuthProvider.credentialFromResult(result);
        this.router.navigate(['/', 'chat']);
        return credential;
    })
}

logout 関数は、ユーザーが [ログアウト] ボタンをクリックするとトリガーされます。

  1. src/app/services/chat.service.ts ファイルに戻ります。
  2. 関数 logout を見つけます。
  3. 関数全体を次のコードに置き換えます。

chat.service.ts

// Logout of Friendly Chat.
logout() {
    signOut(this.auth).then(() => {
        this.router.navigate(['/', 'login'])
        console.log('signed out');
    }).catch((error) => {
        console.log('sign out error: ' + error);
    })
}

認証状態を追跡する

それに応じて UI を更新するには、ユーザーがログインしているかログアウトしているかを確認する方法が必要です。AngularFire には、認証状態が変わるたびに更新されるオブザーバブルを取得する関数が用意されています。これはすでに実装されていますが、一読する価値があります。

  1. src/app/services/chat.service.ts ファイルに戻ります。
  2. 変数の割り当て user$ を見つけます。

chat.service.ts

// observable that is updated when the auth state changes
user$ = user(this.auth);

上記のコードは、監視可能なユーザーを返す AngularFire 関数 user を呼び出します。認証状態が変わるたびに(ユーザーがログインまたはログアウトしたとき)トリガーされます。フレンドリーチャットの Angular テンプレート コンポーネントは、このオブザーバブルを使用して、リダイレクトやヘッダー ナビゲーションへのユーザー表示などを行う UI を更新します。

アプリへのログインをテストする

  1. 「Google 認証の追加」という commit メッセージを含む commit を作成し、GitHub リポジトリに push します。
  2. Firebase コンソールで [App Hosting] ページを開き、新しいロールアウトが完了するまで待ちます。
  3. ウェブアプリでページを更新し、ログインボタンと Google アカウントを使用してアプリにログインします。「auth/operation-not-allowed」というエラー メッセージが表示された場合は、Firebase コンソールで、認証プロバイダとして Google ログインが有効になっていることを確認します。
  4. ログインすると、プロフィール写真とユーザー名が表示されます: angularfire-3.png

9. Cloud Firestore にメッセージを書き込む

このセクションでは、アプリの UI にデータを入力できるように、データを Cloud Firestore に書き込みます。これは Firebase コンソールを使用して手動で行うことができますが、基本的な Cloud Firestore の書き込みのデモを行うためにアプリ自体で行います。

データモデル

Cloud Firestore のデータは、コレクション、ドキュメント、フィールド、サブコレクションに分割されます。チャットの各メッセージを、messages という最上位のコレクションにドキュメントとして保存します。

688d7bc5fb662b57.png

Cloud Firestore にメッセージを追加する

ユーザーが書き込んだチャット メッセージを保存するには、Cloud Firestore を使用します。

このセクションでは、ユーザーがデータベースに新しいメッセージを書き込む機能を追加します。ユーザーが [送信] ボタンをクリックすると、以下のコード スニペットがトリガーされます。メッセージ フィールドの内容を含むメッセージ オブジェクトを、messages コレクションの Cloud Firestore インスタンスに追加します。add() メソッドは、自動生成された ID を持つ新しいドキュメントをコレクションに追加します。

  1. src/app/services/chat.service.ts ファイルに戻ります。
  2. 関数 addMessage を見つけます。
  3. 関数全体を次のコードに置き換えます。

chat.service.ts

// Adds a text or image message to Cloud Firestore.
addMessage = async (
  textMessage: string | null,
  imageUrl: string | null,
): Promise<void | DocumentReference<DocumentData>> => {
  // ignore empty messages
  if (!textMessage && !imageUrl) {
    console.log(
      "addMessage was called without a message",
      textMessage,
      imageUrl,
    );
    return;
  }

  if (this.currentUser === null) {
    console.log("addMessage requires a signed-in user");
    return;
  }

  const message: ChatMessage = {
    name: this.currentUser.displayName,
    profilePicUrl: this.currentUser.photoURL,
    timestamp: serverTimestamp(),
    uid: this.currentUser?.uid,
  };

  textMessage && (message.text = textMessage);
  imageUrl && (message.imageUrl = imageUrl);

  try {
    const newMessageRef = await addDoc(
      collection(this.firestore, "messages"),
      message,
    );
    return newMessageRef;
  } catch (error) {
    console.error("Error writing new message to Firebase Database", error);
    return;
  }
};

メッセージの送信をテストする

  1. 「Post new chat to Firestore」というコミット メッセージを含む commit を作成し、GitHub リポジトリに push します。
  2. Firebase コンソールで [App Hosting] ページを開き、新しいロールアウトが完了するまで待ちます。
  3. friendChat を更新します。ログイン後、「こんにちは」などのメッセージを入力して、[送信] をクリックします。これにより、メッセージが Cloud Firestore に書き込まれます。ただし、実際のウェブアプリではまだデータを確認できません。これは、データの取得を実装する必要があるためです(Codelab の次のセクションで説明します)。
  4. Firebase コンソールで新しく追加されたメッセージを確認できます。Emulator Suite UI を開きます。[構築] セクションで [Firestore Database] をクリックします(またはこちらをクリックすると、新しく追加したメッセージが入った messages コレクションが表示されます)。

6812efe7da395692.png

10. メッセージを読む

メッセージを同期する

アプリでメッセージを読み取るには、データが変更されたときにトリガーされるオブザーバブルを追加してから、新しいメッセージを表示する UI 要素を作成する必要があります。

新たに追加されたメッセージをアプリからリッスンするコードを追加します。このコードでは、messages コレクションのスナップショットを取得します。読み込み時に長い履歴が表示されないよう、チャットの最新 12 件のメッセージのみを表示します。

  1. src/app/services/chat.service.ts ファイルに戻ります。
  2. 関数 loadMessages を見つけます。
  3. 関数全体を次のコードに置き換えます。

chat.service.ts

// Loads chat message history and listens for upcoming ones.
loadMessages = () => {
  // Create the query to load the last 12 messages and listen for new ones.
  const recentMessagesQuery = query(collection(this.firestore, 'messages'), orderBy('timestamp', 'desc'), limit(12));
  // Start listening to the query.
  return collectionData(recentMessagesQuery);
}

データベース内のメッセージをリッスンするには、collection 関数を使用して、リッスンするデータが含まれるコレクションを指定することで、コレクションに対するクエリを作成します。上記のコードでは、チャット メッセージが保存されている messages コレクション内の変更をリッスンしています。また、limit(12) を使用して直近の 12 件のメッセージのみをリッスンし、orderBy('timestamp', 'desc') を使用してメッセージを日付順に並べ替えて最新の 12 件のメッセージを取得することで、上限を適用します。

collectionData 関数は、内部でスナップショットを使用します。クエリに一致するドキュメントに変更があると、コールバック関数がトリガーされます。メールが削除、変更、追加された場合が該当します。詳細については、Cloud Firestore のドキュメントをご覧ください。

メッセージの同期をテストする

  1. 「Show new chat in the UI」というコミット メッセージを含む commit を作成し、GitHub リポジトリに push します。
  2. Firebase コンソールで [App Hosting] ページを開き、新しいロールアウトが完了するまで待ちます。
  3. friendChat を更新します。先ほどデータベースで作成したメッセージが friendChat UI に表示されます(以下を参照)。新しいメッセージを自由に書いてください。すぐに表示されます。
  4. (省略可)エミュレータ スイートの Firestore セクションで直接、手動で新しいメッセージの削除、変更、追加を試すことができます。変更内容は UI に反映されます。

お疲れさまでした。アプリで Cloud Firestore ドキュメントを読み取っています。

angularfire-2.png

11. AI 機能を追加する

Google AI を使用して、チャットアプリに便利な機能を追加します。

Google AI API キーを取得する

  1. Google AI Studio に移動し、[API キーを作成] をクリックします。
  2. この Codelab で作成した Firebase プロジェクトを選択します。このプロンプトは Google Cloud プロジェクト用ですが、すべての Firebase プロジェクトは Google Cloud プロジェクトです。
  3. [既存のプロジェクトで API キーを作成] をクリックします。
  4. 生成された API キーをコピーする

拡張機能をインストールする

この拡張機能は、新しいドキュメントが Firestore の messages コレクションに追加されるたびにトリガーされる Cloud Functions の関数をデプロイします。この関数は Gemini を呼び出し、そのレスポンスをドキュメントの response フィールドに書き戻します。

  1. [Build Chatbot with the Gemini API] 拡張機能ページで、[Firebase コンソールでインストール] をクリックします。
  2. 画面の指示に従います。[拡張機能を構成する] ステップが表示されたら、次のパラメータ値を設定します。
    • Gemini API プロバイダ: Google AI
    • Google AI API キー: 先ほど作成したキーを貼り付けて、[シークレットを作成] をクリックします。
    • Firestore の収集パス: messages
    • プロンプト フィールド: text
    • レスポンス フィールド: response
    • オーダー フィールド: timestamp
    • コンテキスト: Keep your answers short, informal, and helpful. Use emojis when possible.
  3. [拡張機能をインストール] をクリックします。
  4. 拡張機能のインストールが完了するまで待ちます

AI 機能をテストする

フレンドリーチャットには、AI 拡張機能からレスポンスを読み取るコードがすでにあります。新しいチャット メッセージを送信するだけでテストできます。

  1. フレンドリーチャットを開いて、メッセージを送信します。
  2. しばらくすると、メッセージの横に返信がポップアップ表示されます。実際のユーザーではなく生成 AI を使用して作成されたことを明示するため、最後に ✨ ai generated というメモが付いています。

12. 画像を送信する

次に、画像を共有する機能を追加します。

構造化データの保存には Cloud Firestore が、ファイルの保存には Cloud Storage のほうが適しています。Cloud Storage for Firebase はファイル/blob ストレージ サービスです。ユーザーがこのアプリを使って共有する画像を保存するために使用します。

画像を Cloud Storage に保存する

この Codelab では、ファイル選択ツール ダイアログをトリガーするボタンがすでに追加されています。ファイルを選択すると、saveImageMessage 関数が呼び出され、選択したファイルへの参照を取得できます。saveImageMessage 関数は次の処理を行います。

  1. チャット フィード内に「プレースホルダ」のチャット メッセージを作成します。これにより、画像のアップロード中にユーザーに「読み込み中」のアニメーションが表示されます。
  2. 画像ファイルを Cloud Storage のパス /<uid>/<file_name> にアップロードします。
  3. 画像ファイルの公開読み取り可能な URL を生成します。
  4. 一時的な読み込み画像の代わりに、新しくアップロードされた画像ファイルの URL でチャット メッセージを更新します。

次に、画像を送信する機能を追加します。

  1. src/chat.service.ts ファイルに戻ります。
  2. 関数 saveImageMessage を見つけます。
  3. 関数全体を次のコードに置き換えます。

chat.service.ts

// Saves a new message containing an image in Firestore.
// This first saves the image in Firebase storage.
saveImageMessage = async(file: any) => {
  try {
    // 1 - Add a message with a loading icon that will get updated with the shared image.
    const messageRef = await this.addMessage(null, this.LOADING_IMAGE_URL);

    // 2 - Upload the image to Cloud Storage.
    const filePath = `${this.auth.currentUser?.uid}/${file.name}`;
    const newImageRef = ref(this.storage, filePath);
    const fileSnapshot = await uploadBytesResumable(newImageRef, file);

    // 3 - Generate a public URL for the file.
    const publicImageUrl = await getDownloadURL(newImageRef);

    // 4 - Update the chat message placeholder with the image's URL.
    messageRef ?
    await updateDoc(messageRef, {
      imageUrl: publicImageUrl,
      storageUri: fileSnapshot.metadata.fullPath
    }): null;
  } catch (error) {
    console.error('There was an error uploading a file to Cloud Storage:', error);
  }
}

画像の送信をテストする

  1. 「Add the capability to post images」という commit メッセージを含む commit を作成し、GitHub リポジトリに push します。
  2. Firebase コンソールで [App Hosting] ページを開き、新しいロールアウトが完了するまで待ちます。
  3. friendChat を更新します。ログイン後、左下の画像アップロード ボタン angularfire-4.png をクリックし、ファイル選択ツールを使用して画像ファイルを選択します。画像をお探しの場合は、こちらのコーヒーカップの素敵な写真をお使いください。
  4. 選択した画像を含む新しいメッセージがアプリの UI に表示されます: angularfire-2.png

ログインしていない状態で画像を追加しようとすると、画像を追加するにはログインする必要があるというエラーが表示されます。

13. 通知を表示する

次に、ブラウザ通知のサポートを追加します。チャットに新しいメッセージが投稿されると、アプリからユーザーに通知が届きます。Firebase Cloud Messaging(FCM)は、メッセージや通知を無料で確実に配信するためのクロス プラットフォーム メッセージング ソリューションです。

FCM Service Worker を追加する

ウェブアプリには、ウェブ通知を受信して表示する Service Worker が必要です。

AngularFire が追加されたときに、メッセージ プロバイダがすでに設定されているはずです。/angularfire-start/src/app/app.module.ts のインポート セクションに次のコードが存在することを確認してください。

provideMessaging(() => {
    return getMessaging();
}),

app/app.module.ts

Service Worker は Firebase Cloud Messaging SDK を読み込んで初期化するだけで、通知の表示に対処できます。

FCM デバイス トークンを取得する

デバイスまたはブラウザで通知が有効になっている場合は、デバイス トークンが提供されます。このデバイス トークンは、特定のデバイスまたは特定のブラウザに通知を送信するために使用します。

ユーザーがログインしたら、saveMessagingDeviceToken 関数を呼び出します。ここで、ブラウザから FCM デバイス トークンを取得し、Cloud Firestore に保存します。

chat.service.ts

  1. 関数 saveMessagingDeviceToken を見つけます。
  2. 関数全体を次のコードに置き換えます。

chat.service.ts

// Saves the messaging device token to Cloud Firestore.
saveMessagingDeviceToken= async () => {
    try {
      const currentToken = await getToken(this.messaging);
      if (currentToken) {
        console.log('Got FCM device token:', currentToken);
        // Saving the Device Token to Cloud Firestore.
        const tokenRef = doc(this.firestore, 'fcmTokens', currentToken);
        await setDoc(tokenRef, { uid: this.auth.currentUser?.uid });
 
        // This will fire when a message is received while the app is in the foreground.
        // When the app is in the background, firebase-messaging-sw.js will receive the message instead.
        onMessage(this.messaging, (message) => {
          console.log(
            'New foreground notification from Firebase Messaging!',
            message.notification
          );
        });
      } else {
        // Need to request permissions to show notifications.
        this.requestNotificationsPermissions();
      }
    } catch(error) {
      console.error('Unable to get messaging token.', error);
    };
}

ただし、このコードは最初は動作しません。アプリでデバイス トークンを取得できるようにするには、通知を表示する権限をユーザーがアプリに付与する必要があります(Codelab の次のステップ)。

通知を表示する権限をリクエストする

ユーザーがアプリに通知を表示する権限をまだ付与していない場合、デバイス トークンは付与されません。この場合、requestPermission() メソッドを呼び出します。これにより、この権限を要求するブラウザ ダイアログが表示されます(サポートされているブラウザ)。

8b9d0c66dc36153d.png

  1. src/app/services/chat.service.ts ファイルに戻ります。
  2. 関数 requestNotificationsPermissions を見つけます。
  3. 関数全体を次のコードに置き換えます。

chat.service.ts

// Requests permissions to show notifications.
requestNotificationsPermissions = async () => {
    console.log('Requesting notifications permission...');
    const permission = await Notification.requestPermission();
    
    if (permission === 'granted') {
      console.log('Notification permission granted.');
      // Notification permission granted.
      await this.saveMessagingDeviceToken();
    } else {
      console.log('Unable to get permission to notify.');
    }
}

デバイス トークンを取得する

  1. 「Add the capability to post images」という commit メッセージを含む commit を作成し、GitHub リポジトリに push します。
  2. Firebase コンソールで [App Hosting] ページを開き、新しいロールアウトが完了するまで待ちます。
  3. friendChat を更新します。ログインすると、通知権限ダイアログ(bd3454e6dbfb6723.png)が表示されます。
  4. [Allow] をクリックします。
  5. ブラウザの JavaScript コンソールを開きます。「Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu」というメッセージが表示されます。
  6. デバイス トークンをコピーします。この Codelab の次のステージで必要になります。

デバイスに通知を送信する

デバイス トークンを取得したら、通知を送信できます。

  1. Firebase コンソールの [Cloud Messaging] タブを開きます。
  2. [新しい通知] をクリックします
  3. 通知のタイトルと通知テキストを入力します。
  4. 画面の右側にある [テスト メッセージを送信] をクリックします。
  5. ブラウザの JavaScript コンソールからコピーしたデバイス トークンを入力し、プラス(「+」)記号をクリックします。
  6. [test] をクリックします。

アプリがフォアグラウンドの場合は、JavaScript コンソールに通知が表示されます。

アプリがバックグラウンドで動作している場合は、次の例のように、ブラウザに通知が表示されます。

de79e8638a45864c.png

14. Cloud Firestore セキュリティ ルール

データベース セキュリティ ルールを表示する

Cloud Firestore は、特定のルール言語を使用して、アクセス権限、セキュリティ、データ検証を定義します。

この Codelab の冒頭で Firebase プロジェクトを設定したときに、データストアへのアクセスを制限しないように、「テストモード」のデフォルトのセキュリティ ルールを選択しました。Firebase コンソールの [データベース] セクションの [ルール] タブで、これらのルールを表示、変更できます。

この時点では、データストアへのアクセスを制限しないデフォルトのルールが表示されています。つまり、すべてのユーザーが、データストア内の任意のコレクションに対して読み書きできます。

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}

次のルールを使用して、ルールを更新し、項目を制限します。

firestore.rules

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    // Messages:
    //   - Anyone can read.
    //   - Authenticated users can add and edit messages.
    //   - Validation: Check name is same as auth token and text length below 300 char or that imageUrl is a URL.
    //   - Deletes are not allowed.
    match /messages/{messageId} {
      allow read;
      allow create, update: if request.auth != null
                    && request.resource.data.name == request.auth.token.name
                    && (request.resource.data.text is string
                      && request.resource.data.text.size() <= 300
                      || request.resource.data.imageUrl is string
                      && request.resource.data.imageUrl.matches('https?://.*'));
      allow delete: if false;
    }
    // FCM Tokens:
    //   - Anyone can write their token.
    //   - Reading list of tokens is not allowed.
    match /fcmTokens/{token} {
      allow read: if false;
      allow write;
    }
  }
}

Emulator Suite のセキュリティ ルールが自動的に更新されます。

Cloud Storage のセキュリティ ルールを表示する

Cloud Storage for Firebase では、特定のルール言語を使用して、アクセス権限、セキュリティ、データ検証を定義します。

この Codelab の冒頭で Firebase プロジェクトを設定したとき、デフォルトの Cloud Storage セキュリティ ルールを使用して、認証されたユーザーのみに Cloud Storage の使用を許可することにしました。Firebase コンソールの [Storage] セクションの [ルール] タブで、ルールを表示および変更できます。デフォルトのルールが表示されます。このルールでは、ログインしているすべてのユーザーが、ストレージ バケット内のすべてのファイルを読み書きできます。

rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

次の処理を行うようにルールを更新します。

  • 各ユーザーに自分の特定のフォルダへの書き込みのみを許可する
  • すべてのユーザーに Cloud Storage からの読み取りを許可する
  • アップロードされたファイルが画像であることを確認してください。
  • アップロードできる画像のサイズを最大 5 MB に制限する

これは、次のルールを使用して実装できます。

storage.rules

rules_version = '2';

// Returns true if the uploaded file is an image and its size is below the given number of MB.
function isImageBelowMaxSize(maxSizeMB) {
  return request.resource.size < maxSizeMB * 1024 * 1024
      && request.resource.contentType.matches('image/.*');
}

service firebase.storage {
  match /b/{bucket}/o {
    match /{userId}/{messageId}/{fileName} {
      allow write: if request.auth != null && request.auth.uid == userId && isImageBelowMaxSize(5);
      allow read;
    }
  }
}

15. お疲れさまでした

これで、Firebase を使用してリアルタイム チャットのウェブ アプリケーションを構築できました。

学習した内容

  • Firebase App Hosting
  • Firebase Authentication
  • Cloud Firestore
  • Firebase SDK for Cloud Storage
  • Firebase Cloud Messaging
  • Firebase Performance Monitoring

次のステップ

詳細

16. [省略可] App Check で適用する

Firebase App Check を使用すると、不要なトラフィックからサービスを保護し、バックエンドを不正使用から保護できます。このステップでは、App Check と reCAPTCHA Enterprise を使用して認証情報の検証を追加し、未承認のクライアントをブロックします。

まず、App Check と reCAPTCHA を有効にする必要があります。

reCAPTCHA Enterprise の有効化

  1. Cloud コンソールの [セキュリティ] で、[reCaptcha Enterprise] を見つけて選択します。
  2. プロンプトが表示されたらサービスを有効にし、[鍵を作成] をクリックします。
  3. プロンプトが表示されたら表示名を入力し、プラットフォーム タイプとして [ウェブサイト] を選択します。
  4. デプロイした URL をドメインリストに追加し、[チェックボックスによる本人確認を使用する] オプションがオフになっていることを確認します。
  5. [鍵を作成] をクリックし、生成された鍵を安全な場所に保存します。これは、この手順の後半で必要になります。

App Check を有効にする

  1. Firebase コンソールの左側のパネルで、[ビルド] セクションを見つけます。
  2. [App Check] をクリックし、[Sign-in method] タブをクリックして [App Check] に移動します。
  3. [登録] をクリックし、プロンプトが表示されたら reCaptcha Enterprise キーを入力し、[保存] をクリックします。
  4. API ビューで [Storage] を選択し、[適用] をクリックします。Cloud Firestore についても同じことを行います。

これで App Check が適用されるようになりました。アプリを更新して、チャット メッセージを表示または送信してみます。次のようなエラー メッセージが表示されます。

Uncaught Error in snapshot listener: FirebaseError: [code=permission-denied]: Missing or insufficient permissions.

つまり、App Check はデフォルトで未検証のリクエストをブロックします。それでは、アプリに検証を追加しましょう。

environment.ts ファイルに移動し、reCAPTCHAEnterpriseKeyenvironment オブジェクトに追加します。

export const environment = {
  firebase: {
    apiKey: 'API_KEY',
    authDomain: 'PROJECT_ID.firebaseapp.com',
    databaseURL: 'https://PROJECT_ID.firebaseio.com',
    projectId: 'PROJECT_ID',
    storageBucket: 'PROJECT_ID.appspot.com',
    messagingSenderId: 'SENDER_ID',
    appId: 'APP_ID',
    measurementId: 'G-MEASUREMENT_ID',
  },
  reCAPTCHAEnterpriseKey: {
    key: "Replace with your recaptcha enterprise site key"
  },
};

key の値は、reCAPTCHA Enterprise トークンに置き換えます。

次に、app.module.ts ファイルに移動し、次のインポートを追加します。

import { getApp } from '@angular/fire/app';
import {
  ReCaptchaEnterpriseProvider,
  initializeAppCheck,
  provideAppCheck,
} from '@angular/fire/app-check';

同じ app.module.ts ファイルで、次のグローバル変数宣言を追加します。

declare global {
  var FIREBASE_APPCHECK_DEBUG_TOKEN: boolean;
}

@NgModule({ ...

インポートで、ReCaptchaEnterpriseProvider を使用して App Check の初期化を追加し、isTokenAutoRefreshEnabledtrue に設定して、トークンの自動更新を許可します。

imports: [
BrowserModule,
AppRoutingModule,
CommonModule,
FormsModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAppCheck(() => {
const appCheck = initializeAppCheck(getApp(), {
  provider: new ReCaptchaEnterpriseProvider(
  environment.reCAPTCHAEnterpriseKey.key
  ),
  isTokenAutoRefreshEnabled: true,
  });
  if (location.hostname === 'localhost') {
    self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
  }
  return appCheck;
}),

ローカルテストを許可するには、self.FIREBASE_APPCHECK_DEBUG_TOKENtrue に設定します。localhost でアプリを更新すると、次のようなデバッグ トークンがコンソールに記録されます。

App Check debug token: CEFC0C76-7891-494B-B764-349BDFD00D00. You will need to add it to your app's App Check settings in the Firebase console for it to work.

次に、Firebase コンソールで App Check の [Apps] ビューに移動します。

オーバーフロー メニューをクリックして、[デバッグ トークンを管理] を選択します。

次に、[デバッグ トークンを追加] をクリックし、プロンプトが表示されたら、コンソールのデバッグ トークンを貼り付けます。

chat.service.ts ファイルに移動し、次のインポートを追加します。

import { AppCheck } from '@angular/fire/app-check';

同じ chat.service.ts ファイルで、他の Firebase サービスとともに App Check を挿入します。

export class ChatService {
appCheck: AppCheck = inject(AppCheck);
...
  1. 「App Check で未承認のクライアントをブロック」というコミット メッセージを含む commit を作成し、GitHub リポジトリに push します。
  2. Firebase コンソールで [App Hosting] ページを開き、新しいロールアウトが完了するまで待ちます。

お疲れさまでした。アプリで App Check が機能するようになりました。