私たちは Firebase を通じ、デベロッパーがサーバーの管理から解放され、クライアントサイドのコードだけでウェブアプリやモバイルアプリを作成できる世界を実現するために努力しています。しかし、ときには独自にサーバーを立ち上げて活用しなければならない場合もあります。そこで、昨年 11 月に Firebase Admin SDK を発表しました。

本日は、Admin SDK の 2 つの新機能を紹介します。
  • Node.js SDK に、Firebase Cloud Messaging(FCM)経由でメッセージを送信するための Admin API が追加されました。
  • Java SDK が複数のビルトイン認証情報で初期化できるようになり、とりわけ Google のインフラ上で簡単に使えるようになりました。
Admin Node.js FCM API

新しい Admin Node.js FCM API では、FCM 経由でメッセージを送信するプロセスが簡単になっています。この新しい API は、何の追加設定もしなくても使うことができます。Node.js SDK の認証を行っている既存の認証情報がすべて処理してくれるからです。新しい API には、個々の端末、端末グループ、トピック、条件に対してメッセージを送信するメソッドが含まれています。
たとえば、開催が迫っているスーパーボウル用のアプリを作成し、アトランタ ファルコンズのトピック(/topics/falcons)またはニューイングランド ペイトリオッツのトピック(/topics/patriots)をサブスクライブしているユーザーに通知する場合を考えてみましょう。
var admin = require("firebase-admin");

// Fetch the service account key JSON file contents
var serviceAccount = require("path/to/serviceAccountKey.json");

// Initialize the app with a service account, granting admin privileges
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://<DATABASE_NAME>.firebaseio.com"
});

// Define who to send the message to
var condition = "'falcons' in topics || 'patriots' in topics";

// Define the message payload
var payload = {
  notification: {
    title: "Super Bowl LI: Falcons vs. Patriots",
    body: "Your team is Super Bowl bound! Get the inside scoop on the big game."
  }
};

// Send a message to the condition with the provided payload
admin.messaging.sendToCondition(condition, payload)
  .then(function(response) {
    console.log("Successfully sent message! Server response:", response);
  })
  .catch(function(error) {
    console.log("Error sending message:", error);
  });
各 FCM メソッドには、3 番目の省略可能な引数に、メッセージのオプションを指定することもできます。たとえば、試合までもう 1 週間を切っているので、有効期間が 1 週間のメッセージを優先度 high で送ってみましょう。
// condition and payload are the same as above

var options = {
  priority: "high",
  timeToLive: 60 * 60 * 24 * 7
};

admin.messaging.sendToCondition(condition, payload, options)
  .then(function(response) {
    console.log("Successfully sent message! Server response:", response);
  })
  .catch(function(error) {
    console.log("Error sending message:", error);
  });
新しい Admin Node.js FCM API を使うと、このようなことができます。詳しいコードサンプルやドキュメントについては、メッセージの送信をご覧ください。

Admin Java 認証情報インターフェース 

昨年 11 月に Admin SDK が公開されて以来、Node.js SDK はいくつかの初期化メソッドをサポートしていますが、Java SDK はサービス アカウント証明書ファイルを使った初期化しかできませんでした。最新の Admin Java SDK リリースでは、同様な認証情報インターフェースが両方の SDK とも提供するようになっています。そして、いくつかの便利なデフォルト実装もあります。

新しい API へのアップグレードは簡単です。以前からの SDK 初期化方法では、次のように setServiceAccount() ãƒ¡ã‚½ãƒƒãƒ‰ã‚’使います。
FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccountCredentials.json");

FirebaseOptions options = new FirebaseOptions.Builder()
    .setServiceAccount(serviceAccount)
    .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com")
    .build();

FirebaseApp.initializeApp(options);
アップデートされた SDK 初期化方法では、次のように setCredential() ãƒ¡ã‚½ãƒƒãƒ‰ã‚’使います。
FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccountCredentials.json");

FirebaseOptions options = new FirebaseOptions.Builder()
    .setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
    .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com")
    .build();

FirebaseApp.initializeApp(options);

