Top 10 Packages Avançados para Flutter
1. Riverpod
Muito mais que um gerenciador de estado, é um framework de Injeção de Dependência reativo.
-
Características: Captura erros em tempo de compilação, permite acesso ao estado sem
BuildContexte facilita testes unitários. -
Exemplo Prático:
final userDataProvider = FutureProvider((ref) => ref.watch(apiProvider).getUser());
2. Freezed
O pacote essencial para Modelagem de Dados e classes imutáveis.
-
Características: Gera automaticamente
copyWith,fromJson/toJsone suporte a Sealed Classes (Unions). -
Exemplo Prático:
@freezed class User with _$User { const factory User({required String name, required int age}) = _User; }
3. Drift
O motor SQL mais avançado (antigo Moor) para persistência de dados offline.
-
Características: Permite escrever queries em Dart puro, oferece migrações automáticas e é totalmente reativo (Streams).
-
Exemplo Prático:
// Seleção reativa de dados Stream<List<Todo>> watchEntries() => select(todos).watch();
4. GoRouter
A solução padrão para Navegação Declarativa (Router API).
-
Características: Gerencia Deep Linking, rotas aninhadas e redirecionamentos baseados em autenticação.
-
Exemplo Prático:
GoRoute(path: '/details/:id', builder: (context, state) => DetailsPage(id: state.pathParameters['id']!))
5. Auto Route
Um roteador baseado em geração de código focado em segurança de tipos.
-
Características: Gera rotas fortemente tipadas, evitando erros de digitação em strings de caminhos.
-
Exemplo Prático:
context.router.push(UserRoute(id: 10)); // Passagem de argumentos segura
6. Isar
Banco de dados NoSQL ultra rápido, sucessor espiritual do Hive.
-
Características: Suporta transações ACID, consultas complexas, links entre objetos e é otimizado para múltiplos núcleos.
-
Exemplo Prático:
final users = await isar.users.filter().nameStartsWith("Gemini").findAll();
7. Talker
Sistema de Observabilidade e Logs avançado para monitoramento em tempo real.
-
Características: Intercepta logs de rede, erros do Flutter e mensagens de sistema em uma interface visual.
-
Exemplo Prático:
final talker = Talker();
talker.error('Erro crítico na API', exception, stackTrace);
8. Sentry
A ferramenta líder para Monitoramento de Erros e Performance em produção.
-
Características: Reporta crashes automaticamente e fornece “Breadcrumbs” (os passos do usuário antes do erro).
-
Exemplo Prático:
await SentryFlutter.init((options) => options.dsn = 'SUA_DSN_AQUI');
9. Hydrated BLoC
Uma extensão do BLoC que persiste estados automaticamente.
-
Características: Salva o estado do BLoC no disco e o restaura ao reiniciar o app sem código extra.
-
Exemplo Prático:
// O estado do tema é salvo automaticamente ao mudar @override ThemeState? fromJson(Map<String, dynamic> json) => ThemeState.fromMap(json);
10. Flutter Hooks
Inspirado no React Hooks, focado em reutilização de lógica de widgets.
-
Características: Elimina o boilerplate de
StatefulWidgetscomo controladores de animação ou texto. -
Exemplo Prático:
final controller = useTextEditingController(); // Gerido automaticamente
📊 Tabela de Comparação e Uso
| Package | Foco Principal | Complexidade | Quando Implementar? |
| Riverpod | Gestão de Estado / DI | Média | Em qualquer projeto profissional. |
| Freezed | Modelagem / Imutabilidade | Baixa | Sempre que criar classes de dados. |
| Drift | SQL Reativo | Alta | Apps Offline-First complexos. |
| Isar | NoSQL Performance | Média | Quando velocidade é a maior prioridade. |
| GoRouter | Navegação Web/Mobile | Baixa | Apps com navegação complexa. |
| Sentry | Observabilidade | Média | Antes de publicar o app na loja. |
💡 Cenário de Uso Combinado
Em um projeto de alto nível, a arquitetura geralmente se parece com isto:
-
Modelos: Criados com Freezed para segurança de dados.
-
Repositórios: Usam Drift ou Isar para cache local.
-
Comunicação: Riverpod injeta os repositórios nos Widgets.
-
Navegação: Auto Route ou GoRouter gerencia as transições.
-
Monitoramento: Sentry e Talker garantem que nada falhe silenciosamente.
Este é um exemplo de arquitetura profissional utilizando o “Trio de Ouro” do Flutter avançado: Riverpod (Estado e DI), GoRouter (Navegação) e Freezed (Modelagem imutável).
Este fluxo simula uma autenticação completa: o estado do utilizador é monitorizado e, caso ele saia (logout), o router redireciona-o automaticamente para a página de Login.
1. Modelagem com Freezed (user_model.dart)
O Freezed garante que o nosso estado seja imutável e fornece métodos como copyWith.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user_model.freezed.dart';
part 'user_model.g.dart';
@freezed
class AuthState with _$AuthState {
const factory AuthState.initial() = _Initial;
const factory AuthState.loading() = _Loading;
const factory AuthState.authenticated(String email) = _Authenticated;
const factory AuthState.unauthenticated() = _Unauthenticated;
}
2. Lógica de Estado com Riverpod (auth_provider.dart)
Aqui gerimos a lógica. O Notifier permite-nos expor métodos para login/logout.
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'auth_provider.g.dart';
@riverpod
class AuthNotifier extends _$AuthNotifier {
@override
AuthState build() => const AuthState.unauthenticated();
Future<void> login(String email, String password) async {
state = const AuthState.loading();
await Future.delayed(const Duration(seconds: 2)); // Simula API
state = AuthState.authenticated(email);
}
void logout() {
state = const AuthState.unauthenticated();
}
}
3. Navegação Declarativa com GoRouter (router.dart)
O segredo aqui é o refreshListenable. O router “ouve” as mudanças no estado do Riverpod e decide para onde enviar o utilizador.
import 'package:go_router/go_router.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final routerProvider = Provider<GoRouter>((ref) {
final authState = ref.watch(authNotifierProvider);
return GoRouter(
initialLocation: '/login',
// Redirecionamento Automático
redirect: (context, state) {
final isAuth = authState is _Authenticated;
final isLoggingIn = state.matchedLocation == '/login';
if (!isAuth && !isLoggingIn) return '/login';
if (isAuth && isLoggingIn) return '/home';
return null;
},
routes: [
GoRoute(path: '/login', builder: (context, state) => const LoginPage()),
GoRoute(path: '/home', builder: (context, state) => const HomePage()),
],
);
});
4. Interface (UI) – Login e Home
Página de Login:
class LoginPage extends ConsumerWidget {
const LoginPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(authNotifierProvider);
return Scaffold(
body: Center(
child: state.maybeWhen(
loading: () => const CircularProgressIndicator(),
orElse: () => ElevatedButton(
onPressed: () => ref.read(authNotifierProvider.notifier).login('dev@flutter.com', '123456'),
child: const Text('Entrar no App'),
),
),
),
);
}
}
Página Home:
class HomePage extends ConsumerWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(title: const Text('Dashboard')),
body: Center(
child: ElevatedButton(
onPressed: () => ref.read(authNotifierProvider.notifier).logout(),
child: const Text('Sair (Logout)'),
),
),
);
}
}
💎 Vantagens desta Abordagem Avançada
-
Redirecionamento Centralizado: Não precisas de chamar
context.push()manualmente após o login. O router detecta que o estado mudou paraauthenticatede move o utilizador sozinho. -
Segurança de Estado: Com o
Freezed, é impossível o app estar em “Loading” e “Authenticated” ao mesmo tempo, pois as Unions são exclusivas. -
Testabilidade: Podes testar o
AuthNotifiere oGoRouterseparadamente sem precisar de emuladores, injetando mocks noProviderContainer. -
Sincronização: Se o token expirar (mudança para
unauthenticated), o utilizador é expulso da Home instantaneamente, de qualquer parte do app.
Este padrão é o que empresas como a Nubank, Airbnb e BMW utilizam nas suas aplicações Flutter de larga escala. Gostarias de ver como integrar o Sentry neste fluxo para capturar erros de login automaticamente?