はじめに
Firebase でチャットアプリを作成するチュートリアル(Firebase web codelab)を試してみました。
チュートリアルでは、以下のことが学べます。
- Cloud Firestore と Cloud Storage のデータ同期
- Firebase Authentication のユーザー認証
- Web アプリケーションのデプロイ
- Firebase Cloud Messaging の通知送信
- Web アプリケーションのパフォーマンスデータ収集
環境
・Firebase 8.2.1
・openSUSE Tumbleweed 20201229
・Virtual Machine:2vCPU, 4GB Memory, 40GB Disk
・VMware(R) Workstation 15 Pro
事前準備
root ユーザー移行
sudo su -
git インストール
zypper install git
npm インストール
zypper install npm
サンプルコードの入手
codelab のリポジトリを複製
git clone https://github.com/firebase/codelab-friendlychat-web
Firebase プロジェクト作成
Firebase にログインして、プロジェクトを作成します。

Firebase Authentication の設定
ウェブアイコン をクリックして、Firebase Web アプリを作成します。

左ペインの「Authentication」➡「Sign-in method」で「Google」をクリックして、有効化します。

Google Cloud Console で OAuth 同意画面を設定します。*1

Cloud Firestore の設定
左ペインの「Cloud FIrestore」から「データベース作成」をクリックして「テストモード」を有効化します。

Firebase CLI インストール
CLI インストール
sudo su -
npm -g install firebase-tools
インストール確認
cd /home/hatkobelab/codelab-friendlychat-web/web-start/
firebase --version
Firebase CLI 承認
firebase login
※CLI をインストールした OS 上で実行する必要があります。それ以外の場合は、localhost に接続できずエラーとなります。本例では、以下のように openSUSE で実行しました。

アプリと Firebase プロジェクトを紐づけ
firebase use --add
? Which project do you want to add? friendlychat-46e4f
? What alias do you want to use for this project? (e.g. staging) default
アプリをローカルで実行
アプリを実行
firebase serve --only hosting
※上述と同様に OS 上で実行します。
ブラウザから http://localhost:5000 に接続

アプリの UI が接続されますが、認証がとおっていないため、まだ機能しません。
ユーザーサインイン設定
チュートリアルでは、Google サインインでユーザー認証するためのコードが用意されているので、対象の関数を置き換えます。ファイルは web-start/public/scripts/main.js です。
関数:signIn
function signIn() {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider);
}
関数:signOut
function signOut() {
firebase.auth().signOut();
}
関数:initFirebaseAuth
function initFirebaseAuth() {
firebase.auth().onAuthStateChanged(authStateObserver);
}
関数:getProfilePicUrl
function getProfilePicUrl() {
return firebase.auth().currentUser.photoURL || '/images/profile_placeholder.png';
}
関数:getUserName
function getUserName() {
return firebase.auth().currentUser.displayName;
}
関数:isUserSignedIn
function isUserSignedIn() {
return !!firebase.auth().currentUser;
}
サインインのテストは、上述と同様に OS 上で実行します。
firebase serve --only hosting
以下のように Google でサインインができるようになります。

メッセージの書き込み設定
アプリケーションの UI にデータ入力ができるように Cloud Firestore にデータを書き込みます。ユーザーが作成したメッセージは、Cloud Firestore に保存されます。
チュートリアルでは、ユーザーが「Send」ボタンをクリックすると、データベースに保存するコードが用意されているので、対象の関数を置き換えます。ファイルは web-start/public/scripts/main.js です。
関数:saveMessage
function saveMessage(messageText) {
return firebase.firestore().collection('messages').add({
name: getUserName(),
text: messageText,
profilePicUrl: getProfilePicUrl(),
timestamp: firebase.firestore.FieldValue.serverTimestamp()
}).catch(function(error) {
console.error('Error writing new message to database', error);
});
}
ブラウザから http://localhost:5000 に接続し「hello」などのメッセージを入力して「Send」ボタンをクリックすると、Firebase コンソールでメッセージを確認できます。

メッセージの読み取り設定
アプリケーションでメッセージを読み取り、表示させます。
データベース内のメッセージが更新された際に、新しいメッセージをアプリケーションに表示させるように対象の関数を置き換えます。ファイルは web-start/public/scripts/main.js です。
関数:loadMessages
function loadMessages() {
var query = firebase.firestore()
.collection('messages')
.orderBy('timestamp', 'desc')
.limit(12);
query.onSnapshot(function(snapshot) {
snapshot.docChanges().forEach(function(change) {
if (change.type === 'removed') {
deleteMessage(change.doc.id);
} else {
var message = change.doc.data();
displayMessage(change.doc.id, message.timestamp, message.name,
message.text, message.profilePicUrl, message.imageUrl);
}
});
});
}
画像送信設定
画像を共有する機能を追加します。
Cloud Firestore は、構造化データの保存に適していますが、Cloud Storage はファイルの保存に適しています。
ユーザーがアプリケーションを使用して共有する画像を Cloud Storage に保存するように対象の関数を置き換えます。ファイルは web-start/public/scripts/main.js です。
関数:saveImageMessage
function saveImageMessage(file) {
firebase.firestore().collection('messages').add({
name: getUserName(),
imageUrl: LOADING_IMAGE_URL,
profilePicUrl: getProfilePicUrl(),
timestamp: firebase.firestore.FieldValue.serverTimestamp()
}).then(function(messageRef) {
var filePath = firebase.auth().currentUser.uid + '/' + messageRef.id + '/' + file.name;
return firebase.storage().ref(filePath).put(file).then(function(fileSnapshot) {
return fileSnapshot.ref.getDownloadURL().then((url) => {
return messageRef.update({
imageUrl: url,
storageUri: fileSnapshot.metadata.fullPath
});
});
});
}).catch(function(error) {
console.error('There was an error uploading a file to Cloud Storage:', error);
});
}
ブラウザから http://localhost:5000 に接続し「hello」などのメッセージを入力して「Send」ボタンをクリックすると、アプリケーションに表示されます。また、画像をアプリケーションにアップロードすることもできます。

