Debug Flutter en production : le guide ultime pour diagnostiquer les erreurs
Debugguer Flutter en local est facile. Debugguer en production en est une autre affaire : obfuscation, symbolication, crash groups, redéploiement, performance tracing, alertes et post-mortem. Ce guide ultime couvre toutes les techniques pour diagnostiquer les erreurs Flutter en production en 2026, avec des exemples de code, des case studies réels, et l'intégration de SnapLogs pour un workflow complet d'incident response.
SnapLogs Team
Équipe produit

Debug Flutter en production : le guide ultime pour diagnostiquer les erreurs
Debugguer Flutter sur son simulateur avec un hot reload est une expérience fluide. Debugguer en production, sur 100k devices hétérogènes, sans accès direct, est un autre sport. Ce guide ultime couvre toutes les techniques pour diagnostiquer les erreurs Flutter en production en 2026 : release mode, obfuscation, symbolication, crash groups, performance tracing, alertes, et workflow post-mortem.
Les défis du debug Flutter en production
Le debug local et le debug production diffèrent sur six dimensions.
| Dimension | Local | Production | | --- | --- | --- | | Accès device | Direct (simulateur) | Aucun | | Stack trace | Lisible | Obfusquée | | Logs | debugPrint visibles | Disparaissent | | Reproduction | Trivial | Rarement possible | | Volume | 1 device | 100k devices | | Contexte | Hot reload | Build figé |
En production, vous n'avez accès qu'à ce que votre app décide de remonter. Le socle est donc : instrumenter avant le bug, pas après.
Comprendre les modes de build Flutter
Flutter a trois modes :
- debug : assertions activées, hot reload, stack traces lisibles, pas d'obfuscation.
- profile : pas d'assertions, pas de hot reload, perfs réalistes, stack traces lisibles.
- release : obfuscation, tree-shaking, pas de logs, stack traces obfusquées.
flutter run # debug
flutter run --profile # profile
flutter run --release # release
flutter build apk --release # release build
Le mode release est celui que vos utilisateurs vivent. Testez toujours votre instrumentation en release avant de déployer.
Obfuscation et symbolication
Ce que fait l'obfuscation
En release, Flutter obfusque les noms de classes, méthodes et variables. La stack trace devient :
package:app/main.dart:0x4a3b2c1
package:app/payment.dart:0x7f8e9d2
au lieu de :
package:app/main.dart:42
package:app/payment.dart:128
Sans symbolication, la stack est inutilisable.
Générer les symbols map
Lors du build release, générez les symbols :
flutter build apk --release --obfuscate --split-debug-info=./build/symbols
Cela crée un dossier ./build/symbols/ avec un fichier par target (arm64-v8a, armeabi-v7a, x86_64). Conservez ces fichiers : sans eux, la symbolication est impossible.
Symbolication côté serveur
SnapLogs et Sentry symbolisent les stacks côté serveur si vous uploadez les symbols. Configuration SnapLogs :
# snaplogs.yaml
upload_symbols: true
symbols_path: ./build/symbols
À chaque release, le CLI SnapLogs upload les symbols :
npx snaplogs symbols upload --path=./build/symbols --version=1.4.2
Les stacks reçues sont symbolisées automatiquement. Vous voyez payment.dart:128 au lieu de 0x7f8e9d2.
Symbolication manuelle
Si vous n'avez pas uploadé, vous pouvez symboliser localement :
flutter symbolize -i stack.txt -d ./build/symbols
Où stack.txt contient la stack obfusquée. Utile pour un crash ponctuel.
Crash groups : trier et prioriser
Un crash peut générer 1000 tickets. Il faut grouper.
Groupage par signature
Les crash reporters groupent par signature de stack trace. SnapLogs et Sentry le font automatiquement. Les stacks avec le même premier frame sont groupées.
Groupage par fingerprint personnalisé
Parfois, des crashs avec stacks différentes ont la même cause métier. Forcez un fingerprint :
await SnapLogs.captureException(
e,
stackTrace: st,
fingerprint: ['payment', 'charge', 'provider_declined'],
);
Tous les crashs avec ce fingerprint sont groupés, indépendamment de la stack.
Priorisation
Priorisez par :
- Volume : 10k crashes > 10 crashes.
- Impact : crash sur payment > crash sur settings.
- Récurrence : crash persistant sur 5 versions > crash ponctuel.
Un crash à 10k occurrences sur le flow payment est P0. Un crash à 3 occurrences sur settings est P3.

