Flutter

Flutterアプリが本番ビルドで真っ白になった原因と対処法

Flutterアプリを本番ビルドしてインストールしたら、起動直後に真っ白な画面で止まってしまった。デバッグビルドでは正常に動くのに、本番だけ再現する。

この記事ではその原因と調査手順をまとめます。

環境

  • Flutter 3.x
  • Android targetSdk 35
  • Gradle 8 / AGP / Kotlin 2.x
  • Flavor: dev / prod

症状

  • flutter run (デバッグ)→ 正常動作
  • flutter build apk --flavor prod → インストール後、起動すると真っ白で止まる
  • クラッシュログなし、エラーも出ない

原因

--dart-define で渡す Flavor 情報が本番ビルドのコマンドに含まれていなかったことが原因でした。

アプリ内の初期化処理で Flavor を参照していたため、値が空になり初期化が止まっていました。

# ❌ Flavor が渡されていないビルドコマンド
flutter build apk --flavor prod

# ✅ dart-define で明示的に渡す
flutter build apk --flavor prod --dart-define=FLAVOR=prod

調査手順

真っ白な画面はクラッシュではなく「初期化が止まっている」状態なので、ログに何も出ません。以下の順番で切り分けました。

1. main.dart の初期化処理を疑う

runApp() に到達しているかを確認するため、一番最初に print を仕込みます。

void main() {
  print('main() called'); // ← ここまで来ているか確認
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

本番ビルドでは print が出力されないため、代わりに debugPrint か Firebase Crashlytics の log を使います。

2. WidgetsFlutterBinding.ensureInitialized() 以降を疑う

Firebase や AdMob など非同期で初期化するものがある場合、例外が出ても画面が真っ白なまま止まることがあります。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  try {
    await Firebase.initializeApp();
  } catch (e) {
    // ここをデバッグ出力で確認
    debugPrint('Firebase init error: $e');
  }

  runApp(const MyApp());
}

3. Flavor / dart-define の値を確認する

const flavor = String.fromEnvironment('FLAVOR', defaultValue: 'unknown');
debugPrint('flavor: $flavor'); // 'unknown' が出たら渡されていない

unknown や空文字が出ていたら、ビルドコマンドに --dart-define が不足しています。

4. ルーティングの初期遷移を確認する

go_router などを使っている場合、初期ルートの解決でエラーが起きても画面が真っ白になることがあります。

GoRouter(
  initialLocation: '/',
  errorBuilder: (context, state) {
    return ErrorScreen(error: state.error);  // エラー画面を用意する
  },
  ...
)

修正

ビルドスクリプトに --dart-define を追加して解決しました。

# Makefile の例
build-prod:
	flutter build apk \
	  --flavor prod \
	  --dart-define=FLAVOR=prod \
	  --dart-define=API_BASE_URL=https://api.example.com

まとめ

チェック項目確認方法
main() まで到達しているかdebugPrint で確認
初期化処理で例外が出ていないかtry-catch でキャッチ
dart-define の値が正しく渡されているかString.fromEnvironment で確認
ルーティングの初期遷移でエラーが出ていないかerrorBuilder を設定

本番ビルドは --dart-define が渡されなくてもビルド自体は成功するため、見落としやすいです。Makefile や CI のビルドコマンドを定期的に確認することをおすすめします。