[Flutter] Firebase導入後にiOSビルドが起動しなくなる場合の対処法と原因

icatch image Flutter

今回はFlutterのバグ解決方法の紹介です!

この記事をご覧になられている方はFlutterのインストールと、FlutterプロジェクトへFirebaseの導入は済まされていることかと思います。
もしまだの方がいらしたら以下の記事からどうぞ!
 [Flutter] とにかく楽して安全にUbuntuに環境構築する

Firebase導入後にiOSアプリが起動しない

章タイトルの通りです。通知機能などを実装するためにFlutterプロジェクトにFirebaseを導入後、iOSアプリのリリースビルドをするとアプリ画面が真っ白のまま起動しなくなることがあります。
いわゆるスプラッシュ画面やスプラッシュスクリーンと呼ばれるアプリ起動中の画面のまま、最初の画面に進まないような症状です。

イメージとしてはこの画面でフリーズしている状態です。

解決策

結論 : getToken()の前にAPNsTokenを取得してください。

Firebase Messagingの基本的な設定として、以下のようなコードを書かれているかと思います。

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  
  FirebaseMessaging fireMsg = FirebaseMessaging.instance;
  String fireToken = await fireMsg.getToken();

  runApp(MainApp());
}

iOSの場合のみエラーが出るので、起動OSを判別して以下の処理を追加します!
これでもう一度リリースビルドすれば動きます👍️。お疲れ様でした!

import "package:universal_platform/universal_platform.dart";

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  
  FirebaseMessaging fireMsg = FirebaseMessaging.instance;
  
  // ここを追加 ------------------------------------------------
  if(UniversalPlatform.isIOS){ 
    while (await fireMsg.getAPNSToken() == null) {
      await Future.delayed(const Duration(milliseconds: 100));
    }
  }
  // ---------------------------------------------------------
 
  String fireToken = await fireMsg.getToken();

  runApp(MainApp());
}

原因

原因 : APNsトークンを取得前にFCMトークンを取得しようとしたから

Firebaseを導入して通知機能を実装しようとしたら真っ白!というのが今回のテーマですが、これの原因は↑の通りです。

FirebaseではFirebase Cloud Messaging(FCM)と呼ばれるサービスでプッシュ通知機能を提供しています。これはGoogleが携わっているのでAndroid版ではそのまま使えてエラーが出ませんでした。

一方で、iOSやmacOSなどを搭載したApple製品はApple Push Notification service(APNs)と呼ばれるサービスでプッシュ通知機能を提供しています。
Apple製品へのプッシュ通知は必ずAPNs経由で届くため、FCMとAPNsを連携させる必要があります。

Firebaseの設定の際に、APNsの認証キーをアップロードしたことは覚えておられますか?
設定はそれで十分ですが、FirebaseMessaging.instance.getToken() メソッドではAPNsトークンが取得される前にFCMトークンを取得する場合があるようです。
そうするとAPNsとの連携がうまくいかずにgetTokenメソッドがエラーになり、mainメソッドも途中で落ち、runAppまでたどり着かないので画面が真っ白のまま…のようです。

今回ご紹介した解決策は、FirebaseMessaging.instance.getToken() を実行する前にAPNsトークンが取得し終わるまで待つ事です。
それが追記していただいた以下のコードでした。
APNsトークンの取得が終わっていない間、FirebaseMessaging.instance.getAPNSToken() メソッドはnullを返します。1度呼び出せばAPNsトークン取得まで待機してくれる訳では無いのが曲者でした🤯
対処法としてAPNsトークンが取得できるまで100ミリ秒周期でポーリングしています。特別なことは無い素直な方法ですが一番確実かと思われます。

while (await fireMsg.getAPNSToken() == null) {
  await Future.delayed(const Duration(milliseconds: 100));
}

この記事が役に立ちましたらぜひ左下のGoodボタンをお願いします!
皆様のGoodが執筆の励みになります。

コメント

タイトルとURLをコピーしました