Рубрики
Flutter

Firebase во Flutter: Полное руководство 2025

Полное руководство по интеграции Firebase во Flutter: Authentication, Firestore, Cloud Functions, Push Notifications.

Firebase — это платформа от Google для разработки мобильных приложений. В этом руководстве разберём полную интеграцию Firebase во Flutter.

Установка

Настройка проекта

  1. Создайте проект в Firebase Console
  2. Добавьте приложения Android и iOS
  3. Скачайте конфигурационные файлы

Зависимости

dependencies:
  firebase_core: ^3.0.0
  firebase_auth: ^5.0.0
  cloud_firestore: ^5.0.0
  firebase_storage: ^12.0.0
  firebase_messaging: ^15.0.0
  firebase_analytics: ^11.0.0

Инициализация

import 'package:firebase_core/firebase_core.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

Authentication

Email/Password аутентификация

import 'package:firebase_auth/firebase_auth.dart';

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;

  // Регистрация
  Future<UserCredential?> register(
    String email,
    String password,
  ) async {
    try {
      return await _auth.createUserWithEmailAndPassword(
        email: email,
        password: password,
      );
    } catch (e) {
      print('Registration error: $e');
      return null;
    }
  }

  // Вход
  Future<UserCredential?> login(
    String email,
    String password,
  ) async {
    try {
      return await _auth.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
    } catch (e) {
      print('Login error: $e');
      return null;
    }
  }

  // Выход
  Future<void> logout() async {
    await _auth.signOut();
  }

  // Текущий пользователь
  User? get currentUser => _auth.currentUser;

  // Stream изменений аутентификации
  Stream<User?> get authStateChanges => _auth.authStateChanges();
}

Google Sign-In

dependencies:
  google_sign_in: ^6.2.0
class GoogleAuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final GoogleSignIn _googleSignIn = GoogleSignIn();

  Future<UserCredential?> signInWithGoogle() async {
    try {
      final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();

      if (googleUser == null) return null;

      final GoogleSignInAuthentication googleAuth =
          await googleUser.authentication;

      final credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );

      return await _auth.signInWithCredential(credential);
    } catch (e) {
      print('Google sign-in error: $e');
      return null;
    }
  }
}

Отслеживание состояния

class AuthWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        }

        if (snapshot.hasData) {
          return HomeScreen();
        }

        return LoginScreen();
      },
    );
  }
}

Cloud Firestore

Базовые операции

import 'package:cloud_firestore/cloud_firestore.dart';

class DatabaseService {
  final FirebaseFirestore _db = FirebaseFirestore.instance;

  // Создать документ
  Future<void> createUser(User user) async {
    await _db.collection('users').doc(user.id).set(user.toMap());
  }

  // Читать документ
  Future<User?> getUser(String userId) async {
    final doc = await _db.collection('users').doc(userId).get();

    if (doc.exists) {
      return User.fromMap(doc.data()!);
    }
    return null;
  }

  // Обновить документ
  Future<void> updateUser(User user) async {
    await _db.collection('users').doc(user.id).update(user.toMap());
  }

  // Удалить документ
  Future<void> deleteUser(String userId) async {
    await _db.collection('users').doc(userId).delete();
  }
}

StreamBuilder для real-time

class UserList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: FirebaseFirestore.instance
          .collection('users')
          .orderBy('createdAt', descending: true)
          .snapshots(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        }

        if (!snapshot.hasData) {
          return Center(child: Text('No users found'));
        }

        final users = snapshot.data!.docs;

        return ListView.builder(
          itemCount: users.length,
          itemBuilder: (context, index) {
            final user = User.fromMap(users[index].data() as Map<String, dynamic>);
            return ListTile(title: Text(user.name));
          },
        );
      },
    );
  }
}

Запросы

// Где
final snapshot = await _db
    .collection('users')
    .where('age', isGreaterThan: 18)
    .get();

// Сортировка
final snapshot = await _db
    .collection('users')
    .orderBy('createdAt', descending: true)
    .limit(10)
    .get();