Le volume de crashs par jour permet d'identifier les pics et de mesurer l'impact d'un deploy. Un pic soudain = regression.
Error monitoring en production
Capture des erreurs
Configurez les trois points de capture :
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:snaplogs/snaplogs.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await SnapLogs.init(
apiKey: const String.fromEnvironment('SNAPLOGS_KEY'),
environment: 'production',
sampleRate: 0.05,
errorSampleRate: 1.0,
);
// 1. Erreurs framework
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.presentError(details);
SnapLogs.captureException(details.exception, stackTrace: details.stack);
};
// 2. Erreurs async hors framework
runZonedGuarded<Future<void>>(() async {
runApp(const MyApp());
}, (Object error, StackTrace stack) {
SnapLogs.captureException(error, stackTrace: stack);
});
// 3. Erreurs d'isolate
Isolate.current.addErrorListener(
RawReceivePort((dynamic pair) {
final List<dynamic> data = pair as List<dynamic>;
SnapLogs.captureException(
data.first as Object,
stackTrace: data.last as StackTrace,
);
}).sendPort,
);
}
Sans ces trois, vous ratez une partie des crashes.
Filtrage du bruit
Certaines erreurs ne méritent pas un ticket. Utilisez beforeSend :
await SnapLogs.init(
apiKey: key,
beforeSend: (event) {
if (event.tags['flow'] == 'health_check') return null;
if (event.message.contains('SocketException')) return null;
return event;
},
);
Breadcrumbs automatiques
SnapLogs capture automatiquement :
- Taps (
onTap,onPressed). - Navigations (
push,pop). - Requêtes réseau (
http.get,http.post).
Ces breadcrumbs sont attachés au crash. Vous voyez la timeline :
T 12:04:31 TAP "Login"
T 12:04:31 NAV push /dashboard
T 12:04:32 NET POST /auth/token → 200
T 12:04:34 NAV push /payments
T 12:04:35 TAP "Pay"
T 12:04:35 NET POST /payments/charge → 500
T 12:04:35 ERR PaymentException
Le dev voit immédiatement : le token a expiré entre login et payment.
Performance tracing en production
Mesurer le jank
Le jank (frame qui met >16ms à rendre) est invisible dans les crashs. Utilisez :
- Flutter DevTools en profile mode pendant le dev.
- Firebase Performance en production.
- Sentry Performance en production.
SnapLogs ne fait pas de perf monitoring mais capture les breadcrumbs qui aident à identifier les écrans lents (ex : tous les crashes surviennent après /dashboard qui met 3s à charger).
Tracer les écrans lents
Instrumentez vos écrans :
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key});
@override
State<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> {
DateTime? _loadStart;
@override
void initState() {
super.initState();
_loadStart = DateTime.now();
_loadData();
}
Future<void> _loadData() async {
try {
await fetchDashboard();
} finally {
final duration = DateTime.now().difference(_loadStart!);
SnapLogs.log(
level: LogLevel.info,
message: 'dashboard_loaded',
fields: {'duration_ms': duration.inMilliseconds},
);
if (duration.inMilliseconds > 2000) {
SnapLogs.log(
level: LogLevel.warning,
message: 'dashboard_slow',
fields: {'duration_ms': duration.inMilliseconds},
);
}
}
}
@override
Widget build(BuildContext context) => const Scaffold(body: Center(child: Text('Dashboard')));
}
Vous pouvez ensuite filtrer les dashboards >2s dans SnapLogs et investiguer.
Tracer les appels réseau
import 'package:http/http.dart' as http;
Future<void> tracedGet(String url) async {
final start = DateTime.now();
try {
final response = await http.get(Uri.parse(url));
final duration = DateTime.now().difference(start);
SnapLogs.log(
level: LogLevel.info,
message: 'http_get',
fields: {
'url': url,
'status': response.statusCode,
'duration_ms': duration.inMilliseconds,
},
);
if (duration.inMilliseconds > 1000) {
SnapLogs.log(
level: LogLevel.warning,
message: 'http_slow',
fields: {'url': url, 'duration_ms': duration.inMilliseconds},
);
}
} catch (e, st) {
SnapLogs.log(
level: LogLevel.error,
message: 'http_error',
fields: {'url': url},
error: e,
stackTrace: st,
);
rethrow;
}
}
DevTools en production : limites et alternatives
Flutter DevTools est conçu pour le dev local. En production, vous ne pouvez pas brancher DevTools sur le device d'un user. Alternatives :
- SnapLogs dashboard : les breadcrumbs et logs remplacent le widget inspector.
- Sentry replay : rejoue la session utilisateur (beta).
- Firebase Remote Config : active des flags de debug à distance.
Pour les rares cas où vous pouvez demander à un user de brancher son téléphone (beta test), utilisez flutter attach :
flutter attach --app-id com.example.app
Mais cela reste exceptionnel.
Alertes et incident response
Configurer les alertes
SnapLogs alerte sur :
- Pic d'erreurs (ex : >100 erreurs/5min).
- Nouveau type de crash (signature inconnue).
- Erreur P0 (fingerprint taggé
p0).
Configuration Slack :
# snaplogs.yaml
alerts:
- name: error_spike
condition: error_rate > 1%
channel: "#alerts-prod"
- name: new_crash
condition: new_signature
channel: "#alerts-prod"
- name: p0
condition: tag == "p0"
channel: "#alerts-p0"
Workflow d'incident response
Voici le workflow recommandé pour une équipe mature.
- Détection : alerte Slack / on-call paging.
- Triage : qualifier la sévérité (P0 à P3).
- Investigation : ouvrir le crash dans SnapLogs, lire les breadcrumbs.
- Mitigation : rollback, feature flag, hotfix.
- Communication : status page, message aux users.
- Résolution : fix, test, deploy.
- Post-mortem : doc rédigé dans les 72h.
Exemple d'alerte Slack
{
"severity": "P0",
"title": "Payment crash spike",
"count": 234,
"window": "5min",
"fingerprint": "payment_charge_provider_declined",
"last_stack": "package:app/payment.dart:128",
"dashboard_url": "https://app.snaplogs.pro/incidents/abc123"
}
Workflow post-mortem
Le post-mortem est obligatoire pour tout incident P0/P1. Template :
### Incident : Payment crash spike 2026-08-09
### Impact
- 234 users affectés
- ~12k€ de revenu perdu
- 4h de downtime partiel
### Timeline
- 11:03 : premier crash
- 11:08 : alerte Slack
- 11:10 : on-call ack
- 11:15 : investigation, root cause identifiée
- 11:30 : feature flag désactivé
- 11:45 : hotfix déployé
- 12:00 : résolution
### Root cause
Le provider de paiement a changé son API sans notice.
Le champs `currency` est devenu obligatoire.
Notre code ne l'envoyait pas pour EUR (défaut).
### Fix
- Ajout du champs currency dans tous les calls.
- Test ajouté (payment_eur_test.dart).
- Alert ajoutée sur tout 500 provider.
### Lessons
- Toujours logger le payload envoyé au provider (censuré).
- Ajouter un contract test sur l'API provider.
- Monitorer les 500 provider comme des P1.
Redéploiement et rollback
Hotfix
Pour un hotfix Flutter :
git checkout -b hotfix/payment-currency
# fix
flutter test
flutter build apk --release --obfuscate --split-debug-info=./build/symbols
npx snaplogs symbols upload --path=./build/symbols --version=1.4.3
# deploy
N'oubliez pas d'uploader les symbols : sinon les nouveaux crashes ne seront pas symbolisables.
Rollback
Si le hotfix aggrave, rollback à la version N-1 :
# Play Store : rollback via console
# App Store : pas de rollback, mais on peut expedier l'ancienne version en review express
Préparez toujours un rollback avant de déployer un hotfix sur un flux critique.
Feature flags
Le vrai game changer est le feature flag. Au lieu de redéployer, désactivez le feature :
if (await FeatureFlags.isEnabled('new_payment_flow')) {
await newPaymentFlow();
} else {
await legacyPaymentFlow();
}
SnapLogs s'intègre avec LaunchDarkly, Flagsmith, ou un système maison via webhook. Voyez la documentation.
Case study : debug d'un crash iOS en production
Contexte
App Flutter e-commerce, 200k DAU. Crash iOS 16.4 uniquement, sur iPhone 14 Pro. Android stable.
Étape 1 : qualifier
SnapLogs dashboard : 89 crashes en 2h, tous iOS 16.4, tous iPhone 14 Pro. P0.
Étape 2 : lire les breadcrumbs
T 12:04:31 NAV push /product/42
T 12:04:32 NET GET /products/42 → 200
T 12:04:32 TAP "Add to cart"
T 12:04:32 NAV push /cart
T 12:04:33 CRASH EXC_BAD_ACCESS
Le crash survient à l'ouverture du cart, après ajout au panier.
Étape 3 : lire la stack
#0 CartScreen.build (package:app/cart.dart:84)
#1 StatelessElement.build (package:flutter/.../widget.dart:512)
#2 ComponentElement.performRebuild (package:flutter/.../widget.dart:432)
Le crash est dans cart.dart:84. Code :
Widget build(BuildContext context) {
final item = cart.items.firstWhere((i) => i.id == lastAddedId); // ligne 84
return Text(item.title);
}
firstWhere throw si l'item n'existe pas. Mais c'est un StatelessWidget reconstruit à chaque push, et lastAddedId peut être null.
Étape 4 : reproduire
Sur iPhone 14 Pro simulator, iOS 16.4 : on reproduit au 3e essai. Sur Android : jamais. Pourquoi ? iOS 16.4 a un timing de rebuild légèrement différent qui expose la race condition.
Étape 5 : fix
final item = cart.items.where((i) => i.id == lastAddedId).firstOrNull;
if (item == null) {
return const SizedBox.shrink();
}
return Text(item.title);
Plus test :
test('Cart handles missing item gracefully', () {
final cart = Cart(items: []);
cart.lastAddedId = 'unknown';
expect(() => buildCartWidget(cart), returnsNormally);
});
Étape 6 : déployer
Hotfix 1.4.3, symbols uploadés, deploy. Crashes tombent à 0 en 1h.
Étape 7 : post-mortem
Documenté. Lesson : toujours utiliser firstOrNull plutôt que firstWhere sur des collections mutables.
Intégration SnapLogs pour le debug production
Voici la configuration complète recommandée.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:snaplogs/snaplogs.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await SnapLogs.init(
apiKey: const String.fromEnvironment('SNAPLOGS_KEY'),
environment: 'production',
sampleRate: 0.05,
errorSampleRate: 1.0,
captureLayoutWarnings: true,
redactPatterns: [
r'\b[\w.]+@[\w.]+\b',
r'\b\d{16}\b',
r'\b[A-Z]{2}\d{2}[A-Z0-9]{12,30}\b',
],
beforeSend: (event) {
if (event.tags['flow'] == 'health_check') return null;
return event;
},
);
FlutterError.onError = (details) {
FlutterError.presentError(details);
SnapLogs.captureException(
details.exception,
stackTrace: details.stack,
tags: {'flow': 'framework'},
);
};
runZonedGuarded<Future<void>>(() async {
runApp(const MyApp());
}, (Object error, StackTrace stack) {
SnapLogs.captureException(
error,
stackTrace: stack,
tags: {'flow': 'async'},
);
});
Isolate.current.addErrorListener(
RawReceivePort((dynamic pair) {
final List<dynamic> data = pair as List<dynamic>;
SnapLogs.captureException(
data.first as Object,
stackTrace: data.last as StackTrace,
tags: {'flow': 'isolate'},
);
}).sendPort,
);
}
Avec cette config, vous captez :
- Toutes les exceptions framework, async, isolate.
- Les breadcrumbs et logs structurés en contexte.
- Les crashes obfusqués, symbolisés côté serveur.
- Les alertes Slack sur pics et nouveaux crashes.
Outils complémentaires
Sentry (crash natif deep)
Pour les crashes NDK ou les kernel panics, Sentry est plus profond. SnapLogs + Sentry = couverture maximale.
Firebase Performance
Pour le jank et la latence réseau, Firebase Performance est pertinent.
n8n (incident automation)
SnapLogs peut déclencher un workflow n8n à chaque incident :
- Créer un ticket Linear.
- Pager l'on-call.
- Mettre à jour une status page.
Voyez la doc d'intégration n8n.
Stratégies de mitigation sans redéploiement
Le redéploiement iOS prend 24-48h en review App Store. Pour les P0, c'est trop long. Voici les stratégies de mitigation sans redeploy.
Feature flags
Le feature flag est la première arme. Désactivez le feature buggy à distance :
final isEnabled = await FeatureFlags.isEnabled('new_checkout_flow');
if (isEnabled) {
await newCheckoutFlow();
} else {
await legacyCheckoutFlow();
}
SnapLogs s'intègre avec LaunchDarkly, Flagsmith, ou un système maison. Désactiver un flag prend 10 secondes, contre 24h pour un redeploy.
Remote config
Pour les valeurs (seuils, timeouts, URLs), utilisez le remote config :
final timeout = await RemoteConfig.getInt('payment_timeout_ms', defaultValue: 5000);
await api.post('/charge', body: {...}).timeout(Duration(milliseconds: timeout));
Si l'API est lente, montez le timeout à 10s via remote config, sans redeploy.
Kill switches
Pour les flows critiques, ajoutez un kill switch :
if (await FeatureFlags.isEnabled('payment_enabled')) {
await paymentFlow();
} else {
await showMaintenanceScreen();
}
En cas de bug majeur, désactivez le flow entier et affichez un message.
Hot patching (avancé)
Pour les équipes matures, le hot patching (code push sans review) existe sur Android (via CodePush React Native, ou des solutions maison Flutter). iOS est plus restrictif, mais des solutions comme Shorebird (Flutter) émergent. SnapLogs s'intègre avec Shorebird pour tracer les versions patchées séparément.
Case study : debug d'un bug de performance en production
Le debug production ne se limite pas aux crashs. Les bugs de perf (jank, lent, freeze) sont tout aussi critiques et souvent plus difficiles à diagnostiquer.
Contexte
App Flutter fitness, 500k DAU. Les utilisateurs se plaignent d'un écran « qui lag ». Pas de crash, pas d'erreur. Difficile à diagnostiquer car subjectif.
Étape 1 : instrumenter
Ajout d'un timer sur l'écran suspecté :
class WorkoutScreen extends StatefulWidget {
const WorkoutScreen({super.key});
@override
State<WorkoutScreen> createState() => _WorkoutScreenState();
}
class _WorkoutScreenState extends State<WorkoutScreen> {
DateTime? _frameStart;
@override
void initState() {
super.initState();
_trackFrames();
}
void _trackFrames() {
WidgetsBinding.instance.addPersistentFrameCallback((_) {
final now = DateTime.now();
if (_frameStart != null) {
final duration = now.difference(_frameStart!);
if (duration.inMilliseconds > 100) {
SnapLogs.log(
level: LogLevel.warning,
message: 'slow_frame',
fields: {'duration_ms': duration.inMilliseconds, 'screen': 'workout'},
);
}
}
_frameStart = now;
});
}
@override
Widget build(BuildContext context) => const Scaffold(body: Center(child: Text('Workout')));
}
Étape 2 : collecter
Après 24h, SnapLogs reçoit 12k slow_frame warnings. Tous sur l'écran workout. Durée médiane : 180ms (au lieu de moins de 16ms pour 60fps).
Étape 3 : lire les breadcrumbs
Le breadcrumbs type avant un slow_frame :
T 12:04:31 NAV push /workout
T 12:04:32 NET GET /exercises → 200 (1.2s)
T 12:04:32 slow_frame duration_ms=180
T 12:04:33 slow_frame duration_ms=210
T 12:04:34 slow_frame duration_ms=190
Le slow frame arrive juste après le GET /exercises qui prend 1.2s. Hypothèse : le parsing JSON bloque l'UI thread.
Étape 4 : confirmer
DevTools en profile mode confirme : 800ms de parsing JSON sur l'UI thread pendant la navigation.
Étape 5 : fix
Isoler le parsing dans un isolate :
Future<List<Exercise>> fetchExercises() async {
final response = await http.get(Uri.parse('https://api.example.com/exercises'));
return await compute(_parseExercises, response.body);
}
List<Exercise> _parseExercises(String body) {
final json = jsonDecode(body) as List<dynamic>;
return json.map((e) => Exercise.fromJson(e as Map<String, dynamic>)).toList();
}
Le compute fait tourner le parsing dans un isolate séparé. L'UI thread n'est plus bloqué.
Étape 6 : mesurer
Après le fix, les slow_frame warnings tombent de 12k/jour à 200/jour (bruit de fond). Le bug est résolu sans aucune plainte supplémentaire.
Lesson
Sans instrumentation, ce bug serait resté invisible. Les users se plaignaient subjectivement, sans stack, sans erreur. Avec SnapLogs, le bug est devenu mesurable, puis résolvable.
Case study : bug intermittent de panier
Contexte
App Flutter e-commerce. 0.3% des paniers se vident aléatoirement. Pas de crash, pas d'erreur visible.
Étape 1 : instrumenter le panier
void addToCart(Item item) {
_cart.add(item);
SnapLogs.log(
level: LogLevel.info,
message: 'cart_add',
fields: {
'item_id': item.id,
'count': _cart.length,
'session_id': sessionId,
'total': _cartTotal,
},
);
}
void removeFromCart(String itemId) {
_cart.removeWhere((i) => i.id == itemId);
SnapLogs.log(
level: LogLevel.info,
message: 'cart_remove',
fields: {
'item_id': itemId,
'count': _cart.length,
'session_id': sessionId,
'total': _cartTotal,
},
);
}
void clearCart(String reason) {
_cart.clear();
SnapLogs.log(
level: LogLevel.warning,
message: 'cart_clear',
fields: {'reason': reason, 'session_id': sessionId},
);
}
Étape 2 : analyser
Après 48h, SnapLogs montre une séquence récurrente :
cart_add item=A count=1
cart_add item=B count=2
cart_add item=C count=3
auth_token_refresh
cart_clear reason=auth_reset
Le clear survient juste après un refresh du token d'auth. Le coupable : la fonction refreshToken appelle clearCart('auth_reset') par erreur, copiée d'un vieux code.
Étape 3 : fix
Retirer l'appel clearCart dans refreshToken. Ajouter un test :
test('refreshToken does not clear cart', () async {
final cart = Cart()..add(Item(id: 'A'));
await refreshToken();
expect(cart.items.length, 1);
});
Lesson
Un bug sans erreur ni crash est invisible aux crash reporters. Seul le logging structuré permet de remonter la séquence d'événements qui révèle la cause.
Gestion des crashes sur Flutter Web
Flutter Web a des particularités. Les crashes se traduisent par :
- Erreurs JavaScript capturées par
window.onerror. - CORS errors (souvent silencieuses côté client).
- Layout overflow (invisible en console).
Pour capter les crashes web :
import 'dart:html' as html;
void setupWebErrorCapture() {
html.window.onError.listen((html.Event event) {
final errorEvent = event as html.ErrorEvent;
SnapLogs.captureException(
Exception(errorEvent.message),
stackTrace: StackTrace.fromString(errorEvent.error ?? ''),
tags: {'flow': 'web_window_error'},
);
});
html.window.onUnhandledError.listen((event) {
SnapLogs.captureException(
event.error,
stackTrace: event.stackTrace,
tags: {'flow': 'web_unhandled'},
);
});
}
Les CORS errors nécessitent de logger le network côté Dart (pas seulement le browser), car le browser masque les détails CORS pour des raisons de sécurité.
Conclusion
Le debug Flutter en production n'est pas un art mystérieux. C'est un système. Les principes :
- Instrumenter avant le bug : capture framework, async, isolate.
- Symboliser : uploadez les symbols à chaque release.
- Grouper : par signature et par fingerprint métier.
- Prioriser : par volume, impact, récurrence.
- Tracer les perfs : logs de durée sur les écrans et le réseau.
- Alerter : pics, nouveaux crashes, P0.
- Post-mortem : pour tout incident P0/P1.
SnapLogs intègre tous ces éléments dans un SDK unique. Pour adopter ce workflow :
- Consultez nos prix et créez un compte.
- Intégrez le SDK Flutter.
- Lisez la documentation.
Pour aller plus loin, voyez notre guide complet du bug report Flutter, notre comparatif des bug trackers, et notre guide du logging mobile moderne. Le debug production n'est pas une option : c'est ce qui sépare une app qui scale d'une app qui churn.
Articles liés
Des 9 EUR/mois, sans engagement
Annulez a tout moment. Mobile Money disponible en Afrique.
Voir les tarifs