FlutterのFirebaseサンプルコードにて。
https://codelabs.developers.google.com/codelabs/flutter-firebase/#3
症状
Firebaseのcloud_firestoreパッケージバージョンを、
dependencies:
flutter:
cloud_firestore: ^0.14.0+2 // ^0.13.0+1からアップデート
上記のようにアップデートすると、以下のエラーが発生しました。
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following FirebaseException was thrown building MyHomePage(dirty, state: _MyHomePageState#ef74c):
[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
対処法:初期化する
Firebase.initializeApp();
を追加。
Widget _buildBody(BuildContext context) {
Firebase.initializeApp(); // new
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('baby').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
警告の通りですね。
サンプルコードでは、以下の箇所も修正必要でした。
Record.fromSnapshot(DocumentSnapshot snapshot)
// : this.fromMap(snapshot.data, reference: snapshot.reference);
: this.fromMap(snapshot.data(), reference: snapshot.reference); // new
発展:初期化完了後に処理したい場合
こちらで説明されております。
https://firebase.flutter.dev/docs/overview/#initializing-flutterfire
以下はStatefulWidgetの場合。
_initialized
を使って初期化が完了しているかを確認します。
class MyAuthPage extends StatefulWidget {
@override
_MyAuthPageState createState() => _MyAuthPageState();
}
class _MyAuthPageState extends State<MyAuthPage> {
bool _initialized = false;
bool _error = false;
// Define an async function to initialize FlutterFire
void initializeFlutterFire() async {
try {
// Wait for Firebase to initialize and set `_initialized` state to true
await Firebase.initializeApp();
setState(() {
_initialized = true;
});
} catch (e) {
// Set `_error` state to true if Firebase initialization fails
setState(() {
_error = true;
});
}
}
@override
void initState() {
initializeFlutterFire();
super.initState();
}
(省略)
追記:main()の先頭で初期化しちゃう場合
main()
をFuture<void> main() async
にして対応します。
Future<void> main() async {
await Firebase.initializeApp();
runApp(MyApp());
}
ただし、これだけだと、以下のエラーが出ると思います。
If you're running an application and need to access the binary messenger before `runApp()` has been called (for example, during plugin initialization), then you need to explicitly call the `WidgetsFlutterBinding.ensureInitialized()` first.
要約すると、「runApp()
の前にプラグインの初期化を行う場合は、はじめに WidgetsFlutterBinding.ensureInitialized()
を実行する必要がある」とのこと。
WidgetsFlutterBinding.ensureInitialized()
は、最初に初期化することを保証することをFlutterに通知します。
最終的には、以下でOK。
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}