Cloud Functions for Firebaseを使ってアプリ内課金の発生を検知してSlack通知する

6 min読了の目安(約3800字TECH技術記事

FirebaseのCloud Functionsは、Firebase内のイベントとお手軽に連携することができます。
今回は、Analyticsイベントの発火を検知して、Cloud FunctionsからSlack通知してみましょう。

セットアップ

  1. Nodeが必要なので、インストール。
    • Firebase Cloud FunctionsはNode8とNode10が動きます
    • でも、Node8のサポートは2020/03で終了したので、Node10を利用しましょう
    • ただし、 Node10でCloud Functions for Firebaseを利用するには、プランをBlazeにする必要があるので注意
  2. Firebase Cloud Functionの 公式ドキュメント から、Firebase CLIをインストールしましょう
    • $ npm install -g firebase-tools
  3. FirebaseCLIでFirebaseにログイン
    • $ firebase login
  4. ログインできていることを確認
    • $ firebase projects:list
  5. ディレクトリに移動してfunctionsを初期化
    • $ firebase init functions
    • Create a new project を選択するとProjectから生成してくれる。手順に従って進む。
    • ProjectIDとNameを登録し、TypeScriptかJavaScriptを選択。TSLintを利用するかどうかも聞かれる
    • npmの依存をインストールするかどうかを聞かれる。yarnを利用したい場合は、No
  6. 初期設定できたら、 firebase.json .firebaserc を確認
    • [ ポイント] もし複数環境を切り替えたい場合、"dev": "sandbox-dev-hoge" のようにdefaultの横に足してあげると良い
  7. functionsディレクトリが生成されていて、そこにfunctions関数のソースコードがある。開発はこの中で行う
  8. デプロイは firebase deploy --only functions
  9. 管理画面にも今作ったfirebaseプロジェクトができているはず

アプリ内課金イベントを検知する

アプリ内課金のAnalyticsイベントは、デフォルトで設定されており、Firebase Analyticsが自動で検知して収集してくれます。

複数の課金商品がある場合などは、独自に設定しましょう。

Analyticsイベントとの連携方法

Firebase Analytics のイベント連携 ドキュメント より以下を引用

Cloud Functions では、Google アナリティクスの AnalyticsEvent がサポートされています。このイベントは、ユーザー アクティビティでコンバージョン イベントが生成されるたびにトリガーされます。たとえば、in_app_purchase イベントが生成されるとトリガーされる関数を作成して、アプリ内購入が行われたことを示すことができます。functions.analytics.event() メソッドを使用して関数をトリガーするアナリティクス イベントを指定し、onLog() イベント ハンドラ内でイベントを処理する必要があります。

つまり、 functions.analytics.event('in_app_purchase').onLog((event) => { ... } と書くことで、イベント連携ができます。

実装する

  1. SlackのIncoming Webhook URLを生成して取得
  2. add package $ npm install request @types/request
  3. firebase functions:config:set slack.url="URLを入れる"
    • これはコード内でfunctions.config().slack.urlとして参照できる
  4. 以下を実装
    • .region("asia-northeast1") とつけて東京リージョンを指定
    • 引数のeventのなかに情報が入っている
    • .analytics.event("in_app_purchase_coins") には、監視したいイベントを指定する
import * as functions from "firebase-functions";
import * as request from "request";

exports.sendSlackMessageOnPurchaseCoin = functions
  .region("asia-northeast1")
  .analytics.event("in_app_purchase_coins")
  .onLog((event) => sentMessageToSlack(event, "コインが購入されました"));

exports.sendSlackMessageOnPurchaseSubscription = functions
  .region("asia-northeast1")
  .analytics.event("in_app_purchase_subscription")
  .onLog((event) => sentMessageToSlack(event, "サブスクが購入されました"));

const sentMessageToSlack = (
  event: functions.analytics.AnalyticsEvent,
  message: string
): request.Request => {
  const url = functions.config().slack.url;
  const user = event.user;
  const purchaseValue = event.valueInUSD; // Amount of the purchase in USD.
  const userLanguage = user?.deviceInfo.userDefaultLanguage; // The user language in language-country format.
  const screenName = event.params["firebase_screen_class"];

  return request.post(url, {
    json: {
      text:
        `${message}💰 $${purchaseValue} \n` +
        "```\n" +
        `at time: ${event.logTime} \n` +
        `lang: ${userLanguage} \n` +
        `country: ${event.user?.geoInfo.country} \n` +
        `model: ${event.user?.deviceInfo?.mobileModelName} \n` +
        `appId: ${event.user?.appInfo?.appId} \n` +
        `appVersion: ${event.user?.appInfo?.appVersion} \n` +
        `screen: ${screenName} \n` +
        "```\n",
    },
  });
};

https://gist.github.com/kichiemon/57b8fdfc5ae19e30b6089ca73d0ba0bc

参考