10 KiB
ADR-014 : Frontend Mobile
Statut : Accepté Date : 2025-01-20
Contexte
RoadWave nécessite applications iOS et Android avec support CarPlay/Android Auto, lecture audio HLS avancée, géolocalisation temps réel. Le choix du framework impacte vélocité développement et performances.
Décision
Flutter pour iOS et Android avec codebase unique.
Alternatives considérées
| Framework | Codebase | Performance | Audio/CarPlay | Communauté |
|---|---|---|---|---|
| Flutter | Unique | Native | Excellente | Large |
| React Native | Unique | Bonne | Modules natifs requis | Très large |
| Native (Swift+Kotlin) | Double | Excellente | Native | Large |
| Ionic/Capacitor | Unique | Moyenne | Limitée | Moyenne |
Justification
- Codebase unique : iOS + Android maintenus ensemble, vélocité développement x2
- Performance : Dart compilé en code natif (pas de bridge JS)
- Audio HLS : Package
just_audiomature avec support HLS, buffering adaptatif - CarPlay/Android Auto : Support via packages communautaires (
flutter_carplay,android_auto_flutter) - Géolocalisation :
geolocatorrobuste avec gestion permissions - Écosystème : Widgets riches (Material/Cupertino), state management mature (Bloc, Riverpod)
Packages Flutter
Voir ADR-022 - Librairies Flutter pour la liste complète des packages, licences, alternatives considérées et justifications détaillées.
Packages clés pour RoadWave :
- State management :
flutter_bloc(pattern BLoC, testable, reactive) - Audio HLS :
just_audio(HLS natif, buffering adaptatif, background playback) - GPS temps réel :
geolocator(mode voiture haute précision) - Geofencing :
geofence_service(mode piéton, détection rayon 200m, économie batterie) - Notifications :
flutter_local_notifications(compteur dynamique, conformité CarPlay/Android Auto) - HTTP :
dio(client HTTP avec retry logic) - Stockage sécurisé :
flutter_secure_storage(JWT tokens, Keychain iOS, KeyStore Android) - Cache images :
cached_network_image(LRU cache)
Points d'attention :
- ⚠️ Permissions progressives requises pour
geofence_serviceetgeolocator(voir section "Stratégie de Permissions") - ⚠️ Licences : 100% permissives (MIT, BSD-3) - voir ADR-022
Stratégie de Permissions (iOS/Android)
Contexte et Enjeux
Problème : La géolocalisation en arrière-plan (requise pour le mode piéton) est très scrutée par Apple et Google :
- iOS App Store : Taux de rejet ~70% si permission "Always Location" mal justifiée
- Android Play Store :
ACCESS_BACKGROUND_LOCATIONnécessite déclaration spéciale depuis Android 10 - RGPD : Permissions doivent être optionnelles et l'app utilisable sans
Architecture de Permissions Progressive
Principe : Demander le minimum au départ, puis proposer upgrade contextuel uniquement si besoin.
Niveaux de Permissions
Trois niveaux de permissions doivent être gérés :
- Denied : Aucune permission → app limitée (contenu national)
- When In Use : "Quand l'app est ouverte" → mode voiture complet ✅
- Always : "Toujours" / Background → mode piéton ✅
Étape 1 : Permission de Base (Onboarding)
Quand : Premier lancement de l'app
Demande : locationWhenInUse uniquement
- iOS : "Allow While Using App"
- Android :
ACCESS_FINE_LOCATION
Justification affichée :
📍 RoadWave a besoin de votre position
Pour vous proposer du contenu audio adapté
à votre localisation en temps réel.
[Autoriser] [Non merci]
Si acceptée : Mode voiture entièrement fonctionnel ✅
Si refusée : Mode dégradé (contenus nationaux/régionaux via GeoIP)
Étape 2 : Upgrade Optionnel (Contextuel)
Quand : Utilisateur active explicitement "Notifications audio-guides piéton" dans Settings
Flow :
- Écran d'éducation (requis pour validation stores) :
┌────────────────────────────────────────┐
│ 📍 Notifications audio-guides piéton │
├────────────────────────────────────────┤
│ Pour vous alerter d'audio-guides à │
│ proximité même quand vous marchez avec │
│ l'app fermée, RoadWave a besoin de │
│ votre position en arrière-plan. │
│ │
│ Votre position sera utilisée pour : │
│ ✅ Détecter monuments à 200m │
│ ✅ Vous envoyer une notification │
│ │
│ Votre position ne sera jamais : │
│ ❌ Vendue à des tiers │
│ ❌ Utilisée pour de la publicité │
│ │
│ Cette fonctionnalité est optionnelle. │
│ Vous pouvez utiliser RoadWave sans │
│ cette permission. │
│ │
│ [Continuer] [Non merci] │
│ │
│ Plus d'infos : Politique confidentialité│
└────────────────────────────────────────┘
-
Demande permission OS :
locationAlways/ACCESS_BACKGROUND_LOCATION -
Si refusée :
- Toggle "Mode piéton" reste désactivé
- Message : "Mode piéton non disponible sans permission arrière-plan"
- App reste pleinement fonctionnelle en mode voiture
Implémentation
Le service de gestion des permissions (lib/core/services/location_permission_service.dart) doit implémenter :
Détection du niveau actuel :
- Vérifier le statut de la permission
location(when in use) - Vérifier le statut de la permission
locationAlways(background) - Retourner le niveau le plus élevé accordé
Demande de permission de base (Étape 1) :
- Demander uniquement la permission
location(when in use) - Utilisée lors de l'onboarding
- Aucun écran d'éducation requis
Demande de permission arrière-plan (Étape 2) :
- Toujours afficher un écran d'éducation AVANT la demande OS
- Demander la permission
locationAlways(iOS) ouACCESS_BACKGROUND_LOCATION(Android) - Si refusée de manière permanente, proposer l'ouverture des réglages système
Gestion des refus :
- Détecter si la permission est refusée de manière permanente
- Proposer l'ouverture des réglages de l'appareil avec un message clair
- Permettre à l'utilisateur d'annuler
Configuration Platform-Specific
iOS (ios/Runner/Info.plist)
Clés requises :
NSLocationWhenInUseUsageDescription: Décrire l'usage pour le mode voiture (contenu géolocalisé en temps réel)NSLocationAlwaysAndWhenInUseUsageDescription: Décrire l'usage optionnel pour le mode piéton (notifications audio-guides en arrière-plan), mentionner explicitement que c'est optionnel et désactivableUIBackgroundModes: Activer les modeslocationetremote-notification
Exemple de texte pour NSLocationAlwaysAndWhenInUseUsageDescription :
"Si vous activez les notifications audio-guides piéton, RoadWave peut vous alerter lorsque vous passez près d'un monument ou musée, même quand l'app est en arrière-plan. Cette fonctionnalité est optionnelle et peut être désactivée à tout moment dans les réglages."
Android (android/app/src/main/AndroidManifest.xml)
Permissions requises :
ACCESS_FINE_LOCATIONetACCESS_COARSE_LOCATION: Permission de base (when in use)ACCESS_BACKGROUND_LOCATION: Permission arrière-plan (Android 10+), nécessite justification Play StoreFOREGROUND_SERVICEetFOREGROUND_SERVICE_LOCATION: Service persistant pour mode piéton (Android 12+)
Android Play Store : Déclaration requise dans Play Console lors de la soumission :
- Justification : "Notifications géolocalisées pour audio-guides touristiques en arrière-plan"
- Vidéo démo obligatoire montrant le flow de demande de permission
Fallbacks et Dégradations Gracieuses
| Niveau Permission | Mode Voiture | Mode Piéton | Contenus Accessibles |
|---|---|---|---|
| Always | ✅ Complet | ✅ Complet | Tous (national + hyperlocal) |
| When In Use | ✅ Complet | ❌ Désactivé | Tous (si app ouverte) |
| Denied | ⚠️ Limité | ❌ Désactivé | Nationaux/régionaux (GeoIP) |
Garantie RGPD : App est pleinement utilisable même avec permission refusée (mode dégradé acceptable).
Tests de Validation Stores
Checklist App Store (iOS) :
- Permission "Always" demandée uniquement si user active mode piéton
- Écran d'éducation avant demande OS (requis iOS 13+)
- App fonctionne sans permission "Always" (validation critique)
- Texte
Info.plistclair et honnête (pas de tracking publicitaire)
Checklist Play Store (Android) :
- Déclaration
ACCESS_BACKGROUND_LOCATIONavec justification détaillée - Vidéo démo flow de permissions (< 30s, requis Play Console)
- App fonctionne sans permission background (validation critique)
- Foreground service notification visible en mode piéton (requis Android 12+)
Documentation Associée
- Guide détaillé : /docs/mobile/permissions-strategy.md
- Règles métier : Règle 05 - Mode Piéton
- RGPD : Règle 02 - Conformité RGPD
Structure application
lib/
├── core/ # Config, DI, routes
│ └── services/ # LocationPermissionService, GeofencingService
├── data/ # Repositories, API clients
├── domain/ # Models, business logic
├── presentation/ # UI (screens, widgets, blocs)
│ └── dialogs/ # PedestrianModeEducationDialog
└── main.dart
Conséquences
- Équipe doit apprendre Dart (syntaxe proche Java/TypeScript)
- Taille binaire : 8-15 MB (acceptable)
- Tests :
flutter_testpour widgets,integration_testpour E2E - CI/CD : Fastlane pour déploiement stores
- Permissions : Stratégie progressive critique pour validation stores (iOS/Android)
- Validation stores : Tests requis avec TestFlight beta (iOS) et Internal Testing (Android)
- Documentation : Justifications permissions détaillées requises pour soumission stores