Питання про Firebase на співбесідах 2026: Flutter Auth, Firestore і правила безпеки
Питання про Firebase для Flutter-розробників із відповідями на Dart: потоки стану auth, Google Sign-In v7, CRUD і моделювання у Firestore, правила безпеки, custom claims, транзакції та зміни у FlutterFire 5.

Питання про Firebase на співбесідах на Flutter-позиції обертаються навколо п'яти тем: трьох потоків стану автентифікації, моделювання даних у Firestore, правил безпеки, офлайн-записів і моделі вартості, що стоїть за кожним читанням. Firebase у 2026 році залишається типовим бекендом для Flutter-додатків, а з жовтня 2026 плагіни FlutterFire виходять як BoM 5.x (firebase_core 5.1.0, firebase_auth 7.0.1, cloud_firestore 7.1.0), з підвищеним до 24 minSdk на Android і Firebase Apple SDK 13 під капотом.
Актуальний реліз FlutterFire: BoM 5.1.0, тобто firebase_auth 7.0.1, cloud_firestore 7.1.0, firebase_core 5.1.0. Мажорна версія 5.0.0 вимагає на Android minSdk 24, базується на Firebase Apple SDK 13.0.0 і перейменовує параметри activate в App Check. Firestore Pipelines, додані в cloud_firestore 6.3.0, отримують нові вирази з кожним релізом.
Питання про Firebase на співбесідах: що запитують у 2026
Інтерв'юери рідко питають про дрібниці API. Вони перевіряють, чи розуміє кандидат, де Firebase застосовує правила, скільки коштує кожна операція і що відбувається, коли зникає мережа. Таблиця нижче зіставляє типові теми з тим, що має містити сильна відповідь. Кожну з них детально розібрано нижче, у розділі питань про Firebase для Flutter-розробників.
| Тема | Типове питання | Що містить сильна відповідь |
|---|---|---|
| Потоки auth | authStateChanges() vs idTokenChanges() vs userChanges() | Які події емітує кожен із них і який захищає навігацію |
| Безпека | Де застосовується контроль доступу? | У правилах безпеки на сервері, ніколи не в перевірках на клієнті; App Check є окремим шаром |
| Ролі | Як реалізувати роль адміністратора? | Custom claims, встановлені через Admin SDK і прочитані через request.auth.token |
| Моделювання даних | Змоделюйте чат-додаток | Підколекції, денормалізоване останнє повідомлення, один документ на повідомлення |
| Узгодженість | Транзакція чи пакетний запис? | Транзакція читає, потім записує і повторює спробу; batch лише записує, атомарно |
| Офлайн | Що відбувається із записом в офлайні? | Локальний кеш, hasPendingWrites, синхронізація після відновлення з'єднання |
| Вартість | Чому цей екран дорогий? | Оплата за кожен прочитаний документ, слухачі, пагінація курсорами |
| Порівняння | Firestore vs Realtime Database | Модель запитів, масштабування, одиниця тарифікації |
Налаштування Firebase в проекті Flutter
Перед написанням будь-якого коду Firebase проект потребує коректної ініціалізації. FlutterFire CLI автоматизує реєстрацію платформи та генерує конфігураційні файли для Android, iOS, web та macOS.
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize Firebase with platform-specific config
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}Файл firebase_options.dart генерується автоматично після запуску flutterfire configure. Він містить API-ключі, ідентифікатори проекту та специфічні для платформи ідентифікатори, тож нічого не доводиться копіювати з консолі Firebase вручну.
Автентифікація Firebase: Email, Google та багатофакторна автентифікація
Firebase Authentication керує ідентифікацією користувачів з мінімальним шаблонним кодом. Пакет firebase_auth підтримує email/пароль, провайдерів OAuth (Google, Apple, GitHub), телефонну верифікацію через SMS та багатофакторну автентифікацію (MFA), зокрема TOTP на macOS починаючи з firebase_auth 6.1.0.
Реєстрація за допомогою email та пароля
Найпоширеніший потік починається з email/пароль. Метод createUserWithEmailAndPassword повертає об'єкт UserCredential, що містить автентифікований об'єкт User.
import 'package:firebase_auth/firebase_auth.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// Register with email and password
Future<User?> register(String email, String password) async {
try {
final credential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
return credential.user;
} on FirebaseAuthException catch (e) {
// Handle specific error codes
switch (e.code) {
case 'email-already-in-use':
throw Exception('This email is already registered');
case 'weak-password':
throw Exception('Password must be at least 6 characters');
default:
throw Exception('Registration failed: ${e.message}');
}
}
}
// Sign in with existing credentials
Future<User?> signIn(String email, String password) async {
final credential = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
return credential.user;
}
// Reactive auth state stream
Stream<User?> get authStateChanges => _auth.authStateChanges();
}Потік authStateChanges() є рекомендованим способом відстежувати стан авторизації в усьому додатку. Він емітує поточного користувача User при підписці та спрацьовує знову при кожному вході або виході.
Правила для паролів більше не мусять жити лише на клієнті: API validatePassword (доступний з firebase_auth 6.0.0) перевіряє пароль на відповідність політиці, налаштованій у консолі Firebase. Політика може вимагати мінімальної довжини, великих і малих літер, цифр і спеціальних символів.
Інтеграція входу через Google
Провайдери OAuth потребують додаткового пакета. Починаючи з google_sign_in 7.0, плагін є синглтоном, який отримують через GoogleSignIn.instance, його потрібно ініціалізувати рівно один раз, а автентифікацію відокремлено від авторизації. Виклик GoogleSignIn().signIn() зі старіших туторіалів більше не компілюється.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
// Call once at startup, before any other GoogleSignIn method
Future<void> initGoogleSignIn() => GoogleSignIn.instance.initialize();
Future<UserCredential> signInWithGoogle() async {
try {
// Shows the native account picker; throws if the user cancels
final googleUser = await GoogleSignIn.instance.authenticate();
// Synchronous getter since v7: only the ID token is exposed here
final googleAuth = googleUser.authentication;
// Firebase only needs the ID token to create the credential
final credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
);
return FirebaseAuth.instance.signInWithCredential(credential);
} on GoogleSignInException catch (e) {
if (e.code == GoogleSignInExceptionCode.canceled) {
throw Exception('Sign-in cancelled');
}
rethrow;
}
}Цей патерн застосовується до всіх провайдерів OAuth: отримати токен провайдера, загорнути його в credential Firebase, а потім викликати signInWithCredential. Якщо додатку також потрібно викликати Google API (Drive, Calendar), токен доступу тепер отримують окремим кроком, authorizationClient.authorizeScopes, як описано в посібнику з міграції google_sign_in.
Кандидат, який пише GoogleSignIn().signIn() і читає accessToken з authentication, цитує API до версії 7.0. У v7 authenticate() повертає обліковий запис, authentication містить лише idToken, а токени доступу для додаткових scopes вимагають явного виклику авторизації.
CRUD-операції у Firestore та моделювання даних
Cloud Firestore організовує дані в колекції та документи. На відміну від SQL-баз даних, Firestore не має схеми: кожен документ може містити різні поля. Ця гнучкість добре підходить для додатків Flutter, але вимагає дисциплінованого моделювання даних для уникнення проблем з продуктивністю.
Запис та читання документів
Операції Firestore є простими з пакетом cloud_firestore. Кожне читання та запис спрямоване на конкретний шлях документа.
import 'package:cloud_firestore/cloud_firestore.dart';
class TaskService {
final _db = FirebaseFirestore.instance;
final String _collection = 'tasks';
// Create a new document with auto-generated ID
Future<String> createTask(String userId, String title) async {
final doc = await _db.collection(_collection).add({
'userId': userId,
'title': title,
'completed': false,
'createdAt': FieldValue.serverTimestamp(),
});
return doc.id;
}
// Read a single document by ID
Future<Map<String, dynamic>?> getTask(String taskId) async {
final snapshot = await _db.collection(_collection).doc(taskId).get();
return snapshot.data();
}
// Update specific fields without overwriting the entire document
Future<void> toggleComplete(String taskId, bool completed) async {
await _db.collection(_collection).doc(taskId).update({
'completed': completed,
'updatedAt': FieldValue.serverTimestamp(),
});
}
// Delete a document
Future<void> deleteTask(String taskId) async {
await _db.collection(_collection).doc(taskId).delete();
}
}FieldValue.serverTimestamp() забезпечує послідовні мітки часу на всіх пристроях, використовуючи годинник сервера Firestore замість годинника клієнта. Починаючи з cloud_firestore 7.1.0, до серверних трансформацій додалися FieldValue.minimum і FieldValue.maximum: вони зберігають менше або більше зі збереженого та вхідного значень без читання, що підходить для лічильників на кшталт найкращого результату.
Потоки реального часу з snapshots()
Firestore відзначається синхронізацією в реальному часі. Метод snapshots() повертає Stream, що емітує нові дані щоразу, коли базові документи змінюються, без необхідності опитування.
import 'package:cloud_firestore/cloud_firestore.dart';
class TaskStream {
final _db = FirebaseFirestore.instance;
// Stream all tasks for a specific user, ordered by creation date
Stream<List<Map<String, dynamic>>> userTasks(String userId) {
return _db
.collection('tasks')
.where('userId', isEqualTo: userId)
.orderBy('createdAt', descending: true)
.snapshots()
.map((snapshot) => snapshot.docs.map((doc) {
final data = doc.data();
data['id'] = doc.id; // Include document ID
return data;
}).toList());
}
}У віджеті Flutter цей потік інтегрується безпосередньо зі StreamBuilder для перебудови інтерфейсу при кожній зміні в базі даних. Firestore автоматично керує з'єднаннями, кешуванням та офлайн-зберіганням.
Готовий до співбесід з Flutter?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Правила безпеки Firestore для додатків Flutter
Правила безпеки працюють на сервері Firestore та контролюють доступ до читання/запису на рівні документа. Без належних правил будь-який автентифікований користувач міг би прочитати або змінити будь-який документ.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Users can only access their own profile
match /users/{userId} {
allow read, update: if request.auth != null
&& request.auth.uid == userId;
allow create: if request.auth != null;
allow delete: if false; // Prevent self-deletion
}
// Tasks belong to the user who created them
match /tasks/{taskId} {
allow read, write: if request.auth != null
&& resource.data.userId == request.auth.uid;
allow create: if request.auth != null
&& request.resource.data.userId == request.auth.uid;
}
}
}Змінна request.auth.uid містить ідентифікатор автентифікованого користувача з Firebase Auth. Правила, що посилаються на resource.data, перевіряють існуючі поля документа, а request.resource.data валідує вхідні дані запису.
Firestore за замовчуванням відхиляє весь доступ у виробничому режимі. Кожна колекція потребує явних правил. Поширена помилка в проектах Flutter: розробка з правилами тестового режиму (allow read, write: if true) та забуття про захист перед виробничим розгортанням.
Офлайн-зберігання та стратегія кешування
Firestore за замовчуванням вмикає офлайн-зберігання на мобільних платформах. Коли пристрій втрачає з'єднання, операції читання повертають дані з кешу, а операції запису ставляться в локальну чергу до відновлення з'єднання.
Ця поведінка не потребує додаткового коду у Flutter: ті самі виклики get() та snapshots() працюють офлайн. Проте для виробничих додатків важливі два аспекти:
- Розмір кешу: Firestore кешує всі документи, які клієнт прочитав. Для додатків з великим обсягом даних варто налаштувати
Settings(cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED)або встановити конкретний ліміт. - Індикатор очікуваних записів:
SnapshotMetadata.hasPendingWritesдозволяє показати користувачам, коли локальні зміни ще не синхронізовані з сервером.
StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance
.collection('tasks')
.doc(taskId)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const CircularProgressIndicator();
final data = snapshot.data!;
final isPending = data.metadata.hasPendingWrites;
return Row(
children: [
Text(data['title']),
if (isPending) const Icon(Icons.cloud_upload, size: 16),
],
);
},
)Архітектура виробничого додатку Flutter з Firebase
Масштабована архітектура відокремлює логіку Firebase від коду інтерфейсу. Патерн репозиторію забезпечує чисту абстракційну верстку, що спрощує тестування та майбутні міграції бекенду.
abstract class TaskRepository {
Future<String> create(String userId, String title);
Stream<List<Task>> watchAll(String userId);
Future<void> update(String id, Map<String, dynamic> fields);
Future<void> delete(String id);
}
// firebase_task_repository.dart
class FirebaseTaskRepository implements TaskRepository {
final _db = FirebaseFirestore.instance;
Future<String> create(String userId, String title) async {
final doc = await _db.collection('tasks').add({
'userId': userId,
'title': title,
'completed': false,
'createdAt': FieldValue.serverTimestamp(),
});
return doc.id;
}
Stream<List<Task>> watchAll(String userId) {
return _db
.collection('tasks')
.where('userId', isEqualTo: userId)
.orderBy('createdAt', descending: true)
.snapshots()
.map((s) => s.docs.map(Task.fromFirestore).toList());
}
// ... update and delete implementations
}З цим патерном рішення для керування станом, такі як Riverpod або BLoC, споживають інтерфейс репозиторію без відомості про Firestore. Модульні тести можуть підставити мок репозиторію, що повертає заздалегідь визначені дані.
Перехід на FlutterFire 5: що ламається
Мажорний реліз жовтня 2026 (BoM 5.0.0, firebase_auth 7.0.0, cloud_firestore 7.0.0, firebase_core 5.0.0) змінює радше вимоги до збірки, ніж Dart API. Пункти, на яких падає збірка або код-рев'ю:
- Android
minSdk24: плагіни базуються на Firebase Android BoM 35. Проект, що досі наminSdk21 або 23, перестає компілюватися. - Apple SDK 13: Firebase Apple SDK переходить на 13.0.0 зі Swift Package Manager (12.19.0 з CocoaPods), а Swift-пакети вимагають macOS 11.
- App Check: параметри
activateперейменовано наproviderWeb,providerAndroidіproviderApple. - Застарілі API:
setIndexConfigurationFromJSONпозначено як deprecated уcloud_firestore7.0.0, аfirebase_ml_model_downloaderбільше не публікується. - Уже видалені в лінійці 6.x:
fetchSignInMethodsForEmail()іUser.updateEmail(). Код, який перед входом перевіряє, яким провайдером користується email, доведеться переробити, оскільки захист від перебору email-адрес приховує цю інформацію.
Повний перелік змін для кожного пакета наведено в примітках до релізів FlutterFire і в changelog cloud_firestore.
Питання про Firebase на співбесідах для Flutter-розробників
Співбесіди часто перевіряють як концептуальне розуміння, так і практичну реалізацію сервісів Firebase. Наступні питання регулярно з'являються на співбесідах з розробниками Flutter у 2026 році. Сам фреймворк охоплює ширший посібник із питань на співбесідах з Flutter.
Чим authStateChanges() відрізняється від idTokenChanges() та userChanges()?
authStateChanges() спрацьовує лише при подіях входу та виходу. idTokenChanges() також спрацьовує при оновленні токена ідентифікації (приблизно кожних 60 хвилин). userChanges() охоплює все вищевказане плюс оновлення профілю, такі як updateDisplayName(). Для більшості навігаційних захистів достатньо authStateChanges().
Що відбувається, коли запис у Firestore здійснюється, коли пристрій в офлайні?
Запис зберігається в локальному кеші та черзі очікуваних записів. Лістенери snapshots() негайно отримують оновлені дані з metadata.hasPendingWrites == true. Коли з'єднання відновлюється, Firestore автоматично синхронізує очікувані записи, і перемагає той запис, який останнім дійшов до сервера.
Як слід моделювати дані Firestore для додатку чату?
Поширений підхід: колекція chats, де кожен документ містить метадані (учасники, мітка часу останнього повідомлення), та підколекція messages під кожним документом чату. Ця структура дозволяє ефективно запитувати список чатів користувача, одночасно сторінкуючи повідомлення в кожній розмові. Денормалізація останнього повідомлення в батьківський документ дозволяє уникнути читання підколекції при відображенні списку.
Чому FieldValue.serverTimestamp() переважніший над DateTime.now()?
DateTime.now() використовує годинник пристрою, який може бути неточним або зманіпульованим. FieldValue.serverTimestamp() використовує годинник сервера Firestore, гарантуючи послідовне сортування на всіх клієнтах. Це важливо для таких функцій, як порядок повідомлень, стрічки активності та журнали аудиту.
Як обробляються складені запити у Firestore та які вимоги до індексів?
Firestore вимагає складеного індексу для запитів, що поєднують кілька полів з клаузулами where та orderBy. Однопольні індекси створюються автоматично, але складені індекси треба визначити вручну у файлі firestore.indexes.json або через консоль Firebase. Коли запит завершується невдачею, Firestore логує пряме посилання для створення відсутнього індексу.
Коли використовувати транзакцію замість пакетного запису?
Транзакція потрібна, коли запис залежить від даних, прочитаних у тій самій операції, наприклад зменшення залишку на складі лише тоді, коли він більший за нуль. SDK повторно виконує callback, якщо прочитаний документ змінився до коміту, тому callback не повинен мати побічних ефектів. Пакетний запис (batch) виконує кілька записів атомарно без жодного читання, наприклад створення документа й оновлення лічильника в іншому місці. Офлайн вони поводяться по-різному: batch стає в чергу, транзакція без з'єднання завершується помилкою.
final db = FirebaseFirestore.instance;
// Transaction: read then write, retried on contention
await db.runTransaction((tx) async {
final ref = db.collection('products').doc(id);
final snap = await tx.get(ref);
final stock = snap.get('stock') as int;
if (stock <= 0) throw Exception('Out of stock');
tx.update(ref, {'stock': stock - 1});
});
// Batched write: atomic writes, no reads
final batch = db.batch();
batch.set(db.collection('orders').doc(), {'productId': id});
batch.update(db.collection('stats').doc('orders'), {
'count': FieldValue.increment(1),
});
await batch.commit();Як реалізувати роль адміністратора у Firebase?
Через custom claims, які встановлюються з довіреного середовища за допомогою Admin SDK, ніколи з Flutter-клієнта. Claim передається всередині ID-токена, тож правила читають його як request.auth.token.admin == true без додаткового читання документа. Документація з custom claims обмежує обсяг даних 1000 байтами, а клієнт бачить новий claim лише після оновлення токена, яке примусово викликає currentUser.getIdToken(true).
Чим правила безпеки відрізняються від App Check?
Правила безпеки вирішують, чи може конкретний користувач читати або записувати конкретний документ. App Check засвідчує, що запит надходить зі справжнього додатку на справжньому пристрої, і блокує скрипти, які повторно використовують публічний API-ключ. Вони відповідають на різні питання, тому продакшн-додатку потрібні обидва механізми. Починаючи з FlutterFire 5, App Check активується параметрами providerAndroid, providerApple і providerWeb.
Чому екран на Firestore може стати дорогим і як робиться пагінація?
Firestore тарифікує кожне читання, запис і видалення документа. Слухач на необмеженій колекції під час першого завантаження читає кожен відповідний документ, а далі виконує по одному читанню на кожен змінений документ. Пагінація використовує курсори запитів замість зсувів: limit(20) для першої сторінки, потім startAfterDocument(lastDoc) для наступної, тож кожна сторінка коштує лише ті документи, які повертає.
Firestore чи Realtime Database: що обрати і чому?
Firestore зберігає документи в колекціях, підтримує складені запити з індексами і тарифікує за операції. Realtime Database зберігає одне JSON-дерево, пропонує неглибокі запити за одним дочірнім ключем і тарифікує переважно за трафік і сховище, що підходить для дрібних, дуже частих оновлень, як-от індикатори присутності. Більшість нових Flutter-додатків починає з Firestore і додає Realtime Database лише для присутності.
Більше матеріалів для підготовки до співбесід з Flutter та Firebase доступно в інтерактивних модулях, які охоплюють ці теми у форматі квізів і завдань на час.
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Джерела
- Примітки до релізів Firebase для Flutter: склад BoM 5.0.0 і 5.1.0, minSdk 24, перейменування параметрів App Check
- Changelog cloud_firestore: Pipelines у 6.3.0,
FieldValue.minimum/maximumі відстань уfindNearestу 7.1.0 - Changelog firebase_auth:
validatePasswordу 6.0.0, TOTP на macOS у 6.1.0, видаленийfetchSignInMethodsForEmail - Посібник з міграції google_sign_in: синглтон,
initialize,authenticate, окрема авторизація у 7.0 - Custom claims у Firebase: ліміт 1000 байтів і оновлення токена
Головне про Flutter і Firebase для співбесіди
- FlutterFire BoM 5.1.0 містить
firebase_auth7.0.1 іcloud_firestore7.1.0 та вимагає на AndroidminSdk24 google_sign_in7 замінюєGoogleSignIn().signIn()наGoogleSignIn.instance.initialize(), а потімauthenticate(), і Firebase потрібен лишеidTokenauthStateChanges()надає реактивний потік для керування станом входу в усьому додатку без ручних перевірок- Синхронізація в реальному часі через
snapshots()усуває опитування і працює безпосередньо зіStreamBuilderдля автоматичного оновлення інтерфейсу - Правила безпеки обов'язкові в продакшні:
request.auth.uidзавжди слід звіряти з полями власника документа, а ролі реалізовувати через custom claims - Транзакція читає, потім записує з повторними спробами, пакетний запис лише записує; пагінація використовує курсори, бо кожне читання документа оплачується
- Офлайн-зберігання працює на мобільних платформах без додаткового коду;
hasPendingWritesдозволяє показати користувачам стан синхронізації - Патерн репозиторію відокремлює Firebase від бізнес-логіки, що спрощує тестування і майбутні міграції
Чи знайдеш ти помилку в Flutter?
Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Автор:
Anthony Fillion-MailletЗасновник SharpSkill
Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.
Оновлено 9 листопада 2026 р.
Теги
Поділитися
Пов'язані статті

Управління станом у Flutter: Riverpod vs BLoC - Повний порівняльний посібник
Детальне порівняння Riverpod 3.x і BLoC 9.x для управління станом у Flutter. Архітектура, автоматичне повторення, тестованість і випадки використання для вибору найкращого рішення.

Топ-20 Питань на Співбесіді з Flutter для Мобільних Розробників
Підготовка до співбесіди з Flutter: 20 найпоширеніших питань. Віджети, управління станом, Dart, архітектура та найкращі практики з детальними поясненнями та прикладами коду.

Флаттер: створення першого кросплатформного застосунку
Повний посібник зі створення мобільного кросплатформного застосунку з Flutter та Dart. Віджети, керування станом, навігація та кращі практики для початківців.