Flutter: Integração com Firebase
Firebase é o super assistente do Flutter — Auth, banco de dados, armazenamento, analytics, notificações push, tudo pronto para uso.
📋 Pré-requisitos: Você já deve estar familiarizado com
- Aula 11: Rede e API REST
- Aula 13: Armazenamento Local
1. O Que Você Vai Aprender
- Configuração de projeto Firebase: FlutterFire CLI + firebase_options.dart setup multi-plataforma
- Authentication: Email/Google/Apple Sign-In + login anônimo + verificação por telefone
- Cloud Firestore: modelagem de dados, escuta em tempo real com snapshots(), consultas compostas e regras de segurança
- Cloud Storage: upload/download de imagens de produtos + estratégia de cache
- Analytics + Cloud Messaging: rastreamento de comportamento do usuário + notificações push de marketing
2. Uma História Real de Colapso de Backend Próprio
(1) O Problema: Alto Custo Operacional de Backend Próprio
O backend próprio do ShopApp do Bob usa Node.js + PostgreSQL + S3, com uma equipe de ops de 3 pessoas e custo mensal de 20 mil USD. Uma migração de banco de dados causou 4 horas de inatividade, perdendo 50 mil USD em pedidos. A sincronização de inventário de produtos em tempo real exigia WebSocket, que era complexo e instável na infraestrutura própria. Notificações push usavam um serviço de terceiros com atrasos frequentes.
(2) A Solução com o Pacote Firebase
Firebase fornece Auth + Firestore + Storage + Analytics + FCM como backend completo — sem necessidade de ops de servidor, sincronização de dados em tempo real automática.
import 'package:cloud_firestore/cloud_firestore.dart';
// ⚙️ Install dependencies: flutter pub add cloud_firestore
// Custom class definition source:
// - Product: see Lesson 11 json_serializable model (add fromFirestore factory constructor)
// Firestore real-time product updates
FirebaseFirestore.instance
.collection('products')
.where('stock', isGreaterThan: 0)
.snapshots()
.listen((snapshot) {
// UI auto-updates when stock changes
products = snapshot.docs.map((d) => Product.fromFirestore(d)).toList();
});
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
(3) Benefício: Zero Ops + Sincronização em Tempo Real + Custos Reduzidos pela Metade
Após Bob migrar para Firebase, a equipe de ops do backend reduziu 2 pessoas, os custos mensais caíram de 20 mil USD para 8 mil USD, e a latência de dados em tempo real passou de segundos para milissegundos.
3. Visão Geral da Arquitetura do Firebase
graph TD
FB[Firebase] --> AUTH[Authentication]
FB --> FS[Cloud Firestore]
FB --> ST[Cloud Storage]
FB --> AN[Analytics]
FB --> CM[Cloud Messaging]
FS --> |snapshots| PL[ProductList Realtime]
AUTH --> |authStateChanges| LP[LoginPage]
CM --> |onMessage| NP[NotificationPopup]
AN --> |logEvent| DA[Dashboard Analytics]
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
(1) Matriz de Serviços do Firebase
| Serviço | Uso | Preço |
|---|---|---|
| Authentication | Autenticação de usuários | Tier gratuito generoso |
| Cloud Firestore | Banco de dados NoSQL em tempo real | Gratuito: 50K leituras/dia |
| Cloud Storage | Armazenamento de arquivos | Gratuito: 5GB |
| Analytics | Analytics de comportamento do usuário | Gratuito |
| Cloud Messaging | Notificações push | Gratuito |
| Crashlytics | Relatórios de crash | Gratuito |
4. Configuração do Projeto Firebase
▶ Exemplo
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
: Inicialização com FlutterFire
# Install FlutterFire CLI
dart pub global activate flutterfire_cli
# Configure Firebase project
flutterfire configure
# Add dependencies
flutter pub add firebase_core firebase_auth cloud_firestore firebase_storage firebase_analytics firebase_messaging
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
// ⚙️ Install dependencies: flutter pub add firebase_core
// ⚙️ Project configuration: dart pub global activate flutterfire_cli && flutterfire configure
// lib/main.dart
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(const ShopApp());
}
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
5. Authentication
(1) Comparação de Métodos de Sign-In
| Método | Complexidade | Experiência do Usuário | Caso de Uso |
|---|---|---|---|
| Email/Password | Baixa | Média | Uso geral |
| Google Sign-In | Média | Alta | Preferido no Android |
| Apple Sign-In | Média | Alta | Obrigatório no iOS |
| Login Anônimo | Baixa | Alta (sem atrito) | Testar antes de registrar |
| Verificação por Telefone | Alta | Média | Verificação de identidade |
▶ Exemplo
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
: Wrapper AuthService
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
// ⚙️ Install dependencies: flutter pub add firebase_auth google_sign_in
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
Stream<User?> get authStateChanges => _auth.authStateChanges();
Future<UserCredential> signInWithEmail(String email, String password) =>
_auth.signInWithEmailAndPassword(email: email, password: password);
Future<UserCredential> signUpWithEmail(String email, String password) =>
_auth.createUserWithEmailAndPassword(email: email, password: password);
Future<UserCredential> signInWithGoogle() async {
final googleUser = await GoogleSignIn().signIn();
final googleAuth = await googleUser?.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
return _auth.signInWithCredential(credential);
}
Future<UserCredential> signInAnonymously() => _auth.signInAnonymously();
Future<void> signOut() => _auth.signOut();
User? get currentUser => _auth.currentUser;
}
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
▶ Exemplo
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
: Riverpod Auth Notifier + Firebase
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
// ⚙️ Install dependencies: flutter pub add firebase_auth flutter_riverpod riverpod_annotation
// ⚙️ Dev dependencies: flutter pub add --dev riverpod_generator build_runner
// Custom class definition source:
// - AuthService: see Section 5 AuthService wrapper in this lesson
@riverpod
class FirebaseAuth extends _$FirebaseAuth {
@override
AsyncValue<User?> build() {
final service = AuthService();
// Listen to auth state changes
service.authStateChanges.listen((user) {
state = AsyncData(user);
});
return AsyncData(service.currentUser);
}
Future<void> login(String email, String password) async {
state = const AsyncLoading();
state = await AsyncValue.guard(() => AuthService().signInWithEmail(email, password));
}
Future<void> loginWithGoogle() async {
state = const AsyncLoading();
state = await AsyncValue.guard(() => AuthService().signInWithGoogle());
}
Future<void> logout() async {
await AuthService().signOut();
}
}
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
6. Cloud Firestore
(1) Modelagem de Dados
firestore/
├── products/{productId}
│ ├── name: "Pro Laptop"
│ ├── price: 1299.99
│ ├── stock: 150
│ ├── category: "Electronics"
│ └── imageUrl: "gs://shopapp.appspot.com/products/laptop.jpg"
├── users/{userId}
│ ├── name: "Bob"
│ ├── email: "alice@shopapp.com"
│ ├── addresses: [{...}]
│ └── preferences: {theme: "dark", currency: "USD"}
├── orders/{orderId}
│ ├── userId: "alice_123"
│ ├── items: [{productId, quantity, price}]
│ ├── total: 99.99
│ ├── status: "shipped"
│ └── createdAt: Timestamp
└── reviews/{reviewId}
├── productId: "laptop_001"
├── userId: "bob_456"
├── rating: 4.5
└── comment: "Great product!"
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
▶ Exemplo
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
: Firestore CRUD
import 'package:cloud_firestore/cloud_firestore.dart';
// ⚙️ Install dependencies: flutter pub add cloud_firestore
// Custom class definition source:
// - Product: see Lesson 11 json_serializable model (add fromFirestore factory constructor)
class ProductFirestore {
final _db = FirebaseFirestore.instance;
Future<List<Product>> getProducts({String? category, int limit = 20}) async {
Query query = _db.collection('products').orderBy('rating', descending: true).limit(limit);
if (category != null) query = query.where('category', isEqualTo: category);
final snapshot = await query.get();
return snapshot.docs.map((d) => Product.fromFirestore(d)).toList();
}
Future<Product> getProduct(String id) async {
final doc = await _db.collection('products').doc(id).get();
return Product.fromFirestore(doc);
}
// Real-time listener
Stream<List<Product>> watchProducts({String? category}) {
Query query = _db.collection('products').where('stock', isGreaterThan: 0);
if (category != null) query = query.where('category', isEqualTo: category);
return query.snapshots().map((s) => s.docs.map((d) => Product.fromFirestore(d)).toList());
}
Future<void> updateStock(String productId, int newStock) =>
_db.collection('products').doc(productId).update({'stock': newStock});
}
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
▶ Exemplo
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
: Regras de segurança do Firestore
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Products: anyone can read, only admins can write
match /products/{productId} {
allow read: if true;
allow write: if isAdmin();
}
// Orders: users can read/write own orders
match /orders/{orderId} {
allow read, write: if request.auth != null && request.auth.uid == resource.data.userId;
allow create: if request.auth != null;
}
// Reviews: anyone can read, authenticated users can create
match /reviews/{reviewId} {
allow read: if true;
allow create: if request.auth != null;
}
}
}
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
7. Cloud Storage
▶ Exemplo
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
: Upload e download de imagem de produto
import 'package:firebase_storage/firebase_storage.dart';
import 'dart:io';
// ⚙️ Install dependencies: flutter pub add firebase_storage
class StorageService {
final _storage = FirebaseStorage.instance;
Future<String> uploadProductImage(String filePath, String productId) async {
final ref = _storage.ref().child('products/$productId/${DateTime.now().millisecondsSinceEpoch}.jpg');
final uploadTask = ref.putFile(File(filePath));
final snapshot = await uploadTask;
return await snapshot.ref.getDownloadURL();
}
Future<String> getDownloadUrl(String path) =>
_storage.ref().child(path).getDownloadURL();
// Upload with progress
Stream<double> uploadWithProgress(String filePath, String productId) {
final ref = _storage.ref().child('products/$productId/main.jpg');
return ref.putFile(File(filePath)).snapshotEvents.map((s) {
return s.bytesTransferred / s.totalBytes;
});
}
}
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
8. Analytics + Cloud Messaging
▶ Exemplo
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
: Rastreamento de eventos do Analytics
import 'package:firebase_analytics/firebase_analytics.dart';
// ⚙️ Install dependencies: flutter pub add firebase_analytics
// Custom class definition source:
// - Product: see Lesson 11 json_serializable model
// - Order: see Lesson 14 Order model
class ShopAnalytics {
static final _analytics = FirebaseAnalytics.instance;
static Future<void> logViewProduct(Product product) =>
_analytics.logEvent(name: 'view_product', parameters: {
'product_id': product.id,
'product_name': product.name,
'price': product.price,
'category': product.category,
});
static Future<void> logAddToCart(Product product, int quantity) =>
_analytics.logEvent(name: 'add_to_cart', parameters: {
'product_id': product.id,
'quantity': quantity,
'price': product.price,
'currency': 'USD',
});
static Future<void> logPurchase(Order order) =>
_analytics.logEvent(name: 'purchase', parameters: {
'order_id': order.id,
'value': order.total,
'currency': 'USD',
'item_count': order.items.length,
});
static Future<void> setUserProperty(String name, String value) =>
_analytics.setUserProperty(name: name, value: value);
}
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
▶ Exemplo
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
: Notificações push com FCM
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
// ⚙️ Install dependencies: flutter pub add firebase_messaging
class NotificationService {
static final _messaging = FirebaseMessaging.instance;
static Future<void> init() async {
// Request permission
await _messaging.requestPermission();
// Get FCM token
final token = await _messaging.getToken();
debugPrint('FCM Token: $token');
// Foreground messages
FirebaseMessaging.onMessage.listen((message) {
debugPrint('Foreground message: ${message.notification?.title}');
});
// Background messages
FirebaseMessaging.onMessageOpenedApp.listen((message) {
// Handle notification tap
final productId = message.data['product_id'];
if (productId != null) {
// Navigate to product detail
}
});
}
}
> Saída: Execute localmente com o Flutter SDK (Flutter 3.x / Dart 3.x). O servidor Piston não possui o Flutter instalado; use `flutter run` na sua máquina local para comparação. A UI/estado real pode variar ligeiramente entre plataformas.
❓ Perguntas Frequentes
P: O tier gratuito do Firebase é suficiente? R: O Firestore oferece 50K leituras/20K escritas/dia gratuitamente — suficiente para apps de pequena escala. DAUs na casa dos milhões exigem um plano pago.
P: Firestore ou Realtime Database? R: Use Firestore para novos projetos (consultas mais poderosas, modelo de dados melhor). Realtime Database é apenas para cenários que exigem latência em tempo real extremamente baixa.
P: Como integrar tokens do Firebase Auth com uma API de backend? R: Obtenha um JWT com
await user.getIdToken()e envie-o ao backend para verificação. O backend usa o Firebase Admin SDK para verificar o token.
P: As consultas do Firestore têm limites de índice? R: Consultas compostas exigem índices compostos. A primeira execução falhará com um erro contendo um link para criar o índice.
P: O push do FCM funciona na China continental? R: Não. A China continental exige integração de push específico de fabricante (Huawei/Xiaomi/OPPO/VIVO) ou serviços de terceiros como JPush.
P: Como depurar regras de segurança do Firestore? R: O Rules Playground do Firebase Console pode simular requisições de leitura/escrita para testar regras. Sempre defina regras estritas em produção.
📖 Resumo
- Firebase é um backend completo: Auth + Firestore + Storage + Analytics + FCM
- FlutterFire CLI gera automaticamente configuração multi-plataforma
- Auth suporta múltiplos métodos de sign-in, authStateChanges para monitoramento em tempo real do estado de login
- Firestore snapshots() habilita sincronização de dados em tempo real, regras de segurança protegem os dados
- Analytics rastreia comportamento do usuário, FCM entrega notificações push
📝 Exercícios
- Básico (dificuldade ⭐): Configure um projeto Firebase, implemente registro e login com Email/Password, e monitore authStateChanges para exibir o status do usuário.
- Intermediário (dificuldade ⭐⭐): Implemente CRUD de produtos com Firestore + escuta em tempo real, com a UI atualizando automaticamente quando o estoque muda.
- Desafio (dificuldade ⭐⭐⭐): Implemente integração completa com Firebase: Google Sign-In + produtos em tempo real com Firestore + upload de imagem no Storage (com progresso) + rastreamento de eventos com Analytics + notificações push com FCM.