diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61e11f3..860defc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.4.0] - 2025-01-24
+
+### Added
+- **🎥 Microsoft Clarity Integration**: Complete integration with official Clarity Flutter SDK for behavioral analytics
+- **EngineClarityConfig**: Configuration class for Microsoft Clarity with Project ID, User ID, and LogLevel support
+- **Masking Widgets**: `EngineMaskWidget` and `EngineUnmaskWidget` for protecting sensitive content
+- **Example App**: Complete example demonstrating Clarity integration with masking examples
+
+### Enhanced
+#### Microsoft Clarity Features
+- **Session Recordings**: Automatic capture of user sessions for replay
+- **Heatmaps**: Visual representation of user interactions
+- **User Insights**: Automatic detection of rage taps, dead taps, excessive scrolling
+- **Auto-tracking**: Automatic capture of navigation and user interactions
+- **Zero Configuration Events**: No manual event logging needed - Clarity captures automatically
+
+#### Architecture Updates
+- **EngineAnalyticsModel**: Added `clarityConfig` property for Clarity configuration
+- **EngineAnalytics**: Added `isClarityInitialized`
+- **Widget Exports**: Added Clarity masking widgets to widget exports
+- **Adapter Pattern**: Adapted Clarity's unique widget-based initialization to Engine Tracking architecture
+
+### Dependencies
+- **clarity_flutter: ^1.0.0**: Official Microsoft Clarity Flutter SDK
+
+### Technical Details
+- **Unique Implementation**: Clarity requires wrapping the app with ClarityWidget instead of static methods
+- **LogLevel Support**: Automatic production optimization (LogLevel.None in release builds)
+- **User ID Validation**: Base-36 format validation for Clarity user IDs
+- **Session Recording**: ~30 minutes for real-time viewing, ~2 hours for complete processing
+
## [1.3.0] - 2025-01-23
### Added
diff --git a/README.md b/README.md
index 467a63b..1347a6f 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,28 @@
# Engine Tracking
+
+

