使えなくなりつつあるFCMの「以前の HTTP プロトコル」から、小さな変更だけでとりあえずWebPushを送る方法

こんにちは。 エキサイト株式会社の三浦です。

以前この記事で、非推奨なFCMの使い方である「以前の HTTP プロトコル」ではWebPushが送信できなくなっている、というお話をしました。

tech.excite.co.jp

今回は、調査していく中で判明した、とりあえず取ることが出来る一時対応について説明します。

「以前の HTTP プロトコル」でWebPushが送信できなくなった

こちらの記事でも紹介しましたが、FirebaseのPush通知サービスであるFCMにおいて、非推奨な「以前の HTTP プロトコル」で送信したWebPushがエラーを返すようになっています。

tech.excite.co.jp

対応として現在の推奨方法である「FCM HTTP v1 API」に切り替える必要がありますが、その際に以下の調査が必要になるかもしれません。

  • 現在のWebPushの機能を保ったままのWebPush送信・受信方法の調査
  • 現在のユーザを引き継ぐ形で切り替えることが出来るのかの調査

これらの調査や実装に時間がかかれば、その間WebPushがほとんど送信できないということになってしまいます。

移行が完了するまでの一時的な対応でもいいので、とりあえず大きな変更なくWebPushを復活させる方法は無いのでしょうか?

「以前の HTTP プロトコル」から、小さな変更だけでとりあえずWebPushを送る方法

実は、多少の変更は必要になりますが、そこまで大きな変更なく「とりあえずWebPushを送信させる」ことは(少なくとも2023/06現在は)可能です。

FCMのドキュメントに、「以前の HTTP プロトコル」から「FCM HTTP v1 API」への移行方法が載っています。

firebase.google.com

これに従い、以下のように変更します。

送信先URLを「FCM HTTP v1 API」のものに変更する

送信先URLを変更します。

なお、新しい送信先URLには、利用するFirebaseアカウントのプロジェクト名を使用します。

プロジェクト名が sample-project であった場合は、以下のように変更します。

変更前: https://fcm.googleapis.com/fcm/send

変更後: https://fcm.googleapis.com/v1/projects/sample-project/messages:send

認証方法を変更する

WebPush送信時、今まではFirebaseアカウントが発行していたサーバーキーを使っていたと思いますが、これをFirebaseが発行するアクセストークンに切り替えます。

以前のサーバーキーは一度発行されれば固定値として使えていましたが、新しいアクセストークンはセキュリティ強化のため、一定時間で期限切れとなるようになっています。

そのため、動的に生成することが必要です。

基本的にはドキュメントに載っている手順で生成できますが、Javaでアクセストークンを発行する方法については、ドキュメントどおりに行ってもエラーになってしまうので注意が必要です。

ドキュメントでは、以下のようになっています。

private static String getAccessToken() throws IOException {
  GoogleCredentials googleCredentials = GoogleCredentials
          .fromStream(new FileInputStream("service-account.json"))
          .createScoped(Arrays.asList(SCOPES));
  googleCredentials.refreshAccessToken();
  return googleCredentials.getAccessToken().getTokenValue();
}

ですがこれだとエラーになってしまうので、以下のようにしましょう。

private static String getAccessToken() throws IOException {
  GoogleCredentials googleCredentials = GoogleCredentials
          .fromStream(new FileInputStream("service-account.json"))
          .createScoped(Arrays.asList(SCOPES));
  googleCredentials.refresh(); // ここを refresh() にしないとエラーになる
  return googleCredentials.getAccessToken().getTokenValue();
}

また、認証ヘッダの形式も変更します。

変更前: Authorization: key={サーバーキー}

変更後: Authorization: Bearer {アクセストークン}

これで、認証も問題なく出来るようになります。

ペイロードは送れない

ドキュメントでは最後に「送信リクエストのペイロードを更新する」という項目があり、一見書いてあるとおりに変更すればペイロードを送信できるように見えます。

しかし、少なくとも私が調査した限り、どうやってもペイロードを含めて送ることができませんでした。

ただし逆に言えば、 ペイロード無しなら上記の方法でWebPushを送ることが出来る ということです。

とりあえずこれで、ブラウザに「WebPushが来た」ということだけは知らせることが出来るようになりました。

ブラウザから通知データを取得してもらう

もちろん、「WebPushが来た」ことだけわかっても、タイトルやリダイレクト先等が分からなければブラウザが通知を表示することができません。

この方法で一時対応をする場合は、ブラウザがWebPushを受け取ったら、サービスワーカーからAPI等にリクエストしてもらい、通知データを取得してもらうようにするのが良いでしょう。

とりあえず上記の方法を取れば、一時対応ではありますがWebPushを復活させることができます。

最後に

とりあえずWebPushは復活できますが、そもそもこの無理矢理な迂回方法もいつまで使えるかわかりません。

あくまで一時対応・時間稼ぎであることを前提に、早急に正式な「FCM HTTP v1 API」に移行しましょう。