Admin Java SDK には、Google Application Default Credentials に基づいた認証情報の実装も含まれており、Google App Engine や Google Compute Engine など、Google のインフラ上でのサービス アカウント認証情報を自動検出できます。これによって、サービス アカウントの認証情報を自分で管理する必要がなくなります。そのため、何の設定も行わなくても、Google Application Default Credentials を使ってローカル環境、ステージング環境、本番環境でまったく同じコードを実行できます。
FirebaseOptions options = new FirebaseOptions.Builder()
    .setCredential(FirebaseCredentials.applicationDefault())
    .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com")
    .build();

FirebaseApp.initializeApp(options);

詳しいコードサンプルやドキュメントは、SDK の初期化をご覧ください。

Admin SDK の今後


Firebase エコシステムのバックエンド デベロッパーに優れたサポートを幅広く提供するため、私たちは努力を続けています。Firebase Admin SDK に追加される今後の機能にもご期待ください。ご希望の機能がある場合は、機能リクエスト サポート チャンネルからリクエストを送信してください。


Posted by Khanh LeViet - Developer Relations Team





Frank van Puffelen
エンジニア

本記事では、Firebase Database、Cloud Messaging、Node.js を使用して Android 端末間で通知を送信する方法を説明します。

Firebase Database は、マルチユーザー モバイル アプリケーション構築のためのすばらしいバックエンドです。複数のユーザーがアプリケーションを開いていれば、あるユーザーによる変更はすべての接続中のユーザーにミリ秒以内に同期されます。


チャット アプリケーションがその良い例です。あるユーザーが送信したメッセージは即座に他のユーザーに同期されるため、たいへんスムーズな使用感を実現できます。

しかし、Android 端末上でアプリを実行していないユーザーはどうなるでしょうか。その場合、端末は Firebase Database サーバーに接続されていないため、変更を自動的に受信することはできません。通常のチャット メッセージの場合はそれでも大丈夫ですが、ほとんどのチャットアプリで @ をつけて誰かを呼び出すときは、そのユーザーを引き戻したいことがほとんどでしょう(例: 「@puf ちょっといいかな?」)。

通常、そのような場合は、Firebase Cloud Messaging を使ってそのユーザーの端末に通知を送ります。このような通知は端末の通知エリアに表示され、何かおもしろいイベントが起こったときにユーザーをアプリに引き戻す手段となります。



本記事では、Firebase Cloud Messaging を使って端末に通知を送信してみます。API キーを Android 端末に公開しなくてもいいように、FCM と通信する Node スクリプトを記述します。しかし、まず最初に、Android 端末から通知を 送信 するコードがどのようなものかを理解しましょう。

Android アプリからプッシュ通知を送信する

ユーザーに通知を送信するには、Android アプリで次のようにします。
sendNotificationToUser("puf", "Hi there puf!");
sendNotificationToUser() メソッドは、次のように実装されているヘルパー メソッドです。
public static void sendNotificationToUser(String user, final String message) {
    Firebase ref = new Firebase(FIREBASE_URL);
    final Firebase notifications = ref.child("notificationRequests");

    Map notification = new HashMap<>();
    notification.put("username", user);
    notification.put("message", message);

    notifications.push().setValue(notification);
}

おそらく、これは予想とは異なるものでしょう。このコードは、通知データをデータベースに書き込んでいるだけです。これでどうやって通知を送信しているのでしょうか。
実は、通知の送信は行っていません。ここでは、データベースをキューとして使用しています。Android アプリは通知を送信するリクエストをデータベースに書き込みます。それを Node スクリプトがピックアップして、Cloud Messaging 経由で通知を送信します。そのスクリプトは後ほど見てゆきます。まずは、このアプリのデータ構造について少しお話ししましょう。

データ構造

他のアプリケーションと同じく、Firebase をバックエンドとしたアプリケーションでもデータ構造は特に重要な部分の 1 つです。通知を送信するためのデータ構造は既に見ています。
  notificationRequests
    $pushid
      message: "Hello there"
      username: "puf"

これが Android アプリが書き込んだノードです。各通知リクエストは、送信するメッセージと通知対象のユーザー名で構成されています。ユーザー名を実際の通知にどのようにマッピングするかは、アプリケーションによって異なります。この場合は、トピックベースの通知を使用します。つまり、ユーザー名は/topics/user_ というトピックにマッピングされます。この場合、メッセージは /topics/user_puf に送信されます(Android アプリは、このトピックをサブスクライブします)。
では、先ほどお話しした Node コードを見てみましょう。

Node コード

