frosty/lib/apis/dio_client.dart
Tommy Chow 6ede000c66 improve Firebase integration across Crashlytics, Analytics, and Performance
- Fix cold-start privacy bug: apply persisted collection preference on launch
- Disable Firebase collection in debug builds to avoid polluting prod data
- Add Crashlytics custom keys (is_logged_in, channel), user identifier, and
  WebSocket reconnection breadcrumbs for actionable crash reports
- Record non-fatal errors for server failures, WebSocket errors, and global
  asset fetch failures (skip timeouts/network errors to avoid noise)
- Update is_logged_in key and user identifier on login/logout transitions
- Log auth reconnection exhaustion before forced logout
- Add FirebaseAnalyticsObserver with named routes for automatic screen tracking
- Add static routeName constants to avoid duplicated string literals
- Add Firebase Performance Dio interceptor for automatic HTTP request tracing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 00:18:21 -08:00

71 lines
2.4 KiB
Dart

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:frosty/apis/firebase_performance_interceptor.dart';
/// Centralized Dio client configuration with interceptors and error handling
class DioClient {
static Dio createClient({List<Interceptor>? additionalInterceptors}) {
final dio = Dio();
// Optimized configuration based on 2024-2025 best practices
dio.options = BaseOptions(
connectTimeout: const Duration(
seconds: 8,
), // Balanced for various networks
receiveTimeout: const Duration(
seconds: 15,
), // Allow for larger API responses
sendTimeout: const Duration(seconds: 10), // Reasonable for uploads
headers: {
'User-Agent': 'Frosty (Flutter Twitch Client)',
'Accept': 'application/json',
'Content-Type': 'application/json',
'Connection': 'keep-alive', // Enable connection reuse
},
followRedirects: true,
maxRedirects: 3, // Reduced for better performance
persistentConnection: true, // Enable connection pooling
);
// Simple logging for debug builds
if (kDebugMode) {
dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
debugPrint('→ ${options.method} ${options.uri}');
handler.next(options);
},
onResponse: (response, handler) {
final statusCode = response.statusCode ?? 0;
final emoji = statusCode >= 200 && statusCode < 300 ? '✅' : '❌';
debugPrint(
'$emoji ${response.statusCode} ${response.requestOptions.method} ${response.requestOptions.uri}',
);
handler.next(response);
},
onError: (error, handler) {
debugPrint(
'❌ ${error.type.name} ${error.requestOptions.method} ${error.requestOptions.uri}',
);
if (error.response != null) {
debugPrint(' Status: ${error.response!.statusCode}');
}
handler.next(error);
},
),
);
}
// Trace HTTP requests as Firebase Performance metrics
dio.interceptors.add(FirebasePerformanceInterceptor());
// Add any additional interceptors provided
if (additionalInterceptors != null) {
for (final interceptor in additionalInterceptors) {
dio.interceptors.add(interceptor);
}
}
return dio;
}
}