LoginSignup
1
1

More than 3 years have passed since last update.

Cloud Functionsでリッチプッシュを送信するぞ

Last updated at Posted at 2020-02-06

Cloud Functions、便利ですよね。

前回はCloud Functionsに色々な処理を任せてしまおうという話をしました。

今回は、ほとんどどのアプリでも実装することになるであろう「Push通知」について解説します。

FCMトークンの設定や受信時の処理はモバイル側で実装する必要がありますが、「送信」についてはCloud Functionsで実装できます。

今回実装したい関数は以下のような要件と仮定します。

  • アプリ管理者がWebの管理画面から配信したいお知らせを登録する
  • お知らせ登録時にユーザーにプッシュ通知で配信される
  • 画像や通知音付きのリッチプッシュにしたい

Cloud Functionsでリッチプッシュを送信する関数を作ろう

実際に僕が使っているコードを例にしながら解説していきます。

プッシュ通知を送信するトリガーの設定


「アプリ管理者によるニュース登録」をトリガーとしたいので、newsモデル配下にデータが作成された時に、Cloud Functionsが起動するように設定する。

該当のコードは以下の通りです。

functions/src/index.ts
export const sendNotification = functions.database.ref("/news/{newsId}")
    .onCreate(async (snapshot: any, context: any) => {

Cloud Functionsからモバイルデバイスに送信するデータの作成

次に、Push通知で送信するデータを作ります。

FirebaseのFCMメッセージは2種類のデータを格納できます。

  1. notification(通知メッセージ)
  2. data(データメッセージ)

notificationには事前に定義された値を格納できます。

一方、dataは開発者が自由に値を設定できるオブジェクトです。

詳細はFirebaseの公式ドキュメントを参照してください。

弊社ではPush通知=「バッジ+画像+通知音付きのリッチプッシュ」であることが多いので、その場合の具体例を以下に示します。

functions/src/index.ts
const value = snapshot.val();    //新規作成されたニュースの値を格納
const message = {
    notification: {
        title: value.subject,    // 通知のタイトル
        body: value.description,    // 通知の本文
        sound: "default",    // 受信時の通知音
        mutable_content: 'true',    // 画像付きのリッチプッシュに必要
        content_available: 'true'    // アプリがバックグラウンドでも通知を届けるために必要
    },
    data: {
        "image-url": value.image_url    // Cloud Storageに格納している画像ファイルのURL
    }
};

Cloud Functionsからモバイルにリッチプッシュを送信するメソッドの使い方

Cloud FunctionsからモバイルにPush通知を送る時は、Firebase Admin SDKのメッセージを使います。

Push通知を一斉配信するために、sendAll()やsendMulticast()が使えたら便利なのですが、これらのメソッドが受け取れる値はMessage型だけなんですよね。

Message型はnotificationにsoundやmutable_contentといった値を設定できません。

つまり、リッチプッシュを実装できないということです。
(iOS/Androidアプリ側でこねくり回せばできるのかもしれません)

notificationにsoundなどの値を設定できるのは、MessagingPayload型だけ。

そしてMessagingPayload型を渡せるのはSendToXXXXX()メソッドのみです。

ということで仕方なくここではSendToDevice()を使います。

実際にメッセージを送信するための関数は以下のように実装しました。

functions/src/index.ts
const sendMessage = (fcmToken: string, message: any, options: any) => {
    return admin.messaging().sendToDevice(fcmToken, message, options)
        .then(() => {
            return Promise.resolve(null)
        })
        .catch(() => {
            return Promise.reject(null)
        });
    };

この関数はPromiseを返します。
あとでPromise.all()を使って配信を並列処理にするためです。

Cloud Functionsからリッチプッシュ通知を一斉配信する方法

Push通知を一斉配信する箇所の処理の流れは以下の通りです。

  1. userモデルから取得したデータからFCMトークンを取り出す
  2. FCMトークンが登録されているユーザーなら、promisesという配列にsendMessage()を引数と共に追加する
  3. 1~2を全ユーザー分繰り返したら、最後にPromise.all(promises)で並列実行する。

実際のコードは以下のようになります。

functions/src/index.ts
const users: any = await queryUserData(); // Userモデルからデータを取得
const userModelLength = users.numChildren(); // Userモデルのデータ数を取得

let promises: Array = [],
    counter = 0;

users.forEach((user: any) => {
    const userValue = user.val();
    const fcmToken: string = (userValue.fcmToken) ? userValue.fcmToken : "";
    if (fcmToken !== "") {
        promises.push(sendMessage(fcmToken, message, options))
    }

    counter += 1
    // 全ユーザーの繰り返し処理完了後にPromise.all()で実行する
    if (counter === userModelLength) { return Promise.all(promises) }
})

Cloud Functionsからモバイルにリッチプッシュ通知を送信するために気をつけること

このFunctionを実装する際にハマった点があるので共有します。

  • FCMトークンが登録されていないユーザーには送信できないので、例外処理や条件分岐が必要
  • soundmutable_contentなどを設定したい時はsend()メソッドは使えないのでSendToDevice()メソッドを使う
  • Promise.all()で並列処理にしないと、ユーザー数が多い場合、配信時間にタイムラグがでる
  • ただし並列処理にする場合、Cloud Functionsのメモリ上限を気にしなきゃいけない

以上です。

Push通知が実装できると一気にアプリでできる幅が広がります。

トリガーを工夫すれば、色々なタイミングでPush通知を送ることができますよ。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1