Firebaseの公式チュートリアルをやっていく(前編)

2019年7月24日

チャットアプリを作ってFirebaseの使い方を学ぶというやつ
Firebase Web Codelabなので、Webとの連携となる。
長くなってきたので、前編と後編で分けることにした。
これは前編。
自分用のメモとして記録している。
チュートリアル通りにできないところもある。

以下が公式のチュートリアル。
このチュートリアルをまったりやっていく。

https://codelabs.developers.google.com/codelabs/firebase-web/?authuser=0#1

前提

チュートリアルは以下の環境で進めた
・OS
Windows 10 Home
・ブラウザ
Google Chrome
・IDE
JetBrains Rider 2019.1.2

チュートリアルで使用するソースを取得する


作業用のフォルダを作ってgit cloneを実行する。

cd C:\root\work\firebase
git clone https://github.com/firebase/friendlychat-web

git cloneすると、friendlychat-webができる。
その中の二つのフォルダが今回のチュートリアルで使用するフォルダとなる。
・web-start:チュートリアルと共に進めていく
・web:完成後のアプリ

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

1.Firebaseにサインインする。
2.プロジェクトを追加をクリック
3.プロジェクト名にFriendlyChatと入力する
すると、プロジェクトIDが以下のように自動的に生成される。
プロジェクト名とプロジェクトIDが異なるのは、プロジェクト名が一意に識別できないため。
仮に一意に識別できる場合は、プロジェクト名=プロジェクトIDとなる。

プロジェクト名≠プロジェクトID
プロジェクト名を変更して
プロジェクト名=プロジェクトID とした。

プロジェクト作成が完了

プロジェクトの設定をする。

1.今回はWebのプロジェクト</>マークをクリックする。

2.アプリの登録をする。
アプリのニックネームに Friendly Chat と入力する。
このアプリのFirebase Hostingも設定します。のチェックボックスにチェックを入れる。
アプリを登録ボタンを押す。

以下のような画面が出るが、次へをクリックする。

Firebase CLIのインストールをしてね、という画面。
後々インストールするのでここではスルーして次へ。

Firebase Hostingへのデプロイの説明がしてある。
これも後々やっていく。

GoogleアカウントでFirebase認証を有効にする

1.左側のAuthenticationをクリックする。

ログイン方法をクリックする

Googleプロバイダが無効になっているので、ここを有効にする。

赤枠の部分を変更する。
プロジェクトの公開名はFriendly Chatとし、
プロジェクトのサポートメールは自身のメールアドレスをドロップダウンから選択する。入力が終わったら保存ボタンを押す。

Cloud Firestoreを有効にする

チュートリアルではFirestoreを使用する。
チャットメッセージを保存するため。

左側のDatabaseをクリック

データベースの作成をクリック

※今回のチュートリアルではRealtime Databaseは使わないので、間違えないように。

こちらでデータベースを作成しないように

テストモードで開始を選択。

Cloud Firestoreのロケーションを設定する。
これは公式に別段記述がなかったけど、非常に重要なステップ。
なぜかというと、ここで選択したロケーションは今後変更することができないからだ。

日本でアプリを公開することを前提とする場合、
asia-northeast1を選択するのが良さそう。
理由は以下のqitaページで詳しく書いてある。

https://qiita.com/qrusadorz/items/99432fac6cbc93ebaff2

Cloud Storageを有効化

左側にあるStorageをクリック

スタートガイドをクリック

今の設定だとセキュリティー的にゆるゆるだけど、後々必要に応じてセキュアな設定にする。とりえず、次へ。

特に設定する項目はないので、完了ボタンを押す。

FirebaseのCLIをインストールする。

//グローバル空間にfirebaseCLIをインストールする。
//適宜自分の環境に合わせて実行するのもOKだと思います。
//ここでは、チュートリアルに沿ってやるため、グローバルにインストール。
npm -g install firebase-tools

//7.1.0とでた。バージョンはインストールするタイミングによって変わる。
firebase --version

//CLIからfirebaseへログインする。
firebase login

//匿名でCLIの使用状況レポートされてよい?という質問
//ここは状況に応じてY/N選んで
Allow Firebase to collect anonymous CLI usage and error reporting information?

Firebase CLIの許可

コマンドライン側でも認証が成功したと表示される
//最初にgit cloneしたフォルダへ移動する
cd C:\root\work\firebase\friendlychat-web\web-start

//以下のコマンドを実行。何をしてるか気になる場合は
//firebase use -helpして確認するか、ググってください。
firebase use --add

//どのプロジェクトを追加したいか聞かれるので今回のチュートリアル用のプロジェクトを選択する。
? Which project do you want to add?
> takumi-friendlychat

//aliasは何にするという質問。例のごとく、friendlychatとしておく。
? What alias do you want to use for this project? (e.g. staging)
friendlychat

ローカルで実際に動かしてみる

//web-startで実行
cd C:\root\work\firebase\friendlychat-web\web-start

firebase serve --only hosting
//web-start/publicをhttp://localhost:5000でホスティングしとるよとのこと。
i  hosting: Serving hosting files from: ./public
+  hosting: Local server: http://localhost:5000

上記の状態でこちらにアクセスする
http://localhost:5000
ローカルサーバで実行されていることを確認できる。