パフォーマンスデータ収集
Performance Monitoring SDK を使用して、アプリケーションからパフォーマンスデータを収集し、Firebase コンソールでデータの確認および分析ができます。
自動トレースの設定
アプリケーション利用時に自動的にパフォーマンスデータ監視を行うためには、main.js に以下を追加します。
TODO
firebase.performance();
パフォーマンスデータの表示
Firebase コンソールからパフォーマンスデータを確認できます。通常は、この後の手順で実施するデプロイ後、12時間以内に表示されます。

アプリケーションのデプロイ
Firebase Hosting を使用してアプリケーションを Firebase プロジェクトにデプロイします。
コマンドは以下を使用します。
> cd /home/hatkobelab/codelab-friendlychat-web/web-start/
> firebase deploy --except functions
デプロイ後、Firebase Hosting の URL(以下の2つの Firebase 独自サブドメイン)から、ウェブアプリケーションにアクセスできるようになります。
https://<firebase-projectId>.firebaseapp.com
https://<firebase-projectId>.web.app

通知設定
Firebase Cloud Messaging を使用して、ウェブアプリに通知を配信することができます。
送信者 ID 許可
アプリケーション側で、通知を許可する送信 ID を設定する必要があります。 web-start/public/manifest.json の gcm_sender_id で設定します。※固定値で変更できません。
{
"name": "Friendly Chat",
"short_name": "Friendly Chat",
"start_url": "/index.html",
"display": "standalone",
"orientation": "portrait",
"gcm_sender_id": "103953800507"
}
Service Worker の追加
通知をアプリケーションに表示させるために必要な Service Worker を追加します。 web-start/public ディレクトリに irebase-messaging-sw.js という名前のファイルを作成して、以下のコンテンツを追加します。*2
importScripts('/__/firebase/8.2.1/firebase-app.js');
importScripts('/__/firebase/8.2.1/firebase-messaging.js');
importScripts('/__/firebase/init.js');
firebase.messaging();
デバイストークンの取得
デバイスまたはブラウザで通知が有効になると、デバイストークンが提供されます。
ユーザーがサインインすると、ブラウザからデバイストークンを取得し、Cloud Firestore に保存するように設定します。ファイルは web-start/public/scripts/main.js です。
function saveMessagingDeviceToken() {
firebase.messaging().getToken().then(function(currentToken) {
if (currentToken) {
console.log('Got FCM device token:', currentToken);
firebase.firestore().collection('fcmTokens').doc(currentToken)
.set({uid: firebase.auth().currentUser.uid});
} else {
requestNotificationsPermissions();
}
}).catch(function(error){
console.error('Unable to get messaging token.', error);
});
}
通知権限のリクエスト
ユーザーに通知許可を求めるダイアログをブラウザに表示させます。ユーザーで許可していない場合、デバイストークンは提供されません。
function requestNotificationsPermissions() {
console.log('Requesting notifications permission...');
firebase.messaging().requestPermission().then(function() {
saveMessagingDeviceToken();
}).catch(function(error) {
console.error('Unable to get permission to notify.', error);
});
}
サインイン後、通知許可ダイアログが表示されます。

「許可」をクリックすると、ブラウザの JavaScript コンソールに次のメッセージが表示されます。
Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
ブラウザに通知を送信
デバイストークンと、サーバーキーを設定し、次の cURL コマンドを実行します。
サーバーキーは、Firebase コンソール から「プロジェクトの概要」➡「プロジェクトを設定」➡「Cloud Messaging」 で確認できます。
curl -H "Content-Type: application/json" \
-H "Authorization: key=YOUR_SERVER_KEY" \
-d '{
"notification": {
"title": "New chat message!",
"body": "There is a new message in FriendlyChat",
"icon": "/images/profile_placeholder.png",
"click_action": "http://localhost:5000"
},
"to": "YOUR_DEVICE_TOKEN"
}' \
https://fcm.googleapis.com/fcm/send
アプリケーションがバックグラウンドにある場合、次のようにブラウザに通知が表示されます。

以上