Flutter vs React Native
Le Flutter de Google, basé sur Dart, face au React Native de Meta, basé sur JavaScript/TypeScript — comparaison sous tous les angles. Quel framework cross-platform se démarque en 2025 ?
Intégration profonde à la plateforme, performance maximale et meilleure UX
Une seule base de code, deux plateformes — avantage de vitesse et de coût
| Catégorie | Native (Swift/Kotlin) | Cross-Platform (Flutter/RN) |
|---|---|---|
| Performance | 10/10 | 8/10 |
| Facilité d'apprentissage | 6/10 | 8/10 |
| Écosystème | 10/10 | 8/10 |
| Communauté | 9/10 | 9/10 |
| Marché de l'emploi | 9/10 | 8/10 |
| Pérennité | 9/10 | 8/10 |
// Swift (iOS) - Intégration HealthKit (possible uniquement en natif)
import HealthKit
import SwiftUI
@Observable
class HealthViewModel {
var stepCount: Int = 0
var heartRate: Double = 0
var activeCalories: Double = 0
private let healthStore = HKHealthStore()
func requestPermission() async throws {
let readTypes: Set<HKObjectType> = [
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!
]
try await healthStore.requestAuthorization(toShare: [], read: readTypes)
}
func fetchTodayStats() async throws {
let now = Date()
let startOfDay = Calendar.current.startOfDay(for: now)
let predicate = HKQuery.predicateForSamples(
withStart: startOfDay, end: now, options: .strictStartDate
)
// Nombre de pas
let stepType = HKQuantityType(.stepCount)
let stepQuery = HKStatisticsQuery(
quantityType: stepType,
quantitySamplePredicate: predicate,
options: .cumulativeSum
) { [weak self] _, result, _ in
Task { @MainActor in
self?.stepCount = Int(result?.sumQuantity()?.doubleValue(for: .count()) ?? 0)
}
}
healthStore.execute(stepQuery)
}
}
// Intégration ARKit — exclusive au natif
import ARKit
import RealityKit
struct ARViewContainer: UIViewRepresentable {
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
let config = ARWorldTrackingConfiguration()
config.planeDetection = [.horizontal, .vertical]
arView.session.run(config)
// Chargement et placement du modèle 3D
let anchor = AnchorEntity(plane: .horizontal)
let box = ModelEntity(mesh: .generateBox(size: 0.1))
anchor.addChild(box)
arView.scene.addAnchor(anchor)
return arView
}
func updateUIView(_ uiView: ARView, context: Context) {}
}// Flutter - Accès aux fonctionnalités de la plateforme (Method Channel)
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
// Définition du canal de plateforme
const platform = MethodChannel('com.myapp/native');
class NativeFeatureService {
// HealthKit sur iOS, Health Connect sur Android
static Future<Map<String, dynamic>> getHealthData() async {
try {
final result = await platform.invokeMethod<Map>('getHealthData');
return Map<String, dynamic>.from(result ?? {});
} on PlatformException catch (e) {
debugPrint('Erreur HealthKit/Health Connect : ${e.message}');
return {};
}
}
// Authentification biométrique spécifique à l'appareil
static Future<bool> authenticateWithBiometrics() async {
try {
return await platform.invokeMethod<bool>('biometricAuth') ?? false;
} on PlatformException catch (e) {
debugPrint('Erreur biométrique : ${e.message}');
return false;
}
}
}
// UI Flutter (identique sur les deux plateformes)
class HealthDashboard extends StatefulWidget {
const HealthDashboard({super.key});
@override
State<HealthDashboard> createState() => _HealthDashboardState();
}
class _HealthDashboardState extends State<HealthDashboard> {
Map<String, dynamic> healthData = {};
@override
void initState() {
super.initState();
loadHealthData();
}
Future<void> loadHealthData() async {
final data = await NativeFeatureService.getHealthData();
setState(() => healthData = data);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Résumé santé')),
body: ListView(
children: [
_StatCard(label: 'Nombre de pas', value: '${healthData["steps"] ?? 0}'),
_StatCard(label: 'Calories', value: '${healthData["calories"] ?? 0} kcal'),
],
),
);
}
}La décision dépend de la taille de l'équipe, du budget et de la complexité de l'application. Petite équipe + budget limité + application orientée contenu → le cross-platform est logique. Grande équipe + profondeur de plateforme + performance critique → privilégiez le natif. Kotlin Multiplatform offre un joli compromis entre les deux, en partageant la logique métier tout en gardant une UI native.
Obtenir une consultation gratuiteKMP est une approche hybride : la logique métier, la couche réseau et les modèles de données sont partagés en Kotlin ; l'UI est écrite nativement sur chaque plateforme. Il combine l'avantage de la performance native avec le partage de code.