Firebase SDKをインポート

チュートリアルにも書いてある通り、 インポート方法はいくつかある。https://firebase.google.com/docs/web/setup
既に、web-start/public/index.htmlの一番下のほうに追加されていることが確認できる。
このチュートリアルでは、firebaseの各種機能を使うので、すべてのライブラリーをインポートしている。
実際にアプリ開発を行う場合は、必要なものだけをインポートするようにしてロード時間を短縮するようにする。

todo:この設定だけだとIDEのインテリセンスが効かないのでnpmでfirabase一式をした。やり方は別記事にする。

Firebaseへの接続設定

以下のコードがindex.htmlにあるか確認しておく。

<script src="/__/firebase/init.js"></script>

http://localhost:5000/__/firebase/init.js

Googleユーザでサインインできるようにする

既にチュートリアルで用意されている
web-start/public/scripts/main.js をチュートリアル通りに編集する。

// サインインメソッド
function signIn() {
  // Sign into Firebase using popup auth & Google as the identity provider.
  var provider = new firebase.auth.GoogleAuthProvider();
  firebase.auth().signInWithPopup(provider);
}

// サインアウトメソッド
function signOut() {
  // Sign out of Firebase.
  firebase.auth().signOut();
}

// 認証ステータスの監視
function initFirebaseAuth() {
  // Listen to auth state changes.
  firebase.auth().onAuthStateChanged(authStateObserver);
}

// サインインユーザのプロフィール画像のパスを返す
function getProfilePicUrl() {
  return firebase.auth().currentUser.photoURL || '/images/profile_placeholder.png';
}

// サインインユーザの名前を返す
function getUserName() {
  return firebase.auth().currentUser.displayName;
}

// サインインしているかを判定
function isUserSignedIn() {
  return !!firebase.auth().currentUser;
}
firebase serve --only hosting
//以下にアクセス
http://localhost:5000

赤いところをクリックして認証画面へ

Google認証できない場合

問題なく認証できている場合は、ここはスルー

OAuthの設定ができていないというエラーが出た。
Learn moreを押す

すでにアプリケーション名とサポートメールは選択済なのにエラーのまま。
以下のサイトを見る限り、、 アプリケーションのロゴも設定が必要とのこと。
適当なロゴ画像を選ぶんで設定を保存。
https://github.com/firebase/quickstart-js/issues/324

認証画面が出た。

チャットメッセージを Cloud Firestore に書き込む

FirestoreのData Modelについては以下を参照

https://firebase.google.com/docs/firestore/data-model

web-start/public/scripts/main.js を編集する。

// Saves a new message on the Cloud Firestore.
function saveMessage(messageText) {
  // Add a new message entry to the Firebase database.
  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 Firebase Database', error);
  });
}

これで再度  http://localhost:5000 に接続してメッセージ送信テストをしてみる。

Cloud Firestoreに保存されていることが確認できる。

チャットメッセージを Cloud Firestore から読みこむ

web-start/public/scripts/main.js を編集する。

// Loads chat messages history and listens for upcoming ones.
function loadMessages() {
  // Create the query to load the last 12 messages and listen for new ones.
  var query = firebase.firestore()
                  .collection('messages')
                  .orderBy('timestamp', 'desc')
                  .limit(12);
  
  // Start listening to the query.
  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);
      }
    });
  });
}

画像データを送信する

web-start/public/scripts/main.js を編集する。

// Saves a new message containing an image in Firebase.
// This first saves the image in Firebase storage.
function saveImageMessage(file) {
  // 1 - We add a message with a loading icon that will get updated with the shared image.
  firebase.firestore().collection('messages').add({
    name: getUserName(),
    imageUrl: LOADING_IMAGE_URL,
    profilePicUrl: getProfilePicUrl(),
    timestamp: firebase.firestore.FieldValue.serverTimestamp()
  }).then(function(messageRef) {
    // 2 - Upload the image to Cloud Storage.
    var filePath = firebase.auth().currentUser.uid + '/' + messageRef.id + '/' + file.name;
    return firebase.storage().ref(filePath).put(file).then(function(fileSnapshot) {
      // 3 - Generate a public URL for the file.
      return fileSnapshot.ref.getDownloadURL().then((url) => {
        // 4 - Update the chat message placeholder with the image’s 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);
  });
}

写経してて感じたけど、thenで繋げていくのが普通なのかな?
Promiseオブジェクトって要はC#でいうところのTaskみたいなものだと思ってるけど、それなら別にthenで繋げて書く必要もなさそうだと感じたけど、どうなんだろう。
好みの問題か。

あれ?実行してみたら画像出てないんだけど。
firebaseのStorageにはいるけど。。
写経ミスかと思ってチュートリアルのソースコードもコピペしたけど、だめっぽいし。この問題はちょっと寝かせる。

寝かせたら解決した。
やはりただのタイプミスだった。だせーーー。
というか、上記ですでに気づいているんだけど、firebaseのStorageにちゃんとイメージがあるという事実。
これはつまり、画像データの送信に問題なくて、メッセージの読込のどこかで問題があるということ。
少し考えればわかるのに、なーぜか気づけなかった。
あるあるだけど。
ちなみに、以下のようにミスってた。

うまくいった。。よかた。

Firebase

Posted by takumioda