概要
Firebase Cloud Messaging(FCM)ではFCMトークンを利用してPUSH通知の送り先を指定します。
FCMトークンはユーザがアプリをアンインストールしたり、アプリを一定期間立ち上げなかったりすると失効し無効なトークンとして扱われます。そのため、失効したトークンを管理しておかないと、無駄な通知処理が発生し、パフォーマンスの低下やコスト増加を招く可能性があります。
実際に配信を行えば、トークンが失効しているかが判定できますが、PUSH通知を送らずにトークンの有効性を確認する方法が必要になる場合があります。以下がその例です
- 元々有効なトークンの管理をしておらず、把握している全トークンの有効性を一括で確認したい
- 一度無効と判断したトークンの有効性を再度チェックしたい(実際一度無効判定になったトークンが復活するケースを確認している)
この記事では、FCM APIのvalidate_onlyフラグを使って安全にトークンの有効性を検証する方法を紹介します。今回はPython(firebase-admin SDK)での実装事例を前提としています。
ポイント
1. validate_onlyフラグの活用
FCM APIのprojects.messages.sendにはvalidate_onlyというフラグがあります。これをtrueに設定することで、実際に配信せずにバリデーションだけを
実行できます。
Pythonのfirebase-admin SDKでは、dry_runパラメータがこのvalidate_onlyフラグに対応しています:
batch_response = messaging.send_each(messages, dry_run=True)
-
dry_run=True(= API のvalidate_only: true): バリデーションのみ実行、実際の配信は行われない -
dry_run=False(= API のvalidate_only: false): 実際に配信される
dry_run=Trueが実際に機能しているかの見分け方
dry_run=True が実際に機能しているかどうかはレスポンスのmessage_idで判別できます。通常message_idはリクエストごとにユニークなIDが返されますが、dry_run=Trueの場合は常に以下のように固定のIDが返されます:
-
dry_run=Trueの場合:projects/{project_id}/messages/fake_message_id -
dry_run=Falseの場合:projects/{project_id}/messages/{実際のメッセージID}
2. dataメッセージによる二重の安全策
万が一dry_runフラグが逆転してしまった場合(dry_run=Falseで実行されてしまった場合)でも、ユーザーへの誤配信を防ぐために、実際の配信では使用しないdataのみを設定したデータメッセージを利用します。FCMには通知メッセージとデータメッセージの2種類がありますが、ここではデータメッセージは受け取ったデータをクライアント側で処理する必要があり、無効な値だけの場合何も処理しないようになっていれば通知等は表示されません。
messages = [messaging.Message(
token=token,
data={
'validation': 'true' # 実際の配信で使用しないdataのみ
}
)]
検証
上記の方法で実際に配信されるかどうかを検証しました。
検証結果
| 条件 | message_id | 配信 |
|---|---|---|
| validationのdataのみ + dry_run=True | fake_message_id |
届かない ✅ |
| validationのdataのみ + dry_run=False | 正規のID | 届かない(dataだけなので表示されない)✅ |
| 通常のdata + dry_run=True | fake_message_id |
届かない ✅ |
| 通常のdata + dry_run=False | 正規のID | 届く |
実装例
以下が実際にユーザにPUSH通知を送らずにFCMトークンの有効性を確認するコードです。
#!/usr/bin/env python3
from firebase_admin import messaging, initialize_app, credentials
def validate_fcm_tokens(tokens, project_id, credential_path):
"""FCMトークンの有効性を検証する(実際の配信は行わない)"""
cred = credentials.Certificate(credential_path)
initialize_app(credential=cred, options={'projectId': project_id})
# 安全のため、validationフラグのみをdataとして設定
messages = [
messaging.Message(
token=token,
data={'validation': 'true'}
)
for token in tokens
]
# dry_run=Trueでバリデーションのみ実行(APIのvalidate_only=trueに相当)
batch_response = messaging.send_each(messages, dry_run=True)
valid_tokens = []
invalid_tokens = []
for idx, response in enumerate(batch_response.responses):
if response.success:
valid_tokens.append(tokens[idx])
else:
error_code = response.exception.code if response.exception else "Unknown"
invalid_tokens.append((tokens[idx], error_code))
return valid_tokens, invalid_tokens
まとめ
- FCM APIの
validate_onlyフラグ(Python SDKではdry_run=True)を使えば、実際に配信せずにトークンの有効性を確認できる - 万が一に備えて、実際の配信で使わないdataのみを設定することでより安全にトークンの有効性を確認できる
この方法を使えば、FCMトークンの有効性を安全に検証でき、無効なトークンを効率的に管理できます。