Irbisa · Шпаргалка
Firebase и бэкенд-сервисы
FlutterFire, Auth, Firestore, FCM, Remote Config, Crashlytics, App Check, Supabase
Как подключить Firebase к Flutter-приложению и что
main()должен дождаться доrunApp?// Once per machine: dart pub global activate flutterfire_cli// Once per project: flutterfire configureimport 'package:firebase_core/firebase_core.dart';import 'firebase_options.dart'; Future<void> main() async {…Как читать и писать данные Firestore во Flutter и чем
get()отличается отsnapshots()?final notes = FirebaseFirestore.instance .collection('notes') .withConverter<Note>( fromFirestore: (snap, _) => Note.fromJson(snap.data()!), toFirestore: (note, _) => note.toJson(), );…Чем Cloud Firestore отличается от Realtime Database и когда выбирать каждую?
Как реализовать вход через Google с Firebase Auth и почему он часто работает в debug, но ломается в сборке из Play Store?
Future<void> initGoogle() => GoogleSignIn.instance.initialize(); Future<UserCredential?> signInWithGoogle() async { if (kIsWeb) { return FirebaseAuth.instance.signInWithPopup(GoogleAuthProvider()); }…На холодном старте приложение на кадр показывает экран логина, а потом прыгает на ленту. Что на самом деле делает
authStateChanges()?class AuthGate extends StatelessWidget { const AuthGate({super.key}); @override Widget build(BuildContext context) { return StreamBuilder<User?>(…Стейджинговая сборка пишет в продовый Firestore, хотя
firebase_options.dartвы подменили. Что всё ещё смотрит в прод?# One Firebase project per environment, one configure run per flavor.# repeat per build configuration (Release-staging, Profile-staging, ...)flutterfire configure --project=myapp-staging \ --out=lib/firebase/options_staging.dart \ --android-package-name=com.myapp.staging \ --android-out=android/app/src/staging/google-services.json \…Гость неделю играл, потом вошёл через Google, и всё сохранённое исчезло. Что сделал этот вход?
Future<void> startAsGuest() async { if (FirebaseAuth.instance.currentUser == null) { await FirebaseAuth.instance.signInAnonymously(); }}…Лента должна показывать три свежих комментария под каждым постом. Как это требование меняет вашу модель данных в Firestore?
Только что отправленное сообщение мгновенно появляется в списке, а через секунду прыгает на другую позицию. О чём говорят снапшоты?
В авиарежиме ваш
await docRef.set(...)не возвращается никогда, но новая строка уже на экране. Это баг?// wrong: offline this Future never completes and the spinner never stopsFuture<void> badSave(String text) async { setState(() => _saving = true); await db.collection('notes').add({'text': text}); setState(() => _saving = false);}…Два пользователя одновременно нажимают «Купить» на последнем товаре, и оба получают заказ. Что не так с этим кодом?
Future<void> buy(String itemId, String uid) async { final item = db.doc('items/$itemId'); final snap = await item.get(); final stock = snap.get('stock') as int; if (stock <= 0) throw const SoldOut(); await item.update({'stock': stock - 1}); await db.collection('orders').add({'itemId': itemId, 'uid': uid});}Этот запрос работает на эмуляторе, а в проде стрим падает с
failed-precondition. Почему и как исправить это раз и навсегда?Stream<List<Order>> openOrders(String uid) => db .collection('orders') .where('userId', isEqualTo: uid) .where('status', isEqualTo: 'open') .orderBy('createdAt', descending: true) .limit(20) .snapshots() .map((s) => s.docs.map(Order.fromDoc).toList());Как работают security rules в Firestore и почему их не заменить тем, что кнопка «Удалить» спрятана от не-авторов?
rules_version = '2';service cloud.firestore { match /databases/{database}/documents { match /notes/{noteId} { allow read, delete: if request.auth != null && resource.data.ownerId == request.auth.uid;…Пуши приходят, когда приложение закрыто, но ничего не появляется, пока пользователь держит его открытым. Как
firebase_messagingобрабатывает каждое состояние приложения?@pragma('vm:entry-point') // release builds tree-shake it otherwiseFuture<void> _onBackground(RemoteMessage message) async { // A separate isolate: no providers, no navigator, no app state. await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);}…Найдите баг: после нескольких переходов по экранам один пуш в foreground показывает один и тот же баннер два-три раза.
class _InboxScreenState extends State<InboxScreen> { int _unread = 0; @override void initState() { super.initState(); FirebaseMessaging.onMessage.listen((message) { showLocalBanner(message.notification?.title); setState(() => _unread++); }); } @override Widget build(BuildContext context) => Text('Unread: $_unread');}Crashlytics подключён, пользователи каждый день жалуются на вылеты, а дашборд пустой. Чего не хватает в обвязке?
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); final crashlytics = FirebaseCrashlytics.instance; await crashlytics.setCrashlyticsCollectionEnabled(!kDebugMode);…Что вы логируете в Firebase Analytics во Flutter-приложении и что туда попадать не должно никогда?
На слабой сети сплэш висит восемь секунд, потому что старт ждёт Remote Config. Как это должно быть устроено?
final rc = FirebaseRemoteConfig.instance; Future<void> bootstrapConfig() async { await rc.setConfigSettings(RemoteConfigSettings( fetchTimeout: const Duration(seconds: 8), // default 60 s minimumFetchInterval:…Callable-функция работает на эмуляторе, а в проде возвращает
internalбез сообщения. Что происходит?Счёт за Firestore за месяц вырос до пятизначного, а число пользователей не изменилось. Куда смотреть во Flutter-коде в первую очередь?
// wrong: a new stream on every rebuild re-attaches the listener@overrideWidget build(BuildContext context) => StreamBuilder<QuerySnapshot>( stream: db.collection('orders').where('userId', isEqualTo: uid).snapshots(), builder: _rows, );…Найдите баг в этом
OrdersRepository:watchMyOrders()должен следить за тем, кто вошёл в аккаунт прямо сейчас.class OrdersRepository { OrdersRepository(this._auth, this._db); final FirebaseAuth _auth; final FirebaseFirestore _db; // Orders of whoever is signed in right now. Stream<List<Order>> watchMyOrders() => _auth.authStateChanges().asyncExpand((user) { if (user == null) return Stream.value(const <Order>[]); return _db .collection('orders') .where('userId', isEqualTo: user.uid) .snapshots() .map((s) => s.docs.map(Order.fromDoc).toList()); });}Любой может вытащить API-ключ из APK и обратиться к Firestore напрямую. Что добавляет App Check и от чего он всё равно не защищает?
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); // Before the first Firestore, Storage or Functions call. await FirebaseAppCheck.instance.activate(…Как тестировать Flutter-приложение на Firebase так, чтобы ни один прогон не трогал прод и ни одному widget-тесту не нужна была сеть?
// 1. Widget tests: the seam is a repository, Firebase never loads.class FakeOrders implements OrderRepository { FakeOrders(this.orders); final List<Order> orders; @override Stream<List<Order>> watch(String uid) => Stream.value(orders);…Клиент спрашивает, строить на Firebase, на Supabase или на своём бэкенде. Как выбирать и как оставить себе путь к отступлению?