+
+
+## 📋 Sobre o Projeto
+
[](https://pub.dev/packages/engine_tracking)
[](https://opensource.org/licenses/MIT)
[](https://flutter.dev/)
[](https://dart.dev/)
-Uma biblioteca Flutter completa para **tracking de analytics** e **bug reporting**, oferecendo integração com Firebase Analytics, Firebase Crashlytics, Grafana Faro e Google Cloud Logging.
+Uma biblioteca Flutter completa para **tracking de analytics** e **bug reporting**, oferecendo integração com Firebase Analytics, Firebase Crashlytics, Microsoft Clarity, Grafana Faro, Splunk e Google Cloud Logging.
+
+### 📱 Plataformas Suportadas
+- ✅ iOS
+- ✅ Android
+
+---
-## 🚀 Características Principais
+## 🚀 Principais Características
-- 📊 **Analytics Múltiplo**: Suporte simultâneo para Firebase Analytics, Grafana Faro e Google Cloud Logging
-- 🐛 **Bug Tracking Avançado**: Integração com Firebase Crashlytics, Grafana Faro e Google Cloud Logging para monitoramento completo
+- 📊 **Analytics Múltiplo**: Firebase Analytics, Microsoft Clarity, Grafana Faro, Splunk e Google Cloud Logging
+- 🐛 **Bug Tracking Avançado**: Firebase Crashlytics, Grafana Faro e Google Cloud Logging para monitoramento completo
- 🌐 **HTTP Tracking**: Monitoramento automático de requisições HTTPS com métricas detalhadas
- 👁️ **View Tracking**: Sistema automático de tracking de telas com `EngineStatelessWidget` e `EngineStatefulWidget`
- ⚙️ **Configuração Flexível**: Ative/desative serviços individualmente através de configurações
@@ -20,25 +32,12 @@ Uma biblioteca Flutter completa para **tracking de analytics** e **bug reporting
- 🧪 **Testável**: Cobertura de testes superior a 95% para componentes testáveis
- 🏗️ **Arquitetura Consistente**: Padrão unificado entre Analytics e Bug Tracking
- 🎯 **Inicialização Condicional**: Serviços são inicializados apenas se habilitados na configuração
-- 📦 **Export Unificado**: Todos os imports podem ser feitos através de `package:engine_tracking/engine_tracking.dart`
+- 📦 **Export Unificado**: Todos os imports através de `package:engine_tracking/engine_tracking.dart`
- 🚀 **Exemplos Completos**: Apps de demonstração com casos de uso reais (HTTP + View Tracking)
-## 📦 Instalação
-
-Adicione ao seu `pubspec.yaml`:
-
-```yaml
-dependencies:
- engine_tracking: ^1.3.0
-```
-
-Execute:
+---
-```bash
-flutter pub get
-```
-
-## 🏗️ Arquitetura da Solução
+## 🗺️ Arquitetura da Solução
### 🆔 Sistema de Session ID (Correlação Automática)
@@ -67,8 +66,8 @@ graph TD
N --> R["Splunk"]
N --> S["Crashlytics"]
- T["Correlação de Logs"] --> U["Mesmo session_id"]
- U --> V["Jornada Completa do Usuário"]
+ U["Correlação de Logs"] --> V["Mesmo session_id"]
+ V --> W["Jornada Completa do Usuário"]
```
### 📱 Widgets Stateless e Stateful com Tracking Automático
@@ -152,16 +151,16 @@ graph TD
L --> Q["Grafana Faro"]
L --> R["Splunk"]
- N --> S["Firebase Crashlytics"]
- N --> T["Grafana Faro Bug Tracking"]
+ N --> T["Firebase Crashlytics"]
+ N --> U["Grafana Faro Bug Tracking"]
- K -->|Sim| U{{"level == error || fatal?"}}
- U -->|Sim| V["EngineBugTracking.recordError()"]
- U -->|Não| W["Apenas log normal"]
+ K -->|Sim| V{{"level == error || fatal?"}}
+ V -->|Sim| W["EngineBugTracking.recordError()"]
+ V -->|Não| X["Apenas log normal"]
- V --> X["Crash Reporting"]
- X --> S
- X --> T
+ W --> Y["Crash Reporting"]
+ Y --> T
+ Y --> U
```
### 📊 Sistema de Analytics (EngineAnalytics)
@@ -181,24 +180,28 @@ graph TD
I --> J["Firebase Analytics Config"]
I --> K["Faro Config"]
I --> L["Splunk Config"]
+ I --> M["Google Logging Config"]
- D --> M["Adapters"]
- E --> M
- F --> M
- G --> M
- H --> M
+ D --> O["Adapters"]
+ E --> O
+ F --> O
+ G --> O
+ H --> O
- M --> N["EngineFirebaseAnalyticsAdapter"]
- M --> O["EngineFaroAnalyticsAdapter"]
- M --> P["EngineSplunkAnalyticsAdapter"]
+ O --> P["EngineFirebaseAnalyticsAdapter"]
+ O --> Q["EngineFaroAnalyticsAdapter"]
+ O --> R["EngineSplunkAnalyticsAdapter"]
+ O --> S["EngineGoogleLoggingAnalyticsAdapter"]
- N --> Q["Firebase Analytics SDK"]
- O --> R["Grafana Faro SDK"]
- P --> S["Splunk SDK"]
+ P --> T["Firebase Analytics SDK"]
+ Q --> U["Grafana Faro SDK"]
+ R --> V["Splunk SDK"]
+ S --> W["Google Cloud Logging API"]
- Q --> T["Google Analytics Dashboard"]
- R --> U["Grafana Dashboard"]
- S --> V["Splunk Dashboard"]
+ T --> X["Google Analytics Dashboard"]
+ U --> Y["Grafana Dashboard"]
+ V --> Z["Splunk Dashboard"]
+ W --> AA["Google Cloud Console"]
```
### 🐛 Sistema de Bug Tracking (EngineBugTracking)
@@ -218,68 +221,79 @@ graph TD
C --> J["EngineBugTrackingModel"]
J --> K["Crashlytics Config"]
J --> L["Faro Config"]
+ J --> M["Google Logging Config"]
- D --> M["Adapters"]
- E --> M
- F --> M
- G --> M
- H --> M
- I --> M
+ D --> N["Adapters"]
+ E --> N
+ F --> N
+ G --> N
+ H --> N
+ I --> N
- M --> N["EngineCrashlyticsAdapter"]
- M --> O["EngineFaroBugTrackingAdapter"]
+ N --> O["EngineCrashlyticsAdapter"]
+ N --> P["EngineFaroBugTrackingAdapter"]
+ N --> Q["EngineGoogleLoggingBugTrackingAdapter"]
- N --> P["Firebase Crashlytics SDK"]
- O --> Q["Grafana Faro SDK"]
+ O --> R["Firebase Crashlytics SDK"]
+ P --> S["Grafana Faro SDK"]
+ Q --> T["Google Cloud Logging API"]
- P --> R["Firebase Console"]
- Q --> S["Grafana Dashboard"]
+ R --> U["Firebase Console"]
+ S --> V["Grafana Dashboard"]
+ T --> W["Google Cloud Console"]
- T["Flutter Error Handler"] --> F
- U["Platform Error Handler"] --> E
+ X["Flutter Error Handler"] --> F
+ Y["Platform Error Handler"] --> E
- V["Custom Errors"] --> E
- W["Logging Events"] --> D
+ Z["Custom Errors"] --> E
+ AA["Logging Events"] --> D
```
-## 🚀 Exemplos de Uso
+---
-O pacote inclui exemplos completos demonstrando todas as funcionalidades:
+## 📦 Instalação
+
+Adicione ao seu `pubspec.yaml`:
+
+```yaml
+dependencies:
+ engine_tracking: ^1.4.0
+```
+
+Execute:
-### 📱 Exemplo Principal
-Demonstra inicialização, tracking de eventos, propriedades de usuário e navegação:
```bash
-cd example && flutter run
+flutter pub get
```
-### 🌐 Exemplo HTTP Tracking
-Novo exemplo demonstrando tracking de requisições HTTPS com APIs públicas:
-- **PokéAPI**: Requisições GET para dados de pokémons
-- **JSONPlaceholder**: GET de posts/usuários e POST para criação
-- **Tracking completo**: Tempo de resposta, códigos de status, tratamento de erros
+---
-Para acessar: Execute o app e toque em **"HTTP Tracking"**
+## 🚀 Exemplos de Uso
-### 👁️ Exemplo View Tracking
-Sistema completo de tracking automático de telas com `EngineStatelessWidget` e `EngineStatefulWidget`:
-- Tracking automático de visualizações
-- Logging de ações do usuário
-- Monitoramento de ciclo de vida
+### 📱 Exemplos Inclusos
-Para acessar: Execute o app e toque em **"View Tracking"**
+O pacote inclui exemplos completos demonstrando todas as funcionalidades:
-## 📊 Analytics
+```bash
+cd example && flutter run
+```
-O `EngineAnalytics` oferece integração com Firebase Analytics e Grafana Faro para tracking completo de eventos e comportamento do usuário.
+- **📱 Exemplo Principal**: Inicialização, tracking de eventos, propriedades de usuário e navegação
+- **🌐 Exemplo HTTP Tracking**: Requisições com PokéAPI e JSONPlaceholder
+- **👁️ Exemplo View Tracking**: Sistema automático de tracking de telas
### 🎯 Configuração Básica
```dart
import 'package:engine_tracking/engine_tracking.dart';
-Future setupAnalytics() async {
+Future setupTracking() async {
final analyticsModel = EngineAnalyticsModel(
firebaseAnalyticsConfig: const EngineFirebaseAnalyticsConfig(enabled: true),
+ clarityConfig: const EngineClarityConfig(
+ enabled: true,
+ projectId: 'seu-projeto-clarity',
+ ),
faroConfig: const EngineFaroConfig(
enabled: true,
endpoint: 'https://faro-collector.grafana.net/collect',
@@ -288,44 +302,49 @@ Future setupAnalytics() async {
environment: 'production',
apiKey: 'sua-chave-api-faro',
),
- googleLoggingConfig: const EngineGoogleLoggingConfig(
- enabled: true,
- projectId: 'seu-projeto-gcp',
- logName: 'engine-tracking',
- credentials: {
- // Conteúdo completo do arquivo JSON da Service Account
- "type": "service_account",
- "project_id": "seu-projeto-gcp",
- "private_key_id": "...",
- "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
- "client_email": "sua-service-account@seu-projeto-gcp.iam.gserviceaccount.com",
- "client_id": "...",
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
- "token_uri": "https://oauth2.googleapis.com/token",
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
- "client_x509_cert_url": "...",
- },
- resource: {
- 'type': 'global',
- 'labels': {'project_id': 'seu-projeto-gcp'},
+ googleLoggingConfig: const EngineGoogleLoggingConfig(
+ enabled: true,
+ projectId: 'seu-projeto-gcp',
+ logName: 'engine-tracking',
+ credentials: {
+ "type": "service_account",
+ "project_id": "seu-projeto-gcp",
+ "private_key_id": "...",
+ "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
+ "client_email": "sua-service-account@seu-projeto-gcp.iam.gserviceaccount.com",
+ // ... resto das credenciais
+ },
+ resource: {
+ 'type': 'global',
+ 'labels': {'project_id': 'seu-projeto-gcp'},
},
),
- splunkConfig: const EngineSplunkConfig(enabled: false, /* outros campos */),
- );
+ splunkConfig: const EngineSplunkConfig(enabled: false),
+ );
+
+ final bugTrackingModel = EngineBugTrackingModel(
+ crashlyticsConfig: const EngineCrashlyticsConfig(enabled: true),
+ faroConfig: const EngineFaroConfig(
+ enabled: true,
+ endpoint: 'https://faro-collector.grafana.net/collect',
+ appName: 'MeuApp',
+ appVersion: '1.0.0',
+ environment: 'production',
+ apiKey: 'sua-chave-api-faro',
+ ),
+ googleLoggingConfig: const EngineGoogleLoggingConfig(enabled: true, /* configs */),
+ );
await EngineAnalytics.init(analyticsModel);
+ await EngineBugTracking.init(bugTrackingModel);
}
```
-### 📈 Logging de Eventos
+### 📈 Tracking de Eventos
```dart
// Evento simples (Session ID incluído automaticamente)
await EngineAnalytics.logEvent('button_clicked');
-// Output: {
-// "event_name": "button_clicked",
-// "session_id": "818c22c7-bcab-4e37-a12e-cd42a49547c6"
-// }
// Evento com parâmetros
await EngineAnalytics.logEvent('purchase_completed', {
@@ -334,14 +353,6 @@ await EngineAnalytics.logEvent('purchase_completed', {
'currency': 'BRL',
'category': 'subscription',
});
-// Output: {
-// "event_name": "purchase_completed",
-// "session_id": "818c22c7-bcab-4e37-a12e-cd42a49547c6",
-// "item_id": "premium_plan",
-// "value": 29.99,
-// "currency": "BRL",
-// "category": "subscription"
-// }
// Evento de abertura do app
await EngineAnalytics.logAppOpen();
@@ -353,7 +364,7 @@ await EngineAnalytics.logAppOpen();
// Definir ID do usuário
await EngineAnalytics.setUserId('user_12345');
-// Com informações completas (para Faro)
+// Com informações completas (para Faro/Clarity)
await EngineAnalytics.setUserId(
'user_12345',
'usuario@exemplo.com',
@@ -379,1027 +390,86 @@ await EngineAnalytics.setPage(
);
```
-### ✅ Verificação de Status
+### 🐛 Bug Tracking
```dart
-// Verificar se analytics está habilitado
-if (EngineAnalytics.isEnabled) {
- print('✅ Analytics está ativo');
-}
-
-// Verificar serviços específicos
-if (EngineAnalytics.isFirebaseAnalyticsEnabled) {
- print('🔥 Firebase Analytics ativo');
-}
-
-if (EngineAnalytics.isFaroEnabled) {
- print('📊 Faro Analytics ativo');
-}
-
-if (EngineAnalytics.isGoogleLoggingInitialized) {
- print('☁️ Google Cloud Logging ativo');
-}
-```
-
-## 🐛 Bug Tracking
-
-O `EngineBugTracking` oferece captura e logging de erros usando Firebase Crashlytics e Grafana Faro.
-
-### ⚙️ Configuração Básica
-
-```dart
-import 'package:engine_tracking/engine_tracking.dart';
-
-Future setupBugTracking() async {
- final bugTrackingModel = EngineBugTrackingModel(
- crashlyticsConfig: const EngineCrashlyticsConfig(enabled: true),
- faroConfig: const EngineFaroConfig(
- enabled: true,
- endpoint: 'https://faro-collector.grafana.net/collect',
- appName: 'MeuApp',
- appVersion: '1.0.0',
- environment: 'production',
- apiKey: 'sua-chave-api-faro',
- ),
- googleLoggingConfig: const EngineGoogleLoggingConfig(
- enabled: true,
- projectId: 'seu-projeto-gcp',
- logName: 'engine-tracking',
- credentials: {
- // Conteúdo completo do arquivo JSON da Service Account
- "type": "service_account",
- "project_id": "seu-projeto-gcp",
- "private_key_id": "...",
- "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
- "client_email": "sua-service-account@seu-projeto-gcp.iam.gserviceaccount.com",
- "client_id": "...",
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
- "token_uri": "https://oauth2.googleapis.com/token",
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
- "client_x509_cert_url": "...",
- },
- resource: {
- 'type': 'global',
- 'labels': {'project_id': 'seu-projeto-gcp'},
- },
- );
-
- await EngineBugTracking.init(bugTrackingModel);
-}
-```
-
-### 📝 Logging Estruturado
-
-```dart
-// Log simples
-await EngineBugTracking.log('Usuário fez login');
-
-// Log com contexto detalhado
-await EngineBugTracking.log(
- 'Erro no processamento de pagamento',
- level: 'error',
- attributes: {
- 'user_id': 'user_12345',
- 'payment_method': 'credit_card',
- 'amount': 29.99,
- 'transaction_id': 'txn_abc123',
- },
- stackTrace: StackTrace.current,
-);
-```
-
-### 👤 Gerenciamento de Usuário
-
-```dart
-// Definir informações do usuário
-await EngineBugTracking.setUserIdentifier(
- 'user_12345',
- 'usuario@exemplo.com',
- 'João Silva',
-);
-
-// Chaves customizadas
-await EngineBugTracking.setCustomKey('plan_type', 'premium');
-await EngineBugTracking.setCustomKey('last_login', DateTime.now().toString());
-await EngineBugTracking.setCustomKey('device_type', 'mobile');
-```
-
-### 🚨 Tratamento de Erros
+// Log estruturado
+await EngineBugTracking.log('Usuário realizou compra', {
+ 'user_id': '12345',
+ 'product_id': 'abc-123',
+ 'amount': 29.99,
+});
-```dart
-// Captura manual de erro
+// Capturar erros
try {
- await riskyOperation();
+ // código que pode falhar
} catch (error, stackTrace) {
await EngineBugTracking.recordError(
error,
stackTrace,
- reason: 'Falha na operação crítica',
- information: ['Contexto adicional', 'Dados do usuário'],
- isFatal: false,
- data: {
- 'operation_id': '12345',
- 'user_id': 'user_123',
- 'timestamp': DateTime.now().toIso8601String(),
- },
+ reason: 'Falha no processamento de pagamento',
);
}
-// Tratamento global de erros Flutter
-FlutterError.onError = EngineBugTracking.recordFlutterError;
-```
-
-### 🧪 Teste de Crash (Debug)
-
-```dart
-// Apenas em modo debug para testar integração
-#if DEBUG
-await EngineBugTracking.testCrash();
-#endif
-```
-
-## 🆔 Session ID (Correlação Automática)
-
-O `EngineSession` oferece sistema de correlação de logs e analytics através de UUID v4 único por sessão do app.
-
-### 🎯 Características Principais
-
-- ✨ **Zero Configuração**: Session ID gerado automaticamente na primeira chamada
-- 🔗 **Correlação Automática**: UUID v4 incluído automaticamente em todos os eventos
-- 🆔 **Padrão RFC 4122**: Compatible com qualquer sistema que use UUID v4
-- 🔄 **Singleton Pattern**: Mesma instância de sessão durante toda a vida do app
-- 🧪 **Testável**: Método `resetForTesting()` para cenários de teste
-
-### 🚀 Uso Automático
-
-O Session ID é incluído automaticamente em todos os eventos sem configuração adicional:
-
-```dart
-// Zero configuração necessária!
-await EngineAnalytics.logEvent('button_clicked', {'action': 'submit'});
-// Resultado:
-// {
-// "event_name": "button_clicked",
-// "session_id": "818c22c7-bcab-4e37-a12e-cd42a49547c6",
-// "action": "submit"
-// }
-
-await EngineLog.info('User action completed');
-// Resultado no Google Cloud Logging:
-// {
-// "message": "User action completed",
-// "session_id": "818c22c7-bcab-4e37-a12e-cd42a49547c6",
-// "level": "info"
-// }
-```
-
-### 🔍 Acesso Direto (Opcional)
-
-Se precisar acessar o Session ID diretamente:
-
-```dart
-import 'package:engine_tracking/engine_tracking.dart';
-
-// Obter Session ID atual
-String sessionId = EngineSession.instance.sessionId;
-print('Current Session: $sessionId');
-
-// Verificar formato UUID v4
-bool isValidUUID = EngineSession.instance.isValidUUIDv4(sessionId);
-print('Valid UUID v4: $isValidUUID'); // true
-
-// Para testes unitários (reseta session ID)
-EngineSession.instance.resetForTesting();
-```
-
-### 🎯 Formato UUID v4
-
-O Session ID gerado segue o padrão UUID v4 (RFC 4122):
-
-```
-Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
-Exemplo: 818c22c7-bcab-4e37-a12e-cd42a49547c6
-
-Características:
-- 32 caracteres hexadecimais (0-9a-f)
-- 5 grupos separados por hífen
-- 13º caractere sempre "4" (versão)
-- 17º caractere sempre "8", "9", "a" ou "b" (variant)
+// Definir contexto do usuário
+await EngineBugTracking.setUserIdentifier('user_12345');
+await EngineBugTracking.setCustomKey('subscription_plan', 'premium');
```
-### 📊 Correlação nos Painéis
-
-Com o Session ID, você pode:
-
-- **Firebase Analytics**: Filtrar eventos por `session_id` para ver jornada completa
-- **Google Cloud Logging**: Usar `session_id` para correlacionar logs da mesma sessão
-- **Grafana Faro**: Agrupar eventos por sessão para análise de performance
-- **Splunk**: Criar dashboards de jornada do usuário baseados no `session_id`
-
-```bash
-# Exemplo de query no Google Cloud Logging
-jsonPayload.session_id="818c22c7-bcab-4e37-a12e-cd42a49547c6"
-
-# Exemplo de filtro no Firebase Analytics
-session_id == "818c22c7-bcab-4e37-a12e-cd42a49547c6"
-```
-
-## 📋 Logging do Sistema
-
-O `EngineLog` oferece sistema de logging estruturado com diferentes níveis.
-
-### 📊 Níveis de Log
+### 📝 Sistema de Logging
```dart
-import 'package:engine_tracking/engine_tracking.dart';
-
-// Debug (Session ID incluído automaticamente)
-await EngineLog.debug('Debug message', data: {'key': 'value'});
-// Output: {
-// "message": "Debug message",
-// "session_id": "818c22c7-bcab-4e37-a12e-cd42a49547c6",
-// "key": "value"
-// }
-
-// Info
-await EngineLog.info('Info message', data: {'status': 'success'});
-
-// Warning
-await EngineLog.warning('Warning message', error: exception);
-
-// Error
-await EngineLog.error('Error message', error: exception, stackTrace: stackTrace);
-
-// Fatal
-await EngineLog.fatal('Fatal error', error: exception, stackTrace: stackTrace);
-```
-
-### 🏷️ Níveis Disponíveis
-
-| Nível | Valor | Uso Recomendado |
-|-------|-------|-----------------|
-| `debug` | 100 | Informações de desenvolvimento |
-| `info` | 800 | Informações gerais |
-| `warning` | 900 | Avisos e situações inesperadas |
-| `error` | 1000 | Erros recuperáveis |
-| `fatal` | 1200 | Erros críticos do sistema |
-
-## 🔧 Configuração Avançada
-
-### 🏗️ Configuração por Ambiente
-
-```dart
-class TrackingConfig {
- static EngineAnalyticsModel getAnalyticsConfig(String environment) {
- final isProduction = environment == 'production';
-
- return EngineAnalyticsModel(
- firebaseAnalyticsConfig: EngineFirebaseAnalyticsConfig(enabled: isProduction),
- faroConfig: EngineFaroConfig(
- enabled: isProduction,
- endpoint: isProduction
- ? 'https://faro-prod.grafana.net/collect'
- : 'https://faro-dev.grafana.net/collect',
- appName: 'MeuApp',
- appVersion: '1.0.0',
- environment: environment,
- apiKey: isProduction ? 'prod-key' : 'dev-key',
- ),
- );
- }
-
- static EngineBugTrackingModel getBugTrackingConfig(String environment) {
- final isProduction = environment == 'production';
-
- return EngineBugTrackingModel(
- crashlyticsConfig: EngineCrashlyticsConfig(enabled: isProduction),
- faroConfig: EngineFaroConfig(
- enabled: true, // Faro sempre ativo para debugging
- endpoint: isProduction
- ? 'https://faro-prod.grafana.net/collect'
- : 'https://faro-dev.grafana.net/collect',
- appName: 'MeuApp',
- appVersion: '1.0.0',
- environment: environment,
- apiKey: isProduction ? 'prod-key' : 'dev-key',
- ),
- );
- }
-}
-```
-
-### 🎛️ Configuração Padrão
-
-```dart
-// Analytics com configuração padrão (tudo desabilitado)
-final defaultAnalytics = EngineAnalyticsModelDefault();
-await EngineAnalytics.init(defaultAnalytics);
-
-// Bug tracking com configuração padrão (tudo desabilitado)
-final defaultBugTracking = EngineBugTrackingModelDefault();
-await EngineBugTracking.init(defaultBugTracking);
-```
-
-## 📊 Modelos de Dados
-
-### EngineAnalyticsModel
-
-```dart
-class EngineAnalyticsModel {
- final EngineFirebaseAnalyticsConfig firebaseAnalyticsConfig;
- final EngineFaroConfig faroConfig;
-
- EngineAnalyticsModel({
- required this.firebaseAnalyticsConfig,
- required this.faroConfig,
- });
-}
-
-class EngineAnalyticsModelDefault implements EngineAnalyticsModel {
- // Implementação com valores padrão desabilitados
-}
-```
-
-### EngineBugTrackingModel
-
-```dart
-class EngineBugTrackingModel {
- final EngineCrashlyticsConfig crashlyticsConfig;
- final EngineFaroConfig faroConfig;
-
- EngineBugTrackingModel({
- required this.crashlyticsConfig,
- required this.faroConfig,
- });
-}
-
-class EngineBugTrackingModelDefault implements EngineBugTrackingModel {
- // Implementação com valores padrão desabilitados
-}
-```
-
-### Configurações de Serviços
-
-```dart
-// Firebase Analytics
-class EngineFirebaseAnalyticsConfig {
- final bool enabled;
-
- const EngineFirebaseAnalyticsConfig({required this.enabled});
-}
-
-// Firebase Crashlytics
-class EngineCrashlyticsConfig {
- final bool enabled;
-
- const EngineCrashlyticsConfig({required this.enabled});
-}
-
-// Grafana Faro (Compartilhado)
-class EngineFaroConfig {
- final bool enabled;
- final String endpoint;
- final String appName;
- final String appVersion;
- final String environment;
- final String apiKey;
-
- const EngineFaroConfig({
- required this.enabled,
- required this.endpoint,
- required this.appName,
- required this.appVersion,
- required this.environment,
- required this.apiKey,
- });
-}
-```
-
-### EngineLogLevelType
-
-```dart
-enum EngineLogLevelType {
- debug('DEBUG', 100),
- info('INFO', 800),
- warning('WARNING', 900),
- error('ERROR', 1000),
- fatal('FATAL', 1200);
-
- final String name;
- final int value;
-
- const EngineLogLevelType(this.name, this.value);
-}
-```
-
-## 📱 Exemplo Completo
-
-Execute o exemplo interativo:
-
-```bash
-cd example
-flutter run
-```
-
-### 🏗️ Implementação Completa
-
-```dart
-import 'package:flutter/material.dart';
-import 'package:engine_tracking/engine_tracking.dart';
-
-void main() async {
- WidgetsFlutterBinding.ensureInitialized();
-
- // Configurar Analytics
- final analyticsModel = EngineAnalyticsModel(
- firebaseAnalyticsConfig: const EngineFirebaseAnalyticsConfig(enabled: true),
- faroConfig: const EngineFaroConfig(
- enabled: true,
- endpoint: 'https://faro-collector.grafana.net/collect',
- appName: 'MeuApp',
- appVersion: '1.2.3',
- environment: 'production',
- apiKey: 'faro-api-key',
- ),
- );
-
- // Configurar Bug Tracking
- final bugTrackingModel = EngineBugTrackingModel(
- crashlyticsConfig: const EngineCrashlyticsConfig(enabled: true),
- faroConfig: const EngineFaroConfig(
- enabled: true,
- endpoint: 'https://faro-collector.grafana.net/collect',
- appName: 'MeuApp',
- appVersion: '1.2.3',
- environment: 'production',
- apiKey: 'faro-api-key',
- ),
- );
-
- // Inicializar serviços
- await Future.wait([
- EngineAnalytics.init(analyticsModel),
- EngineBugTracking.init(bugTrackingModel),
- ]);
-
- // Configurar usuário
- await Future.wait([
- EngineAnalytics.setUserId('user_12345', 'user@exemplo.com', 'João Silva'),
- EngineBugTracking.setUserIdentifier('user_12345', 'user@exemplo.com', 'João Silva'),
- ]);
-
- // Configurar tratamento global de erros
- FlutterError.onError = EngineBugTracking.recordFlutterError;
-
- runApp(MyApp());
-}
-
-class MyApp extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- title: 'Engine Tracking Demo',
- home: MyHomePage(),
- );
- }
-}
-
-class MyHomePage extends StatefulWidget {
- @override
- _MyHomePageState createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State {
- @override
- void initState() {
- super.initState();
- // Registrar visualização da tela
- EngineAnalytics.setPage('HomeScreen');
- }
-
- void _onButtonPressed() async {
- // Registrar evento de analytics
- await EngineAnalytics.logEvent('button_pressed', {
- 'button_name': 'home_action',
- 'timestamp': DateTime.now().millisecondsSinceEpoch,
- 'user_journey_step': 'main_interaction',
- });
-
- // Log para debugging
- await EngineBugTracking.log(
- 'Botão pressionado na tela inicial',
- level: 'info',
- attributes: {'screen': 'home', 'action': 'button_press'},
- );
- }
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(title: Text('Engine Tracking Demo')),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- ElevatedButton(
- onPressed: _onButtonPressed,
- child: Text('Testar Tracking'),
- ),
- SizedBox(height: 20),
- Card(
- child: Padding(
- padding: EdgeInsets.all(16),
- child: Column(
- children: [
- Text('Status dos Serviços:', style: TextStyle(fontWeight: FontWeight.bold)),
- SizedBox(height: 8),
- _buildStatusRow('Analytics', EngineAnalytics.isEnabled),
- _buildStatusRow('Firebase Analytics', EngineAnalytics.isFirebaseAnalyticsEnabled),
- _buildStatusRow('Faro Analytics', EngineAnalytics.isFaroEnabled),
- _buildStatusRow('Google Cloud Logging', EngineAnalytics.isGoogleLoggingInitialized),
- _buildStatusRow('Bug Tracking', EngineBugTracking.isEnabled),
- _buildStatusRow('Crashlytics', EngineBugTracking.isCrashlyticsEnabled),
- _buildStatusRow('Faro Logging', EngineBugTracking.isFaroEnabled),
- _buildStatusRow('GCP Bug Tracking', EngineBugTracking.isGoogleLoggingInitialized),
- ],
- ),
- ),
- ),
- ],
- ),
- ),
- );
- }
-
- Widget _buildStatusRow(String service, bool isEnabled) {
- return Row(
- children: [
- Icon(
- isEnabled ? Icons.check_circle : Icons.cancel,
- size: 16,
- color: isEnabled ? Colors.green : Colors.red,
- ),
- SizedBox(width: 8),
- Text('$service: ${isEnabled ? 'Enabled' : 'Disabled'}'),
- ],
- );
- }
-}
-```
-
-## 🏗️ Estrutura do Projeto
-
-### 📁 Organização de Diretórios e Arquivos
-
-```
-engine-tracking/
-├── .github/ # 🔧 Automação e Templates GitHub
-│ ├── workflows/ # 🔄 GitHub Actions Pipelines
-│ │ ├── ci.yml # Pipeline principal CI/CD
-│ │ ├── publish.yml # Publicação automática pub.dev
-│ │ └── quality.yml # Auditorias semanais de qualidade
-│ ├── ISSUE_TEMPLATE/ # 📝 Templates de Issues
-│ │ ├── bug_report.md # Template para reportar bugs
-│ │ └── feature_request.md # Template para solicitar funcionalidades
-│ ├── pull_request_template.md # Template para Pull Requests
-│ └── README.md # Documentação da infraestrutura CI/CD
-├── lib/ # 📚 Código fonte principal
-│ ├── engine_tracking.dart # 🚪 Ponto de entrada principal
-│ └── src/ # 📦 Implementações internas
-│ ├── src.dart # Export barrel centralizado
-│ ├── analytics/ # 📊 Sistema de Analytics
-│ │ ├── analytics.dart # Export barrel do módulo
-│ │ └── engine_analytics.dart # Implementação principal
-│ ├── bug_tracking/ # 🐛 Sistema de Bug Tracking
-│ │ ├── bug_tracking.dart # Export barrel do módulo
-│ │ └── engine_bug_tracking.dart # Implementação principal
-│ ├── config/ # ⚙️ Configurações dos serviços
-│ │ ├── config.dart # Export barrel das configurações
-│ │ ├── engine_firebase_analytics_config.dart
-│ │ ├── engine_crashlytics_config.dart
-│ │ └── engine_faro_config.dart
-│ ├── models/ # 🏗️ Modelos de dados
-│ │ ├── models.dart # Export barrel dos modelos
-│ │ ├── engine_analytics_model.dart
-│ │ └── engine_bug_tracking_model.dart
-│ ├── enums/ # 🏷️ Enumerações
-│ │ ├── enums.dart # Export barrel das enumerações
-│ │ └── engine_log_level_type.dart
-│ ├── logging/ # 📝 Sistema de logging
-│ │ ├── logging.dart # Export barrel do logging
-│ │ └── engine_log.dart # Implementação de logs
-│ └── observers/ # 👁️ Observadores Flutter
-│ ├── observers.dart # Export barrel dos observadores
-│ └── engine_navigator_observer.dart
-├── test/ # 🧪 Testes unitários e de integração
-│ ├── analytics/ # Testes do sistema de analytics
-│ ├── bug_tracking/ # Testes do sistema de bug tracking
-│ ├── config/ # Testes das configurações
-│ ├── models/ # Testes dos modelos de dados
-│ ├── logging/ # Testes do sistema de logging
-│ └── test_coverage.dart # Suite completa de testes
-├── example/ # 📱 Aplicação de exemplo
-│ ├── lib/main.dart # App Flutter demonstrativo
-│ ├── pubspec.yaml # Dependências do exemplo
-│ └── README.md # Documentação do exemplo
-├── scripts/ # 🛠️ Scripts de desenvolvimento
-│ ├── test_coverage.sh # Script de cobertura de testes
-│ └── pana_analysis.sh # Script de análise de qualidade
-├── codecov.yml # 📊 Configuração Codecov
-├── pana_config.yaml # 🔍 Configuração Pana
-├── pubspec.yaml # 📦 Configuração do pacote
-├── CHANGELOG.md # 📝 Histórico de mudanças
-├── LICENSE # ⚖️ Licença MIT
-├── README.md # 📖 Documentação principal
-└── analysis_options.yaml # 🔬 Configuração do Dart Analyzer
-```
-
-#### ⚙️ Arquivos de Configuração
-
-##### 📊 `codecov.yml` - Cobertura de Código
-- Meta de cobertura: 45% (ajustada para dependências externas)
-- Exclusões: Arquivos gerados, testes, exemplos
-- Integração com PRs para comentários automáticos
-
-##### 🔍 `pana_config.yaml` - Análise de Qualidade
-- Padrão de excelência: 160/160 pontos
-- Verificações completas habilitadas
-- Exclusão de arquivos de desenvolvimento
-
-##### 📦 `pubspec.yaml` - Configuração do Pacote
-- Dependências otimizadas
-- Metadados completos para pub.dev
-- Compatibilidade com Flutter >=3.32.0 e Dart >=3.8.0
-
-### 🎯 Arquitetura e Padrões
-
-#### 🏗️ Padrões Arquiteturais
-- **Construtor Privado**: Previne instanciação desnecessária
-- **API Estática**: Métodos estáticos para facilidade de uso
-- **Inicialização Condicional**: Serviços inicializam apenas se habilitados
-- **Export Unificado**: Import único para todo o pacote
-
-#### 🔒 Princípios de Qualidade
-- **Tipo-seguro**: Implementação completamente tipada
-- **Testável**: Arquitetura focada em testabilidade
-- **Configurável**: Flexibilidade total na configuração
-- **Performático**: Inicialização sob demanda
-
-## 🔧 Desenvolvimento
-
-### 📁 Estrutura Técnica
+// Diferentes níveis de log
+EngineLog.debug('Debug information');
+EngineLog.info('Informational message');
+EngineLog.warning('Warning message');
+EngineLog.error('Error occurred');
+EngineLog.fatal('Fatal error');
+
+// Com contexto adicional
+EngineLog.info('User action', context: {
+ 'action': 'button_click',
+ 'screen': 'home',
+ 'user_id': '12345',
+});
+// Incluir em analytics (padrão: false para debug/info)
+EngineLog.warning('Important warning', includeInAnalytics: true);
```
-lib/
-├── engine_tracking.dart # Ponto de entrada principal
-└── src/
- ├── src.dart # Exportações centralizadas
- ├── analytics/ # Sistema de analytics
- │ ├── analytics.dart # Export barrel
- │ └── engine_analytics.dart # Implementação principal
- ├── bug_tracking/ # Sistema de bug tracking
- │ ├── bug_tracking.dart # Export barrel
- │ └── engine_bug_tracking.dart # Implementação principal
- ├── config/ # Configurações dos serviços
- │ ├── config.dart # Export barrel
- │ ├── engine_firebase_analytics_config.dart
- │ ├── engine_crashlytics_config.dart
- │ ├── engine_faro_config.dart
- │ └── engine_google_logging_config.dart
- ├── models/ # Modelos de dados
- │ ├── models.dart # Export barrel
- │ ├── engine_analytics_model.dart
- │ └── engine_bug_tracking_model.dart
- ├── enums/ # Enumerações
- │ ├── enums.dart # Export barrel
- │ └── engine_log_level_type.dart
- ├── logging/ # Sistema de logging
- │ ├── logging.dart # Export barrel
- │ └── engine_log.dart # Implementação de logging
- └── observers/ # Observadores Flutter
- ├── observers.dart # Export barrel
- └── engine_navigator_observer.dart
-
-test/
-├── analytics/ # Testes de analytics
-├── bug_tracking/ # Testes de bug tracking
-├── config/ # Testes de configuração
-├── models/ # Testes de modelos
-├── logging/ # Testes de logging
-└── test_coverage.dart # Suite completa de testes
-
-example/ # App de demonstração
-├── lib/main.dart # Implementação de exemplo
-├── pubspec.yaml # Dependências do exemplo
-└── README.md # Documentação do exemplo
-```
-
-## Sistema de Tracking de Views
-
-Este sistema fornece funcionalidades automáticas de tracking para widgets StatelessWidget e StatefulWidget, permitindo monitorar o comportamento do usuário passo a passo.
-
-## 🎯 Widget Tracking
-O Engine Tracking oferece um sistema avançado de tracking automático para widgets, permitindo monitoramento transparente de navegação, ações do usuário e ciclo de vida de telas.
-
-### Características dos Widgets
-
-- 📊 **Tracking Automático**: Visualizações de tela registradas automaticamente
-- 🔄 **Ciclo de Vida**: Monitoramento de init/dispose em StatefulWidgets
-- 👆 **Ações do Usuário**: Métodos integrados para logging de interações
-- 📝 **Eventos Customizados**: Sistema flexível para eventos específicos
-- 🐛 **Tratamento de Erros**: Captura contextualizada de erros por tela
-- ⚙️ **Configurável**: Controle granular sobre tracking automático
-
-### Implementações Disponíveis
-
-#### 1. Classes Engine (Recomendado)
-
-As classes Engine oferecem implementação completa com tracking automático integrado.
-
-##### EngineStatelessWidget
+### 👁️ View Tracking com Widgets
```dart
-import 'package:engine_tracking/engine_tracking.dart';
-
class HomePage extends EngineStatelessWidget {
HomePage({super.key});
@override
- String get screenName => 'home_page';
-
- @override
- Map? get screenParameters => {
- 'version': '1.0.0',
- 'source': 'main_menu',
- };
-
- @override
- Widget buildWithTracking(BuildContext context) {
- return Scaffold(
- appBar: AppBar(title: const Text('Início')),
- body: Column(
- children: [
- ElevatedButton(
- onPressed: () {
- logUserAction('button_pressed', parameters: {
- 'button_type': 'primary',
- 'action': 'navigate_to_settings',
- });
- },
- child: const Text('Configurações'),
- ),
- ElevatedButton(
- onPressed: () {
- logCustomEvent('feature_accessed', parameters: {
- 'feature': 'premium_content',
- });
- },
- child: const Text('Conteúdo Premium'),
- ),
- ],
- ),
- );
- }
-}
-```
-
-##### EngineStatefulWidget
-
-```dart
-import 'package:engine_tracking/engine_tracking.dart';
-
-class ProfilePage extends EngineStatefulWidget {
- const ProfilePage({super.key});
-
- @override
- EngineStatefulWidgetState createState() => _ProfilePageState();
-}
-
-class _ProfilePageState extends EngineStatefulWidgetState {
- String _userName = '';
-
- @override
- String get screenName => 'profile_page';
+ String get screenName => 'home';
@override
Map? get screenParameters => {
'user_type': 'premium',
+ 'version': '1.0.0',
};
@override
Widget buildWithTracking(BuildContext context) {
return Scaffold(
- body: Column(
- children: [
- TextField(
- onChanged: (value) {
- setState(() {
- _userName = value;
- });
-
- logStateChange('username_changed', additionalData: {
- 'character_count': value.length,
- });
- },
- ),
- ElevatedButton(
- onPressed: () {
- logUserAction('profile_updated', parameters: {
- 'field': 'username',
- 'new_length': _userName.length,
- });
- },
- child: const Text('Salvar'),
- ),
- ],
- ),
- );
- }
-}
-```
-
-### Exemplo Completo com Classes Engine
-
-```dart
-import 'package:engine_tracking/engine_tracking.dart';
-
-class SettingsPage extends EngineStatelessWidget {
- SettingsPage({super.key});
-
- @override
- String get screenName => 'settings_page';
-
- @override
- Widget buildWithTracking(BuildContext context) {
- return Scaffold(
- appBar: AppBar(title: const Text('Configurações')),
- body: ListView(
- children: [
- ListTile(
- title: const Text('Notificações'),
- onTap: () => logUserAction('settings_item_tapped',
- parameters: {'item': 'notifications'}),
- ),
- ListTile(
- title: const Text('Privacidade'),
- onTap: () => logUserAction('settings_item_tapped',
- parameters: {'item': 'privacy'}),
- ),
- ],
- ),
- );
- }
-}
-```
-
-```dart
-import 'package:engine_tracking/engine_tracking.dart';
-
-class LoginPage extends EngineStatefulWidget {
- const LoginPage({super.key});
-
- @override
- EngineStatefulWidgetState createState() => _LoginPageState();
-}
-
-class _LoginPageState extends EngineStatefulWidgetState {
- bool _isLoading = false;
-
- @override
- String get screenName => 'login_page';
-
- @override
- Widget buildWithTracking(BuildContext context) {
- return Scaffold(
- body: Column(
- children: [
- TextField(
- decoration: const InputDecoration(labelText: 'Email'),
- onSubmitted: (value) {
- logUserAction('field_completed', parameters: {
- 'field': 'email',
- 'has_value': value.isNotEmpty,
- });
- },
- ),
- ElevatedButton(
- onPressed: _isLoading ? null : () async {
- setState(() {
- _isLoading = true;
- });
-
- logStateChange('login_started');
-
- try {
- await Future.delayed(const Duration(seconds: 2));
- logUserAction('login_success');
- } catch (e) {
- logScreenError('Login falhou',
- exception: e,
- additionalData: {'retry_count': 1});
- }
-
- setState(() {
- _isLoading = false;
- });
- },
- child: _isLoading
- ? const CircularProgressIndicator()
- : const Text('Entrar'),
- ),
- ],
+ appBar: AppBar(title: const Text('Home')),
+ body: ElevatedButton(
+ onPressed: () {
+ logUserAction('cta_clicked', parameters: {
+ 'button_type': 'primary',
+ 'location': 'header',
+ });
+ },
+ child: const Text('Click Me'),
),
);
}
}
```
-## Métodos Disponíveis
-
-### Tracking Automático
-- `_trackScreenView()`: Registra visualização da tela automaticamente
-- **Ciclo de vida**: initState/dispose tracking (apenas StatefulWidget)
-
-### Métodos de Logging
-- `logUserAction(action, {parameters})`: Registra ações do usuário
-- `logCustomEvent(eventName, {parameters})`: Registra eventos customizados
-- `logScreenError(error, {exception, stackTrace, additionalData})`: Registra erros
-- `logStateChange(description, {additionalData})`: Registra mudanças de estado (StatefulWidget)
-
-### Configurações
-- `screenName`: Nome da tela (padrão: nome da classe)
-- `screenParameters`: Parâmetros adicionais da tela
-- `enableAutoTracking`: Ativa/desativa tracking automático
-- `enableLifecycleTracking`: Ativa/desativa tracking de ciclo de vida (StatefulWidget)
-
-## Dados Coletados
-
-### Visualização de Tela
-```json
-{
- "screen_name": "home_page",
- "screen_type": "StatelessWidget",
- "timestamp": "2023-12-01T10:30:00.000Z",
- "parameters": {"version": "1.0.0"}
-}
-```
-
-### Ação do Usuário
-```json
-{
- "screen_name": "home_page",
- "action": "button_pressed",
- "widget_type": "StatelessWidget",
- "button_type": "primary"
-}
-```
-
-### Fechamento de Tela (StatefulWidget)
-```json
-{
- "screen_name": "profile_page",
- "widget_type": "StatefulWidget",
- "time_spent_seconds": 45,
- "time_spent_minutes": 0
-}
-```
-
-## Integração com Analytics
-
-Todos os eventos são automaticamente enviados para:
-- **Firebase Analytics** (se configurado)
-- **Grafana Faro** (se configurado)
-- **Google Cloud Logging** (se configurado)
-- **Engine Log** para debugging
-
-## Melhores Práticas
-
-1. **Use nomes descritivos** para telas e ações
-2. **Inclua parâmetros relevantes** sem dados sensíveis
-3. **Monitore erros** com contexto apropriado
-4. **Use classes Engine** para funcionalidade completa
-5. **Personalize screenName** para identificação clara
-6. **Agrupe ações relacionadas** com prefixos consistentes
-
-## Desabilitando Tracking
-
-```dart
-class MyPage extends EngineStatelessWidget {
- MyPage({super.key});
-
- @override
- bool get enableAutoTracking => false; // Desabilita tracking automático
-
- @override
- Widget buildWithTracking(BuildContext context) {
- // ... resto da implementação
- }
-}
-```
-
-## Exemplo de Uso Avançado
-
```dart
class ShoppingCartPage extends StatefulWidget {
final List initialProducts;
@@ -1479,45 +549,29 @@ class _ShoppingCartPageState extends EngineStatefulWidgetState
}
```
-### 🧪 Scripts de Desenvolvimento
-
-```bash
-# Executar todos os testes
-flutter test
-
-# Testes com cobertura
-flutter test --coverage
-genhtml coverage/lcov.info -o coverage/html
-
-# Análise estática
-dart analyze
-
-# Formatação de código
-dart format .
-
-# Publicar (dry-run)
-dart pub publish --dry-run
-```
-
-### 📊 Comandos de Qualidade
+### ✅ Verificação de Status
-```bash
-# Verificar cobertura
-dart pub global activate test_coverage
-dart pub global run test_coverage --min-coverage=95
+```dart
+// Verificar se analytics está habilitado
+if (EngineAnalytics.isEnabled) {
+ print('✅ Analytics está ativo');
+}
-# Análise Pana
-dart pub global activate pana
-dart pub global run pana
+// Verificar serviços específicos
+if (EngineAnalytics.isFirebaseAnalyticsEnabled) {
+ print('🔥 Firebase Analytics ativo');
+}
-# Verificar dependências
-dart pub outdated
+if (EngineAnalytics.isFaroEnabled) {
+ print('📊 Faro Analytics ativo');
+}
-# Atualizar dependências
-dart pub upgrade
+if (EngineAnalytics.isGoogleLoggingInitialized) {
+ print('☁️ Google Cloud Logging ativo');
+}
```
-## 🧪 Testes
+### 🧪 Testes
Execute os testes:
@@ -1532,11 +586,6 @@ flutter test
- ✅ **Testes completos** para sistema de logging e Google Cloud Logging
- ✅ **Testes completos** para Session ID com validação UUID v4 RFC 4122
-**Observações:**
-- Testes de inicialização com Firebase/Faro são mocados para evitar dependências reais
-- Todos os testes de lógica de negócio e configuração passam corretamente
-- Cobertura focada em componentes testáveis sem dependências externas
-
Para cobertura de testes:
```bash
@@ -1545,67 +594,9 @@ genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html
```
-## 📱 Plataformas Suportadas
-
-- ✅ iOS
-- ✅ Android
-
-## 🤖 Integração MCP (Model Context Protocol)
-
-O Engine Tracking v1.3.0 inclui suporte completo ao **Model Context Protocol (MCP)**, permitindo que assistentes de IA (como Claude, GPT-4, etc.) acessem dados do projeto em tempo real.
-
-### 🔧 Configuração Rápida
-
-O projeto inclui configuração automática para os principais serviços:
-
-```bash
-# Ver documentação completa
-docs/MCP_CONFIGURATION.md
-docs/MCP_QUICK_SETUP.md
-```
-
-### 🛠️ Serviços Suportados
-
-| Serviço | Funcionalidades | Status |
-|---------|----------------|--------|
-| **GitHub** | Repos, Issues, PRs, Code Search | ✅ Configurado |
-| **Firebase** | Projetos, Deploy, Firestore, Functions | ✅ Configurado |
-| **Supabase** | Tabelas, SQL, Schema, Projetos | ⚙️ Requer tokens |
-| **TaskMaster** | Tarefas, Status, Subtarefas | ✅ Configurado |
-
-### 📋 Ferramentas Incluídas
-
-```bash
-# Testar configurações MCP
-node scripts/test_mcp_connections.js
-
-# Configurar tokens interativamente
-node scripts/setup_mcp_tokens.js
-
-# Ver status atual
-node scripts/setup_mcp_tokens.js --status
-```
-
-### 💡 Capacidades
-
-Com MCP configurado, sua IA pode:
-- 🔍 **Acessar repositórios** GitHub em tempo real
-- 🔥 **Gerenciar projetos** Firebase
-- 🗄️ **Consultar bancos** Supabase
-- 📊 **Monitorar tarefas** TaskMaster
-- 📝 **Analisar código** e estrutura do projeto
-
-### 🚀 Exemplo de Uso
-
-```
-Pergunta à IA: "Mostre o status dos adaptadores Google Cloud Logging"
-Resposta: Lista arquivos, testes e documentação automaticamente
-
-Pergunta: "Quais tarefas estão pendentes no TaskMaster?"
-Resposta: Acessa e mostra tarefas em tempo real
-```
+---
-## 🤝 Contribuição
+## 🤝 Como Contribuir
Contribuições são bem-vindas! Por favor:
@@ -1623,14 +614,25 @@ Contribuições são bem-vindas! Por favor:
- Teste em Android e iOS
- Atualize o CHANGELOG.md
-## 📄 Licença
+### 📄 Licença
Este projeto está licenciado sob a Licença MIT - veja o arquivo LICENSE para detalhes.
+---
+
## 🏢 Sobre a STMR
-Desenvolvido pela STMR - Especialistas em soluções móveis.
+
+

+
+
+Desenvolvido pela **STMR** - Especialistas em soluções móveis.
+
+A STMR é uma empresa focada no desenvolvimento de soluções tecnológicas inovadoras para dispositivos móveis, especializando-se em arquiteturas robustas, performance otimizada e experiências de usuário excepcionais.
+
+### 🎯 Nossa Missão
+Fornecer ferramentas e bibliotecas Flutter de alta qualidade que aceleram o desenvolvimento de aplicações móveis enterprise, mantendo os mais altos padrões de segurança, performance e usabilidade.
---
-**💡 Dica v1.3.0**: Para máxima eficiência, configure apenas os serviços que você realmente utiliza. A biblioteca é otimizada para funcionar com qualquer combinação de serviços habilitados ou desabilitados. Com **Session ID automático**, **Google Cloud Logging** e **MCP**, você agora tem correlação completa de logs, centralização avançada e integração perfeita com assistentes de IA! 🆔🔥
\ No newline at end of file
+**💡 Dica v1.4.0**: Para máxima eficiência, configure apenas os serviços que você realmente utiliza. A biblioteca é otimizada para funcionar com qualquer combinação de serviços habilitados ou desabilitados. Com **Session ID automático** e **Google Cloud Logging**, você agora tem correlação completa de logs e centralização avançada! 🆔🔥
\ No newline at end of file
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 94c6912..2b2fbf4 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,100 +1,212 @@
-include: package:lints/recommended.yaml
+# Flutter/Dart 2025 - Comprehensive Lint Configuration
+# Based on flutter_lints 6.0.0 and modern best practices
+# Consulte este arquivo como referência para nosso padrão de lint
+
+include: package:flutter_lints/flutter.yaml
formatter:
page_width: 120
trailing_commas: preserve
+analyzer:
+ exclude:
+ - lib/generated/**
+ - lib/translations/**
+ - lib/l10n/**
+ - lib/**/*.g.dart
+ - test/_data/**
+ - example/**
+ - examples/**
+ - build/**
+ - .dart_tool/**
+
+ # Language settings for modern Dart features
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+ errors:
+ # Security and runtime safety
+ invalid_assignment: error
+ missing_required_param: error
+ missing_return: error
+ dead_code: error
+ unreachable_from_main: error
+
+ # Performance warnings
+ unused_local_variable: warning
+ unused_element: warning
+ unused_field: warning
+ unused_import: warning
+ unused_shown_name: warning
+
+ # Null safety enforcement
+ receiver_of_type_never: error
+ null_check_on_nullable_type_parameter: error
+
+ # Records and patterns (Dart 3.0+)
+ record_literal_one_positional_no_trailing_comma: error
+
+ # Collections best practices
+ collection_methods_unrelated_type: error
+ unrelated_type_equality_checks: error
+
linter:
rules:
- always_use_package_imports: true
+ # === SECURITY & SAFETY (2025 Critical) ===
+ # Modern security practices
+ avoid_dynamic_calls: true
+ avoid_type_to_string: true
+ avoid_web_libraries_in_flutter: true
+ secure_pubspec_urls: true
+
+ # Null safety enforcement
+ avoid_null_checks_in_equality_operators: true
+ null_check_on_nullable_type_parameter: true
+ unnecessary_null_checks: true
+ unnecessary_null_aware_assignments: true
+ unnecessary_null_aware_operator_on_extension_on_nullable: true
+ unnecessary_nullable_for_final_variable_declarations: true
+
+ # === PERFORMANCE (2025 Focus) ===
+ # Memory and performance optimization
+ avoid_unnecessary_containers: true
+ avoid_function_literals_in_foreach_calls: true
+ avoid_slow_async_io: true
+ prefer_const_constructors: true
+ prefer_const_constructors_in_immutables: true
+ prefer_const_declarations: true
+ prefer_const_literals_to_create_immutables: true
+ use_colored_box: true
+ use_decorated_box: true
+ sized_box_for_whitespace: true
+ sized_box_shrink_expand: true
+
+ # Async/Future optimization
+ avoid_void_async: true
+ unawaited_futures: true
+ discarded_futures: true
await_only_futures: true
+ unnecessary_await_in_return: true
+
+ # === MODERN DART FEATURES (3.0+) ===
+ # Records and patterns support
+ use_super_parameters: true
+ matching_super_parameters: true
+ use_enums: true
+
+ # === CODING STANDARDS ===
+ # Imports and organization
+ always_use_package_imports: true
+ avoid_relative_lib_imports: true
+ depend_on_referenced_packages: true
+ directives_ordering: true
+
+ # Code style consistency
always_declare_return_types: true
- cancel_subscriptions: true
- close_sinks: true
- comment_references: true
- only_throw_errors: true
- prefer_final_in_for_each: true
+ annotate_overrides: true
prefer_single_quotes: true
- avoid_shadowing_type_parameters: true
- avoid_dynamic_calls: false
+ prefer_final_fields: true
+ prefer_final_locals: true
+ prefer_final_parameters: true
+ prefer_final_in_for_each: true
+
+ # === FLUTTER SPECIFIC (2025) ===
+ # Widget best practices
+ use_key_in_widget_constructors: true
+ use_full_hex_values_for_flutter_colors: true
+ sort_child_properties_last: true
+ no_logic_in_create_state: true
+ use_build_context_synchronously: true
+
+ # === ERROR PREVENTION ===
+ # Runtime error prevention
avoid_empty_else: true
- avoid_print: true
- avoid_relative_lib_imports: true
- avoid_returning_null_for_future: true
- avoid_slow_async_io: true
- avoid_type_to_string: true
+ avoid_returning_null_for_void: true
+ avoid_shadowing_type_parameters: true
avoid_types_as_parameter_names: true
- avoid_web_libraries_in_flutter: true
- discarded_futures: true
- unawaited_futures: true
+ control_flow_in_finally: true
empty_statements: true
- prefer_void_to_null: true
- always_put_control_body_on_new_line: true
- always_require_non_null_named_parameters: true
- annotate_overrides: true
+ exhaustive_cases: true
+ no_duplicate_case_values: true
+ throw_in_finally: true
+
+ # Logic and flow
avoid_bool_literals_in_conditional_expressions: true
- avoid_escaping_inner_quotes: true
- parameter_assignments: true
- avoid_function_literals_in_foreach_calls: true
- avoid_returning_null_for_void: true
- avoid_setters_without_getters: true
- avoid_types_on_closure_parameters: true
- avoid_unnecessary_containers: true
- avoid_void_async: true
- camel_case_extensions: true
- camel_case_types: true
- cascade_invocations: true
+ no_literal_bool_comparisons: true
+ prefer_conditional_assignment: true
+ prefer_if_null_operators: true
+ prefer_null_aware_operators: true
+ prefer_null_aware_method_calls: true
+
+ # === READABILITY & MAINTAINABILITY ===
+ # Code organization
+ library_names: true
+ library_prefixes: true
+ file_names: true
+ package_names: true
constant_identifier_names: true
+ non_constant_identifier_names: true
+
+ # Documentation and comments
+ slash_for_doc_comments: true
+ comment_references: true
+ flutter_style_todos: true
+
+ # Code structure
curly_braces_in_flow_control_structures: true
- directives_ordering: true
empty_constructor_bodies: true
- exhaustive_cases: true
- file_names: true
- library_names: true
- library_prefixes: true
- library_private_types_in_public_api: true
- no_leading_underscores_for_library_prefixes: true
- omit_local_variable_types: true
- prefer_adjacent_string_concatenation: true
prefer_collection_literals: true
- prefer_conditional_assignment: true
- prefer_const_constructors: true
- prefer_const_declarations: true
prefer_contains: true
prefer_expression_function_bodies: true
- prefer_final_fields: true
- prefer_final_locals: true
- prefer_final_parameters: true
prefer_foreach: true
prefer_function_declarations_over_variables: true
- prefer_if_null_operators: true
+ prefer_if_elements_to_conditional_expressions: true
prefer_initializing_formals: true
prefer_inlined_adds: true
prefer_interpolation_to_compose_strings: true
prefer_is_empty: true
prefer_is_not_empty: true
prefer_is_not_operator: true
- prefer_mixin: false
- prefer_null_aware_method_calls: true
- prefer_null_aware_operators: true
prefer_spread_collections: true
prefer_typing_uninitialized_variables: true
-analyzer:
- exclude:
- - lib/generated/**
- - lib/translations/**
- - lib/l10n/**
- - lib/**/*.g.dart
- - test/_data/**
- - example/**
- - examples/**
- errors:
- invalid_assignment: warning
- missing_return: error
- dead_code: error
- unused_local_variable: info
- unused_element: info
- unused_field: info
- unused_import: info
- unused_shown_name: info
+ # === MODERN CLEANUP ===
+ # Remove redundancy
+ unnecessary_brace_in_string_interps: true
+ unnecessary_const: true
+ unnecessary_constructor_name: true
+ unnecessary_getters_setters: true
+ unnecessary_lambdas: true
+ unnecessary_late: true
+ unnecessary_new: true
+ unnecessary_overrides: true
+ unnecessary_parenthesis: true
+ unnecessary_raw_strings: true
+ unnecessary_statements: true
+ unnecessary_string_escapes: true
+ unnecessary_string_interpolations: true
+ unnecessary_this: true
+ unnecessary_to_list_in_spreads: true
+
+ # === PROFESSIONAL STANDARDS ===
+ # Trailing commas for better diffs
+ require_trailing_commas: true
+
+ # Parameter organization
+ avoid_positional_boolean_parameters: true
+ avoid_unused_constructor_parameters: true
+
+ # Type safety
+ avoid_equals_and_hash_code_on_mutable_classes: true
+ hash_and_equals: true
+ test_types_in_equals: true
+
+ # === DISABLED RULES (with reasons) ===
+ # Disabled: Conflicting with our style
+ # always_specify_types: false # We prefer type inference where clear
+ # public_member_api_docs: false # Internal packages don't need full docs
+ # avoid_print: false # Useful in development (use debugPrint in production)
+ # lines_longer_than_80_chars: false # We use 120 chars
+ # sort_constructors_first: false # We prefer logical grouping
diff --git a/assets/images/logo.png b/assets/images/logo.png
new file mode 100644
index 0000000..1b78361
Binary files /dev/null and b/assets/images/logo.png differ
diff --git a/example/lib/http_tracking_example.dart b/example/lib/http_tracking_example.dart
index 452113a..623522c 100644
--- a/example/lib/http_tracking_example.dart
+++ b/example/lib/http_tracking_example.dart
@@ -871,11 +871,10 @@ class UsersListPage extends EngineStatelessWidget {
/// Função para demonstrar a inicialização do sistema com tracking HTTP
Future initializeHttpTrackingExample() async {
- // Configuração com tracking HTTP habilitado
final analyticsModel = EngineAnalyticsModel(
firebaseAnalyticsConfig: const EngineFirebaseAnalyticsConfig(enabled: false),
faroConfig: const EngineFaroConfig(
- enabled: true, // Habilitado para capturar requisições HTTP
+ enabled: true,
endpoint: 'https://faro-collector-prod-us-east-0.grafana.net/collect',
appName: 'engine_tracking_http_example',
appVersion: '1.0.0',
@@ -892,12 +891,22 @@ Future initializeHttpTrackingExample() async {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
+ googleLoggingConfig: const EngineGoogleLoggingConfig(
+ enabled: false,
+ projectId: '',
+ logName: '',
+ credentials: {},
+ ),
);
final bugTrackingModel = EngineBugTrackingModel(
crashlyticsConfig: const EngineCrashlyticsConfig(enabled: false),
faroConfig: const EngineFaroConfig(
- enabled: true, // Habilitado para capturar erros HTTP
+ enabled: true,
endpoint: 'https://faro-collector-prod-us-east-0.grafana.net/collect',
appName: 'engine_tracking_http_example',
appVersion: '1.0.0',
@@ -906,9 +915,14 @@ Future initializeHttpTrackingExample() async {
namespace: 'flutter_app',
platform: 'mobile',
),
+ googleLoggingConfig: const EngineGoogleLoggingConfig(
+ enabled: false,
+ projectId: '',
+ logName: '',
+ credentials: {},
+ ),
);
- // Inicializar os sistemas
await EngineAnalytics.initWithModel(analyticsModel);
await EngineBugTracking.initWithModel(bugTrackingModel);
diff --git a/example/lib/main.dart b/example/lib/main.dart
index d97b61b..df23286 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -8,11 +8,17 @@ import 'http_tracking_example.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
- await initializeTracking();
- runApp(const MyApp());
+ final (analyticsModel, bugTrackingModel) = await initializeTracking();
+
+ runApp(
+ EngineWidget(
+ app: const MyApp(),
+ clarityConfig: analyticsModel.clarityConfig,
+ ),
+ );
}
-Future initializeTracking() async {
+Future<(EngineAnalyticsModel analyticsModel, EngineBugTrackingModel bugTrackingModel)> initializeTracking() async {
final faroConfig = EngineFaroConfig(
enabled: true,
endpoint: 'https://faro-collector-prod-sa-east-1.grafana.net/collect/54d9b2d4c4e2a550c890876a914a3525',
@@ -23,7 +29,12 @@ Future initializeTracking() async {
namespace: 'engine.stmr.tech',
platform: Platform.isAndroid ? 'android' : 'ios',
);
- // Configure Analytics
+
+ final clarityConfig = EngineClarityConfig(
+ enabled: true,
+ projectId: 's8nukxh19i',
+ );
+
final analyticsModel = EngineAnalyticsModel(
firebaseAnalyticsConfig: const EngineFirebaseAnalyticsConfig(enabled: false),
faroConfig: faroConfig,
@@ -35,38 +46,50 @@ Future initializeTracking() async {
sourcetype: '',
index: '',
),
+ clarityConfig: clarityConfig,
+ googleLoggingConfig: const EngineGoogleLoggingConfig(
+ enabled: false,
+ projectId: '',
+ logName: '',
+ credentials: {},
+ ),
);
- // Configure Bug Tracking
final bugTrackingModel = EngineBugTrackingModel(
crashlyticsConfig: const EngineCrashlyticsConfig(enabled: false),
faroConfig: faroConfig,
+ googleLoggingConfig: const EngineGoogleLoggingConfig(
+ enabled: false,
+ projectId: '',
+ logName: '',
+ credentials: {},
+ ),
);
try {
- // Initialize services
await Future.wait([
EngineAnalytics.initWithModel(analyticsModel),
EngineBugTracking.initWithModel(bugTrackingModel),
]);
- // Set user information
await Future.wait([
EngineAnalytics.setUserId('demo_user_123', 'demo@example.com', 'Demo User'),
EngineBugTracking.setUserIdentifier('demo_user_123', 'demo@example.com', 'Demo User'),
]);
- // Log app initialization
await EngineAnalytics.logAppOpen();
await EngineBugTracking.log('App initialized successfully', level: 'info');
+
+ return (analyticsModel, bugTrackingModel);
} catch (e, stackTrace) {
- // Log initialization errors
await EngineBugTracking.recordError(
e,
stackTrace,
reason: 'Failed to initialize tracking services',
isFatal: false,
);
+
+ return (EngineAnalyticsModelDefault(), EngineBugTrackingModelDefault());
}
}
@@ -97,7 +120,6 @@ class _HomePageState extends State {
@override
void initState() {
super.initState();
- // Track page view
EngineAnalytics.setPage('HomePage');
}
@@ -106,14 +128,12 @@ class _HomePageState extends State {
_counter++;
});
- // Track button click event
await EngineAnalytics.logEvent('button_clicked', {
'button_name': 'increment_counter',
'counter_value': _counter,
'timestamp': DateTime.now().millisecondsSinceEpoch,
});
- // Log the action
await EngineBugTracking.log(
'Counter incremented',
level: 'info',
@@ -123,10 +143,8 @@ class _HomePageState extends State {
void _simulateError() async {
try {
- // Simulate an error for demonstration
throw Exception('This is a simulated error for testing purposes');
} catch (error, stackTrace) {
- // Record the error
await EngineBugTracking.recordError(
error,
stackTrace,
@@ -136,7 +154,6 @@ class _HomePageState extends State {
data: {'counter_value': _counter, 'error_type': 'simulated'},
);
- // Show snackbar to user
if (mounted) {
ScaffoldMessenger.of(
context,
@@ -199,7 +216,6 @@ class _HomePageState extends State {
Text('$_counter', style: Theme.of(context).textTheme.headlineMedium),
const SizedBox(height: 40),
- // Service Status
Card(
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Padding(
@@ -218,7 +234,6 @@ class _HomePageState extends State {
const SizedBox(height: 20),
- // Action Buttons
Wrap(
spacing: 10,
runSpacing: 10,
@@ -286,7 +301,6 @@ class _SecondPageState extends State {
@override
void initState() {
super.initState();
- // Track page view with previous screen
EngineAnalytics.setPage('SecondPage', 'HomePage');
}
diff --git a/example/lib/view_tracking_example.dart b/example/lib/view_tracking_example.dart
index 631487e..1531704 100644
--- a/example/lib/view_tracking_example.dart
+++ b/example/lib/view_tracking_example.dart
@@ -483,7 +483,6 @@ class _ShoppingCartPageState extends EngineStatefulWidgetState
/// Função para demonstrar a inicialização do sistema
Future initializeTrackingExample() async {
- // Configuração básica do Analytics
final analyticsModel = EngineAnalyticsModel(
firebaseAnalyticsConfig: const EngineFirebaseAnalyticsConfig(enabled: false),
faroConfig: const EngineFaroConfig(
@@ -504,9 +503,18 @@ Future initializeTrackingExample() async {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
+ googleLoggingConfig: const EngineGoogleLoggingConfig(
+ enabled: false,
+ projectId: '',
+ logName: '',
+ credentials: {},
+ ),
);
- // Configuração básica do Bug Tracking
final bugTrackingModel = EngineBugTrackingModel(
crashlyticsConfig: const EngineCrashlyticsConfig(enabled: false),
faroConfig: const EngineFaroConfig(
@@ -519,9 +527,14 @@ Future initializeTrackingExample() async {
namespace: '',
platform: '',
),
+ googleLoggingConfig: const EngineGoogleLoggingConfig(
+ enabled: false,
+ projectId: '',
+ logName: '',
+ credentials: {},
+ ),
);
- // Inicializar os sistemas
await EngineAnalytics.initWithModel(analyticsModel);
await EngineBugTracking.initWithModel(bugTrackingModel);
diff --git a/lib/src/analytics/adapters/engine_firebase_analytics_adapter.dart b/lib/src/analytics/adapters/engine_firebase_analytics_adapter.dart
index 0bc0337..bcc3dfd 100644
--- a/lib/src/analytics/adapters/engine_firebase_analytics_adapter.dart
+++ b/lib/src/analytics/adapters/engine_firebase_analytics_adapter.dart
@@ -108,7 +108,7 @@ class EngineFirebaseAnalyticsAdapter implements IEngineAnalyticsAdapter {
await _firebaseAnalytics?.logScreenView(
screenName: screenName,
- screenClass: enrichedParameters?['screen_class'] ?? 'Flutter',
+ screenClass: enrichedParameters?['screen_class']?.toString() ?? 'Flutter',
parameters: enrichedParameters?.map(
(final k, final v) => MapEntry(k, v as Object),
),
diff --git a/lib/src/analytics/adapters/engine_splunk_analytics_adapter.dart b/lib/src/analytics/adapters/engine_splunk_analytics_adapter.dart
index 9a3ba89..4786f14 100644
--- a/lib/src/analytics/adapters/engine_splunk_analytics_adapter.dart
+++ b/lib/src/analytics/adapters/engine_splunk_analytics_adapter.dart
@@ -161,7 +161,6 @@ class EngineSplunkAnalyticsAdapter implements IEngineAnalyticsAdapter {
try {
await _sendToSplunk({
'event': 'analytics_reset',
- 'data': {},
'timestamp': DateTime.now().millisecondsSinceEpoch / 1000,
});
} catch (e) {
@@ -186,6 +185,6 @@ class EngineSplunkAnalyticsAdapter implements IEngineAnalyticsAdapter {
request.write(body);
final response = await request.close();
- await response.drain();
+ await response.drain>();
}
}
diff --git a/lib/src/bug_tracking/adapters/engine_faro_bug_tracking_adapter.dart b/lib/src/bug_tracking/adapters/engine_faro_bug_tracking_adapter.dart
index dee6f04..f6914dc 100644
--- a/lib/src/bug_tracking/adapters/engine_faro_bug_tracking_adapter.dart
+++ b/lib/src/bug_tracking/adapters/engine_faro_bug_tracking_adapter.dart
@@ -69,9 +69,6 @@ class EngineFaroBugTrackingAdapter implements IEngineBugTrackingAdapter {
debugPrint('setCustomKey: Faro Bug Tracking is not initialized');
return;
}
-
- // Faro doesn't have a direct equivalent for custom keys
- // We can use context for similar functionality
}
@override
diff --git a/lib/src/config/config.dart b/lib/src/config/config.dart
index 1dbef77..1b665ed 100644
--- a/lib/src/config/config.dart
+++ b/lib/src/config/config.dart
@@ -1,3 +1,4 @@
+export 'engine_clarity_config.dart';
export 'engine_crashlytics_config.dart';
export 'engine_faro_config.dart';
export 'engine_firebase_analytics_config.dart';
diff --git a/lib/src/config/engine_clarity_config.dart b/lib/src/config/engine_clarity_config.dart
new file mode 100644
index 0000000..5e0739a
--- /dev/null
+++ b/lib/src/config/engine_clarity_config.dart
@@ -0,0 +1,16 @@
+class EngineClarityConfig {
+ const EngineClarityConfig({
+ required this.enabled,
+ required this.projectId,
+ this.userId,
+ });
+
+ final bool enabled;
+
+ final String projectId;
+
+ final String? userId;
+
+ @override
+ String toString() => 'EngineClarityConfig(enabled: $enabled, projectId: *****, userId: *****)';
+}
diff --git a/lib/src/config/engine_firebase_analytics_config.dart b/lib/src/config/engine_firebase_analytics_config.dart
index d120303..6939de0 100644
--- a/lib/src/config/engine_firebase_analytics_config.dart
+++ b/lib/src/config/engine_firebase_analytics_config.dart
@@ -5,12 +5,4 @@ class EngineFirebaseAnalyticsConfig {
@override
String toString() => 'EngineFirebaseAnalyticsConfig(enabled: $enabled)';
-
- @override
- bool operator ==(final Object other) =>
- identical(this, other) ||
- other is EngineFirebaseAnalyticsConfig && runtimeType == other.runtimeType && enabled == other.enabled;
-
- @override
- int get hashCode => enabled.hashCode;
}
diff --git a/lib/src/config/engine_splunk_config.dart b/lib/src/config/engine_splunk_config.dart
index 761af45..cf7c7d0 100644
--- a/lib/src/config/engine_splunk_config.dart
+++ b/lib/src/config/engine_splunk_config.dart
@@ -18,20 +18,4 @@ class EngineSplunkConfig {
@override
String toString() =>
'EngineSplunkConfig(enabled: $enabled, endpoint: $endpoint, source: $source, sourcetype: $sourcetype, index: $index, token: ****)';
-
- @override
- bool operator ==(final Object other) =>
- identical(this, other) ||
- other is EngineSplunkConfig &&
- runtimeType == other.runtimeType &&
- enabled == other.enabled &&
- endpoint == other.endpoint &&
- token == other.token &&
- source == other.source &&
- sourcetype == other.sourcetype &&
- index == other.index;
-
- @override
- int get hashCode =>
- enabled.hashCode ^ endpoint.hashCode ^ token.hashCode ^ source.hashCode ^ sourcetype.hashCode ^ index.hashCode;
}
diff --git a/lib/src/models/engine_analytics_model.dart b/lib/src/models/engine_analytics_model.dart
index 52ca64f..5015e41 100644
--- a/lib/src/models/engine_analytics_model.dart
+++ b/lib/src/models/engine_analytics_model.dart
@@ -1,3 +1,4 @@
+import 'package:engine_tracking/src/config/engine_clarity_config.dart';
import 'package:engine_tracking/src/config/engine_faro_config.dart';
import 'package:engine_tracking/src/config/engine_firebase_analytics_config.dart';
import 'package:engine_tracking/src/config/engine_google_logging_config.dart';
@@ -5,12 +6,14 @@ import 'package:engine_tracking/src/config/engine_splunk_config.dart';
class EngineAnalyticsModel {
EngineAnalyticsModel({
+ required this.clarityConfig,
required this.firebaseAnalyticsConfig,
required this.faroConfig,
required this.googleLoggingConfig,
required this.splunkConfig,
});
+ final EngineClarityConfig clarityConfig;
final EngineFirebaseAnalyticsConfig firebaseAnalyticsConfig;
final EngineFaroConfig faroConfig;
final EngineGoogleLoggingConfig googleLoggingConfig;
@@ -18,10 +21,13 @@ class EngineAnalyticsModel {
@override
String toString() =>
- 'EngineAnalyticsModel(firebaseAnalyticsConfig: $firebaseAnalyticsConfig, faroConfig: $faroConfig, googleLoggingConfig: $googleLoggingConfig, splunkConfig: $splunkConfig)';
+ 'EngineAnalyticsModel(clarityConfig: $clarityConfig, firebaseAnalyticsConfig: $firebaseAnalyticsConfig, faroConfig: $faroConfig, googleLoggingConfig: $googleLoggingConfig, splunkConfig: $splunkConfig)';
}
class EngineAnalyticsModelDefault implements EngineAnalyticsModel {
+ @override
+ EngineClarityConfig get clarityConfig => const EngineClarityConfig(enabled: false, projectId: '');
+
@override
EngineFirebaseAnalyticsConfig get firebaseAnalyticsConfig => const EngineFirebaseAnalyticsConfig(enabled: false);
diff --git a/lib/src/session/engine_session.dart b/lib/src/session/engine_session.dart
index 1f7ef37..d4dba39 100644
--- a/lib/src/session/engine_session.dart
+++ b/lib/src/session/engine_session.dart
@@ -8,30 +8,21 @@ class EngineSession {
String? _sessionId;
- // Getter público - único ponto de acesso
String get sessionId => _sessionId ??= _generateUUID();
- // Gerador de string hexadecimal privado
String _generateHex(final int length) {
final random = Random();
const chars = '0123456789abcdef';
return List.generate(length, (final index) => chars[random.nextInt(chars.length)]).join();
}
- // Gerador UUID v4 padrão
String _generateUUID() {
final random = Random();
- // UUID v4 formato: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
- // Onde:
- // - 13º caractere é sempre "4" (versão)
- // - 17º caractere é sempre "8", "9", "a" ou "b" (variant)
-
final part1 = _generateHex(8);
final part2 = _generateHex(4);
- final part3 = '4${_generateHex(3)}'; // Versão 4
+ final part3 = '4${_generateHex(3)}';
- // Para a parte 4, primeiro caractere deve ser 8, 9, a ou b
const variantChars = '89ab';
final variantChar = variantChars[random.nextInt(variantChars.length)];
final part4 = '$variantChar${_generateHex(3)}';
@@ -41,14 +32,12 @@ class EngineSession {
return '$part1-$part2-$part3-$part4-$part5';
}
- // Método para enriquecer eventos automaticamente
Map? enrichWithSessionId(final Map? data) {
final enriched = {...?data};
enriched['session_id'] = sessionId;
return enriched;
}
- // Método para reset - usado apenas em testes
static void resetForTesting() {
_instance = null;
}
diff --git a/lib/src/widgets/engine_mask_widget.dart b/lib/src/widgets/engine_mask_widget.dart
new file mode 100644
index 0000000..a5d3267
--- /dev/null
+++ b/lib/src/widgets/engine_mask_widget.dart
@@ -0,0 +1,59 @@
+import 'package:clarity_flutter/clarity_flutter.dart';
+import 'package:flutter/material.dart';
+
+/// Widget to mask sensitive content in recordings
+///
+/// Use this widget to wrap elements that contain sensitive information
+/// that should not appear in recorded sessions.
+///
+/// Example:
+/// ```dart
+/// EngineMaskWidget(
+/// child: Text('Sensitive information'),
+/// )
+/// ```
+class EngineMaskWidget extends StatelessWidget {
+ const EngineMaskWidget({
+ super.key,
+ required this.child,
+ });
+
+ final Widget child;
+
+ @override
+ Widget build(final BuildContext context) => ClarityMask(
+ child: child,
+ );
+}
+
+/// Widget to unmask content within a masked area
+///
+/// Use this widget when you need to show specific content
+/// within an area that has been masked with EngineMaskWidget.
+///
+/// Example:
+/// ```dart
+/// EngineMaskWidget(
+/// child: Column(
+/// children: [
+/// Text('Sensitive information'),
+/// EngineUnmaskWidget(
+/// child: Text('Non-sensitive information'),
+/// ),
+/// ],
+/// ),
+/// )
+/// ```
+class EngineUnmaskWidget extends StatelessWidget {
+ const EngineUnmaskWidget({
+ super.key,
+ required this.child,
+ });
+
+ final Widget child;
+
+ @override
+ Widget build(final BuildContext context) => ClarityUnmask(
+ child: child,
+ );
+}
diff --git a/lib/src/widgets/engine_stateful_widget.dart b/lib/src/widgets/engine_stateful_widget.dart
index 342d8c1..22285f1 100644
--- a/lib/src/widgets/engine_stateful_widget.dart
+++ b/lib/src/widgets/engine_stateful_widget.dart
@@ -3,31 +3,6 @@ import 'dart:async';
import 'package:engine_tracking/engine_tracking.dart';
import 'package:flutter/widgets.dart';
-/// class for StatefulWidget with automatic tracking functionalities
-///
-/// Usage:
-/// ```dart
-/// class MinhaTelaPage extends EngineStatefulWidget {
-/// const MinhaTelaPage({super.key});
-///
-/// @override
-/// EngineStatefulWidgetState createState() => _MinhaTelaPageState();
-/// }
-///
-/// class _MinhaTelaPageState extends EngineStatefulWidgetState {
-/// @override
-/// Widget buildWithTracking(BuildContext context) {
-/// return Scaffold(
-/// body: Center(
-/// child: ElevatedButton(
-/// onPressed: () => logUserAction('botao_clicado'),
-/// child: Text('Clique aqui'),
-/// ),
-/// ),
-/// );
-/// }
-/// }
-/// ```
abstract class EngineStatefulWidget extends StatefulWidget {
const EngineStatefulWidget({super.key});
@@ -35,22 +10,17 @@ abstract class EngineStatefulWidget extends StatefulWidget {
EngineStatefulWidgetState createState();
}
-/// state for StatefulWidget with automatic tracking functionalities
abstract class EngineStatefulWidgetState extends State {
EngineStatefulWidgetState() {
_screenOpenTime = DateTime.now();
}
- /// Screen name for tracking. By default uses the class name
String get screenName => runtimeType.toString();
- /// Additional parameters to send in screen tracking
Map? get screenParameters => null;
- /// Whether to automatically track screen views
bool get enableAutoTracking => true;
- /// Whether to automatically track lifecycle events
bool get enableLifecycleTracking => true;
late final DateTime _screenOpenTime;
@@ -72,7 +42,6 @@ abstract class EngineStatefulWidgetState extends
}
if (enableAutoTracking) {
- // Execute screen tracking after the first frame
WidgetsBinding.instance.addPostFrameCallback((_) async {
await _trackScreenView();
});
@@ -98,14 +67,11 @@ abstract class EngineStatefulWidgetState extends
super.dispose();
}
- /// Builds the widget with automatic tracking
@override
Widget build(final BuildContext context) => buildWithTracking(context);
- /// Method that should be implemented instead of the original build
Widget buildWithTracking(final BuildContext context);
- /// Tracks the screen view
Future _trackScreenView() async {
await EngineLog.debug(
'screen_viewed',
@@ -117,7 +83,6 @@ abstract class EngineStatefulWidgetState extends
);
}
- /// Logs a user action on the current screen
Future logUserAction(
final String action, {
final Map? parameters,
@@ -135,7 +100,6 @@ abstract class EngineStatefulWidgetState extends
);
}
- /// Logs a custom event on the current screen
Future logCustomEvent(
final String eventName, {
final Map? parameters,
@@ -153,7 +117,6 @@ abstract class EngineStatefulWidgetState extends
);
}
- /// Logs a screen-specific error
Future logScreenError(
final String reason, {
final Object? exception,
@@ -174,7 +137,6 @@ abstract class EngineStatefulWidgetState extends
);
}
- /// Logs a state change on the screen
Future logStateChange(
final String stateDescription, {
final Map? additionalData,
diff --git a/lib/src/widgets/engine_widget.dart b/lib/src/widgets/engine_widget.dart
new file mode 100644
index 0000000..665df35
--- /dev/null
+++ b/lib/src/widgets/engine_widget.dart
@@ -0,0 +1,29 @@
+import 'package:clarity_flutter/clarity_flutter.dart';
+import 'package:engine_tracking/src/config/engine_clarity_config.dart';
+import 'package:flutter/material.dart';
+
+class EngineWidget extends StatelessWidget {
+ const EngineWidget({
+ required this.app,
+ required this.clarityConfig,
+ super.key,
+ });
+
+ final Widget app;
+ final EngineClarityConfig clarityConfig;
+
+ @override
+ Widget build(final BuildContext context) {
+ if (clarityConfig.enabled) {
+ return ClarityWidget(
+ app: app,
+ clarityConfig: ClarityConfig(
+ projectId: clarityConfig.projectId,
+ userId: clarityConfig.userId,
+ logLevel: LogLevel.Verbose,
+ ),
+ );
+ }
+ return app;
+ }
+}
diff --git a/lib/src/widgets/widgets.dart b/lib/src/widgets/widgets.dart
index 037b665..2f9d110 100644
--- a/lib/src/widgets/widgets.dart
+++ b/lib/src/widgets/widgets.dart
@@ -1,2 +1,4 @@
+export 'engine_mask_widget.dart';
export 'engine_stateful_widget.dart';
export 'engine_stateless_widget.dart';
+export 'engine_widget.dart';
diff --git a/pubspec.yaml b/pubspec.yaml
index e16a241..b5e3a5a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: engine_tracking
description: Plugin Flutter para tracking, analytics, crashlytics e logs do Engine Framework
-version: 1.3.0
+version: 1.4.0
homepage: https://stmr.tech
repository: https://github.com/moreirawebmaster/engine-tracking
issue_tracker: https://github.com/moreirawebmaster/engine-tracking/issues
@@ -16,6 +16,10 @@ topics:
- crashlytics
- logging
+screenshots:
+ - description: "Engine Tracking Logo"
+ path: assets/images/logo.png
+
platforms:
android:
ios:
@@ -33,6 +37,7 @@ dependencies:
faro: ^0.3.6
googleapis: ^14.0.0
googleapis_auth: ^2.0.0
+ clarity_flutter: ^1.0.0
dev_dependencies:
flutter_test:
diff --git a/test/analytics/engine_analytics_test.dart b/test/analytics/engine_analytics_test.dart
index 10257a1..d3c3be5 100644
--- a/test/analytics/engine_analytics_test.dart
+++ b/test/analytics/engine_analytics_test.dart
@@ -66,6 +66,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
@@ -96,6 +100,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
@@ -125,6 +133,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
@@ -154,6 +166,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
@@ -183,6 +199,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
@@ -212,6 +232,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
@@ -241,6 +265,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
@@ -271,6 +299,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
@@ -300,6 +332,10 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
await EngineAnalytics.initWithModel(model);
diff --git a/test/bug_tracking/engine_bug_tracking_test.dart b/test/bug_tracking/engine_bug_tracking_test.dart
index ce75454..203391b 100644
--- a/test/bug_tracking/engine_bug_tracking_test.dart
+++ b/test/bug_tracking/engine_bug_tracking_test.dart
@@ -6,9 +6,7 @@ import '../helpers/test_configs.dart';
void main() {
group('EngineBugTracking', () {
- setUp(() {
- EngineBugTracking.reset();
- });
+ setUp(EngineBugTracking.reset);
group('Initialization', () {
test('should reset properly', () {
diff --git a/test/models/engine_analytics_model_test.dart b/test/models/engine_analytics_model_test.dart
index 848e3c7..80dcdaa 100644
--- a/test/models/engine_analytics_model_test.dart
+++ b/test/models/engine_analytics_model_test.dart
@@ -25,18 +25,24 @@ void main() {
sourcetype: 'json',
index: 'main',
);
+ const clarityConfig = EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ );
final model = EngineAnalyticsModel(
firebaseAnalyticsConfig: firebaseConfig,
faroConfig: faroConfig,
googleLoggingConfig: TestConfigs.googleLoggingConfigEnabled,
splunkConfig: splunkConfig,
+ clarityConfig: clarityConfig,
);
expect(model.firebaseAnalyticsConfig, equals(firebaseConfig));
expect(model.faroConfig, equals(faroConfig));
expect(model.googleLoggingConfig, equals(TestConfigs.googleLoggingConfigEnabled));
expect(model.splunkConfig, equals(splunkConfig));
+ expect(model.clarityConfig, equals(clarityConfig));
});
test('should not be equal to different types', () {
@@ -65,6 +71,10 @@ void main() {
faroConfig: faroConfig,
googleLoggingConfig: TestConfigs.googleLoggingConfig,
splunkConfig: splunkConfig,
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
expect(model, isNot(equals('string')));
@@ -98,6 +108,10 @@ void main() {
faroConfig: faroConfig,
googleLoggingConfig: TestConfigs.googleLoggingConfigEnabled,
splunkConfig: splunkConfig,
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
);
final stringRepresentation = model.toString();
@@ -106,6 +120,7 @@ void main() {
expect(stringRepresentation, contains('faroConfig'));
expect(stringRepresentation, contains('googleLoggingConfig'));
expect(stringRepresentation, contains('splunkConfig'));
+ expect(stringRepresentation, contains('clarityConfig'));
});
});
diff --git a/test/session/engine_session_test.dart b/test/session/engine_session_test.dart
index 7e29e2e..0aa9406 100644
--- a/test/session/engine_session_test.dart
+++ b/test/session/engine_session_test.dart
@@ -3,10 +3,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
group('EngineSession', () {
- setUp(() {
- // Reset instance para cada teste usando método público
- EngineSession.resetForTesting();
- });
+ setUp(EngineSession.resetForTesting);
test('should generate unique session IDs', () {
final session1 = EngineSession.instance.sessionId;
diff --git a/test/test_coverage.dart b/test/test_coverage.dart
index ac1b1ec..7a44116 100644
--- a/test/test_coverage.dart
+++ b/test/test_coverage.dart
@@ -66,10 +66,14 @@ void main() {
sourcetype: '',
index: '',
),
+ clarityConfig: const EngineClarityConfig(
+ enabled: false,
+ projectId: '',
+ ),
),
returnsNormally,
);
- expect(() => EngineAnalyticsModelDefault(), returnsNormally);
+ expect(EngineAnalyticsModelDefault.new, returnsNormally);
// Bug Tracking
expect(() => const EngineCrashlyticsConfig(enabled: true), returnsNormally);
@@ -90,7 +94,7 @@ void main() {
),
returnsNormally,
);
- expect(() => EngineBugTrackingModelDefault(), returnsNormally);
+ expect(EngineBugTrackingModelDefault.new, returnsNormally);
});
test('should have static methods available', () {