🌀

FlutterでFlutter runでは動くのにVScodeの実行ができない

に公開

状況

Firebase導入時にかなりこの問題にハマりました。

状況として、
・Flutter runでは問題なくビルドできる
・Android Studioでもビルドできる
・VSCodeからのデバックのみ白画面が出力され実行できない
・Firebase導入の直前まで動作していた

こんな感じです。
VSCodeのみ実行できないことからVSCodeとシミュレーターの問題だと思いかなり時間を費やしてしまいました、、

結論から言うとVSCodeに問題はなく、以下が原因でした。(疑ってごめんね、、)

結論:Firebase.initializeApp() が完了する前にウィジェットが構築されていたこと!

解決前のコードがこちらです。

main.dart

// ---省略---

void main() async {
  WidgetsFlutterBinding.ensureInitialized(); // 追加
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'naily',
      ),
      home: userState() ? const FeedPage() : const LoginPage(),
    );
  }
}

このコードのざっくりとした流れは

  1. Firebase.initializeApp()でFirebase を初期化
  2. runApp() でアプリ本体を動かす
  3. userState(Firebaseを使用する関数)を実行

つまり、
Firebase.initializeApp() の非同期処理が完了する前に
userState()(Firebaseを使用する関数)が呼ばれ、null を返していたため、白画面が表示されてしまっていた

これでした。
この問題を解決するために以下を実行しました。

FutureBuilderでFirebaseの初期化が終わってから画面を表示

改善したコードが以下です。

main.dart

//---省略---

/// Firebaseの初期化を待ってからMyAppを表示
class AppInit extends StatelessWidget {
  const AppInit({super.key});

  
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform,
      ),
      builder: (context, snapshot) {
        // ローディング中
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const MaterialApp(
            home: Scaffold(
              body: Center(child: CircularProgressIndicator()),
            ),
          );
        }

        // エラー時
        if (snapshot.hasError) {
          return MaterialApp(
            home: Scaffold(
              body: Center(
                child: Text('🔥 Firebase初期化エラー: ${snapshot.error}'),
              ),
            ),
          );
        }

        // 初期化完了
        return const MyApp();
      },
    );
  }
}

class MyApp extends StatelessWidget {

// ---省略---

ここでは3つの状態があります。
Firebaseの準備中 :ConnectionState.waiting ローディングのぐるぐる
初期化に成功 :ConnectionState.done  MyApp() を表示する
初期化に失敗 :snapshot.hasError == true エラーメッセージ表示

これでFirebaseの初期化が終わってから画面を表示できるようになりました!

なぜFlutter runでは動いたのか

flutter run では Firebase の初期化がたまたま早く終わっていたため、UserState が正しく取得できていたようです。
逆に VSCode のデバッグは初期化がシビアで、runApp() までが早すぎて UserState が null だったため白画面が表示された。と言う流れでした。

まとめ

非同期初期化が必要な処理(Firebaseなど)は、必ず初期化完了を待ってから使うこと!

特に FirebaseAuth のように起動直後に使う場合は、FutureBuilder や async対応の初期化処理を正しく挟むようにします。

Discussion