Flutter: Firebase In-App Messagingの「デバイスでテスト」のメッセージが届かない
結論:flutterfire configureの再実行と、SHA-1のFirebase・GCPへの登録
2023/5/7 Flutter エラー・バグ日記
アプリ起動中にメッセージを送信できる「Firebase In-App Messaging」(以下「FIAM」)を実装中、Androidでデバッグビルドしたアプリに、テストメッセージが表示されなかった。
iOSでは表示されたが、Androidの実機・エミュレーターいずれも表示されなかった。
ネット上の情報やChatGPTからの情報だけでは解決できず、かなり苦労したので、その経過を記録。
参考にさせていただいた記事
公式サイトの説明は以下。
基本的な実装方法に関して、比較的新しい日本語の解説記事は以下。とても参考にさせていただいたm(_ _)m。
こちらの記事
で整理している基本的なFirebaseの設定を済ませた上で、上記記事を参考に実装を試みた。
実装上の問題は見つからないが、テストメッセージが表示されない
Firebaseの設定が済んでいれば、Flutter側の設定は簡単で、細かい条件設定をしないのであれば、下記パッケージ
を「pubspec.yaml」に登録して「pub get」し、コード中にimportするだけで良いはず。
import 'package:firebase_in_app_messaging/firebase_in_app_messaging.dart';
但し、テストデバイスにメッセージを送るには、テストデバイスの「Firebase installation ID」(以下「FID」)が必要になる。
FIDの取得方法は様々あるようだが、自分の場合は、下記パッケージ
を導入し、下記のとおりmain関数内で「debugPrint」させることで、コンソール上から確認することにした。
import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_in_app_messaging/firebase_in_app_messaging.dart'; import 'package:firebase_app_installations/firebase_app_installations.dart'; Future<void> main() async{ // main関数内で非同期処理をするときはこれが必要 WidgetsFlutterBinding.ensureInitialized(); // Firebaseの初期化処理 await Firebase.initializeApp(); // FIDの取得とコンソール表示(テストメッセージ用) String fidO = await FirebaseInstallations.instance.getId(); debugPrint('FID : $fidO'); runApp(MyApp()); }
FIDが確認できたら、Firebase上のFIAM管理画面で「デバイスでテスト」を押し、FIDを登録してテスト送信すれば、メッセージが表示されるはず(いったんアプリを非アクティブ化→アクティブ化する必要あり)、、、だったが、何度やっても表示されなかった。
Firebase In-App Messaging APIは有効化済
ネット上で、メッセージが表示されない原因を調べると、
W/FIAM.Headless(####): Service fetch error: PERMISSION_DENIED: Firebase In-App Messaging API has not been used in project XXXXXXXXX before or it is disabled.
のようなエラーがコンソールに出るケースの情報が、多く見られる。
この場合、GCP(Google Cloud Platform)の画面で、「Firebase In-App Messaging API」を有効化すれば解消するようだが、自分の場合は既に有効化しており、上記エラーも表示されていなかった。。
Firebase Installations Serviceが機能していないと分かる
Firebase側からテストメッセージを送信した後、デバッグビルド中のアプリを、非アクティブ化→アクティブ化するタイミングで、コンソールに下記メッセージが表示される事に気づいた。
I/FIAM.Headless(#####): went foreground I/FIAM.Display(#####): Binding to activity: MainActivity I/FIAM.Headless(#####): Setting display event component ・・・(略)・・・ I/FIAM.Headless(#####): Forcing fetch from service rather than cache. Test Device: false | App Fresh Install: true I/FIAM.Headless(#####): Recoverable exception while reading cache: /data/user/0/########/files/fiam_impressions_store_file: open failed: ENOENT (No such file or directory) ・・・(略)・・・ W/FIAM.Headless(#####): Service fetch error: Firebase Installations Service is unavailable. Please try again later.
最後の2つの文(「No such file or directory」と「Service fetch error」)が、今回の不具合に関係している印象。
ChatGPTに意見を求めると、最後の1文の方が問題らしく、下記内容をアドバイスしてくれた(この他にもコメントはあったが、その後の検証で無関係だったため、ここでは割愛)。
- 「Firebase Installations Service is unavailable. Please try again later.」は、Firebase Installations Service(FIS)が利用できない状況を示している。FISが利用できないと、Firebase In-App Messaging(FIAM)も正常に動作しないことがある。
- Firebaseの設定ファイル(google-services.json)が、プロジェクト内に正しく配置されていることを確認すべし。
1点目(要因部分)については、確かに下記Firebase公式の説明
を見ると、FIAMを動作させる際、内部的に「Firebase Installations Service」(以下「FIS」)が利用されるようなので、FISが「unavailable」だと不具合が生じると理解できた。
また、2点目(対策部分)については、ChatGPTが2021年9月までの情報をベースに回答しているためと思われるが、現在のFirebaseでは、「google-services.json」の設置作業は不要になっている。
そのため、これに相当する作業として、ターミナルでFirebaseにログインした上で、「flutterfire configure」を実行して「firebase_options.dart」を更新する必要があると理解した。
この点については、こちらのFirebase公式説明
にもあるとおり、
新しい Firebase サービスまたはプロダクトの使用を開始する場合は、「flutterfire configure」を再実行する必要がある
との事なので、FIAM導入後も必要なのだろう。
そこで、「flutterfire configure」を実行して「firebase_options.dart」を更新後、改めて「デバイスでテスト」を実行してみたが、依然、テストメッセージは表示されなかった。
コンソール上にも引き続き、同じエラーメッセージが表示されている。。
APIキーの制限を掛けていた事に気づく
「Firebase Installations Service is unavailable」や「Service fetch error」でネット検索すると、下記Q&A記事を見つけた。
1年以上前の記事ではあるが、
「google-services.json」を更新したのに、FIAMのメッセージが表示されない
という内容なので、自分の状況と全く同じ。
解決マーク(緑のチェック)がついている回答内容を見ると、API制限について適切な処理が必要らしい。
回答内に掲載されているリンク先のGitHubのページを見ると、
アプリで使用されているAPI キーが、FirebaseインストールAPIのホワイトリストに登録されていることを確認する
必要があるとのこと。
また、別で見つけた下記記事
においても、
アプリケーションで使用するAPI キーにAPI キー制限を使用している場合は、それらの制限を拡張して、firebaseinstallations.googleapis.comで新しいFirebaseインストールサービスを使用できるようにする必要があります。
との解説がなされていた。
そこで、対象アプリのGCP(Google Cloud Platform)の管理画面へ行き、
「APIとサービス」→「認証情報」→「APIキー」の「Android key」→「APIキーを編集」の画面
を確認すると、APIキーの使用を、指定したAndroidアプリのみに制限する設定がなされていた(セキュリティのために、制限設定したことを忘れていた。。)。
本来、アプリのパッケージ名と、デバッグ証明書のフィンガープリント(SHA-1)を登録しなければならないのだが、この対応をやっていなかった。。
※Google Play Console上で確認できるリリース証明書のフィンガープリントのみ、登録していた。
そのため、デバッグビルドしたアプリでは、「Firebase Installations Service」の利用が認証で弾かれてしまい、FIAMが動作できなかったものと思われる。
早速、ターミナルから
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
を実行し、デバッグ証明書のフィンガープリント(SHA-1)を表示させ、GCPとFirebaseの所定箇所に登録した。
これでFIAMの「デバイスでテスト」のテストメッセージを送信したところ、ようやくアプリ内にメッセージが表示されるようになった。
いくつか留意点(キー制限、保存で反映、リリース用SHA-1登録)
留意点①:
自分の場合、使用可能なAPIキー自体の制限はしていなかったが、もし制限していた場合には、上記GCPの画面の「APIの制限」のところで、FIAMのAPI(Firebase In-App Messaging API)を使用可能リストに追加する必要があると思われる。
留意点②:
GCPの「APIキーを編集」の画面は、画面最下部の「保存」を押さないと、変更が反映されない点に留意が必要。
※当初、SHA-1を登録したつもりなのに、FIAMのメッセージが表示されず、しばらく詰まっていたが、実は「保存」を押しておらず、反映されていないだけだった。。
留意点③:
Google PlayでリリースしたAndroidアプリには、デバッグ用とは別の「リリース証明書のフィンガープリント」が割り振られるため、リリース前に、リリース用のSHA-1(Google Play Consoleで確認可能)を、GCPとFirebaseに登録しておく必要があると思われる。
※前述のとおり、自分の場合は、先にリリース用だけ登録していたため、逆にデバッグ用のアプリでFIAMが動作しなかった。
まとめ
改めて整理すると、FIAMの「デバイスでテスト」のテストメッセージを送れなかった理由と対策は、以下2点だった。
- 「firebase_options.dart」を更新していなかったこと
→「flutterfire configure」を実行して更新 - APIキーのアプリケーション制限がかかっていたのに、デバッグ証明書のフィンガープリント(SHA-1)を登録していなかったこと
→デバッグ用のSHA-1をGCPとFirebaseに登録(Google Playリリース時には、リリース証明書も登録が必要)
\一般的なエラー対処法をまとめた記事はこちら/
リリースしたアプリ(全てFlutterで開発)
個人アプリ開発で役立ったもの
おすすめの学習教材
\超初心者向けでオススメな元Udemyの講座/
\キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/
\Gitの基礎について無料で学べる/
おすすめの学習書籍
\実用的。image_pickerに関してかなり助けられた/
\Dartの基礎文法を素早くインプットできる/