ここまでで、Android アプリからデータベースに通知リクエストを書き込む方法と、データベース構造がどのようなものかがわかりました。それでは、実際に通知を送信するコードを書いてゆきます。
これは、先ほど確認した通知キューを監視する Node プロセスになります。このキューに子供が追加されるたびに必要な情報を取り出し、Cloud Messaging REST API を呼び出して通知を送信します。処理が成功した場合、キューから通知リクエストを削除します。

var firebase = require('firebase');
var request = require('request');

var API_KEY = "..."; // Your Firebase Cloud Server API key

firebase.initializeApp({
  serviceAccount: ".json",
  databaseURL: "https://.firebaseio.com/"
});
ref = firebase.database().ref();

function listenForNotificationRequests() {
  var requests = ref.child('notificationRequests');
  ref.on('child_added', function(requestSnapshot) {
    var request = requestSnapshot.val();
    sendNotificationToUser(
      request.username,
      request.message,
      function() {
        request.ref().remove();
      }
    );
  }, function(error) {
    console.error(error);
  });
};

function sendNotificationToUser(username, message, onSuccess) {
  request({
    url: 'https://fcm.googleapis.com/fcm/send',
    method: 'POST',
    headers: {
      'Content-Type' :' application/json',
      'Authorization': 'key='+API_KEY
    },
    body: JSON.stringify({
      notification: {
        title: message
      },
      to : '/topics/user_'+username
    })
  }, function(error, response, body) {
    if (error) { console.error(error); }
    else if (response.statusCode >= 400) {
      console.error('HTTP Error: '+response.statusCode+' - '+response.statusMessage);
    }
    else {
      onSuccess();
    }
  });
}

// start listening
listenForNotificationRequests();
child_added イベントをリッスンしているため、キューの各通知リクエストに対して sendNotificationToUser() が呼び出されます。送信が成功すると、キューからリクエストを削除します。今回の単純なスクリプトでは、自動リトライは行っていません。そのため、スクリプトを再起動した場合のみ、失敗した通知がリトライされます。もう少し拡張性があるアプローチをとる場合は、firebase-queue ライブラリの使用を検討してください。

スクリプトに API_KEY 定数が含まれていることにお気づきかもしれません。これは、メッセージを送信するために Firebase Cloud Messaging から取得したキーです。まさにこの点が、Android アプリでこのコードを実行しない理由です。API キーがわかれば、そのアプリの名前でメッセージを送信することができるので、悪用される可能性があります。このキーをサーバー上の Node スクリプトで保持することによって、Android アプリのユーザーがキーを入手できないようにしています。

Android アプリで通知を受信する

Firebase Cloud Messaging SDK が通知メッセージを扱う方法のおかげで、Android のコードは最低限で済みます。アプリがバックグラウンドで動作している際に通知メッセージを受け取ると、システム通知エリアにメッセージが表示されます。ユーザーがメッセージをクリックすると、アプリが自動的に開きます。こういった形でアプリを再び開いてもらうことは、まさにこのアプリで実現したかったことです。そのために行う必要があるのは、Firebase Messaging ライブラリをインクルードしてユーザー名のトピックをサブスクライブすることだけです。

トピックのサブスクライブ


あるユーザー宛てのメッセージを識別するために、ユーザー名に一致するトピックを使用します。

String username = "puf";
FirebaseMessaging.getInstance().subscribeToTopic("user_"+username);

この部分はアプリに依存する処理であるため、このスニペットではユーザー名をハードコードしています。しかし、一度ユーザー名さえ決まってしまえば、通知の登録に必要なのは 1 行のコードだけで済むことはわかるでしょう(あとは、アプリがバックグラウンドである場合に通知を表示する部分だけです)。
アプリがフォアグランドである場合に通知の処理を行いたい場合や、メッセージとともに他のデータも送りたい場合は、Firebase Cloud Messaging とメッセージ タイプのドキュメントをご覧ください。

まとめ


本記事では、Firebase と Node スクリプトを使用して Android アプリにプッシュ通知を送る方法を説明しました。今回は Android コードから通知を送信しましたが、Firebase Database にアクセスできる他のアプリケーションからも同じように簡単に送信することができます。iOS サポートを追加することも簡単で、依存性を追加してリモート通知用の登録を行うだけです。


Posted by Yoshifumi Yamaguchi - Developer Relations Team