// Сложные запросы
final snapshot = await _db
    .collection('products')
    .where('category', isEqualTo: 'electronics')
    .where('price', isLessThan: 1000)
    .orderBy('rating', descending: true)
    .get();

Транзакции

Future<void> transferMoney(
  String fromUserId,
  String toUserId,
  double amount,
) async {
  await _db.runTransaction((transaction) async {
    final fromDoc = await transaction.get(_db.collection('users').doc(fromUserId));
    final toDoc = await transaction.get(_db.collection('users').doc(toUserId));

    final fromBalance = fromDoc.data()!['balance'] as double;
    final toBalance = toDoc.data()!['balance'] as double;

    transaction.update(_db.collection('users').doc(fromUserId), {
      'balance': fromBalance - amount
    });

    transaction.update(_db.collection('users').doc(toUserId), {
      'balance': toBalance + amount
    });
  });
}

Firebase Storage

Загрузка файлов

import 'package:firebase_storage/firebase_storage.dart';

class StorageService {
  final FirebaseStorage _storage = FirebaseStorage.instance;

  // Загрузить файл
  Future<String?> uploadFile(
    String filePath,
    String fileName,
  ) async {
    try {
      final ref = _storage.ref().child('uploads/$fileName');
      await ref.putFile(File(filePath));

      final url = await ref.getDownloadURL();
      return url;
    } catch (e) {
      print('Upload error: $e');
      return null;
    }
  }

  // Удалить файл
  Future<void> deleteFile(String fileName) async {
    try {
      await _storage.ref().child('uploads/$fileName').delete();
    } catch (e) {
      print('Delete error: $e');
    }
  }
}

Загрузка изображений

Future<String?> uploadImage(File imageFile) async {
  final fileName = '${DateTime.now().millisecondsSinceEpoch}.jpg';
  final ref = _storage.ref().child('images/$fileName');

  final metadata = SettableMetadata(
    contentType: 'image/jpeg',
  );

  await ref.putFile(imageFile, metadata);
  return await ref.getDownloadURL();
}

Cloud Functions

Вызов функций

dependencies:
  cloud_functions: ^5.0.0
class FunctionsService {
  final FirebaseFunctions _functions = FirebaseFunctions.instance;

  Future<void> sendWelcomeEmail(String userId) async {
    try {
      final result = await _functions.httpsCallable('sendWelcomeEmail').call({
        'userId': userId,
      });

      print(result.data);
    } catch (e) {
      print('Function error: $e');
    }
  }
}

Push Notifications

Настройка

class NotificationService {
  final FirebaseMessaging _messaging = FirebaseMessaging.instance;

  Future<void> initialize() async {
    // Запрос разрешения
    NotificationSettings settings = await _messaging.requestPermission(
      alert: true,
      badge: true,
      sound: true,
    );

    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
      print('User granted permission');
    }

    // Получить токен
    final token = await _messaging.getToken();
    print('FCM Token: $token');

    // Слушать сообщения
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('Got message: ${message.notification?.body}');
    });

    // Сообщения в фоне
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('Opened app from message');
    });
  }
}

Обработка фоновых сообщений

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print('Background message: ${message.messageId}');
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  runApp(MyApp());
}

Analytics

class AnalyticsService {
  final FirebaseAnalytics _analytics = FirebaseAnalytics.instance;

  // Лог события
  Future<void> logEvent(String name, {Map<String, Object?>? parameters}) async {
    await _analytics.logEvent(
      name: name,
      parameters: parameters,
    );
  }

  // Лог просмотра страницы
  Future<void> logScreenView(String screenName) async {
    await _analytics.logScreenView(
      screenName: screenName,
      screenClass: screenName,
    );
  }

  // Лог покупки
  Future<void> logPurchase(String itemId, double price) async {
    await _analytics.logPurchase(
      transactionId: DateTime.now().millisecondsSinceEpoch.toString(),
      itemId: itemId,
      value: price,
    );
  }
}

Заключение

Firebase предоставляет полный бэкенд для Flutter приложений. Используйте его для быстрого прототипирования и production приложений.