15 KiB
iMedia TV+ / Xtream Google TV Player (Hermes Edition)
Spécifications, architecture et guide du projet
Projet : Lecteur IPTV Xtream pour Google TV / Android TV
Package Android : ma.tkgraph.xtreamtv
Plateforme cible : Google TV / Android TV
Langage : Kotlin
Interface : Jetpack Compose / Compose TV
Lecteur vidéo : AndroidX Media3 ExoPlayer
API IPTV : Xtream Codes compatible
Date du document : 11/06/2026
Version : 2.0 (Hermes)
1. Objectif du projet
Développer une application Google TV complète pour lire des contenus IPTV depuis un serveur Xtream, en mettant l'accent sur :
- Qualité logicielle : tests, architecture propre, sécurité
- Expérience utilisateur : navigation fluide, télécommande, réactivité
- Résilience : gestion d'erreur, cache, fallbacks gracieux
- Maintenabilité : documentation, historique, conventions
Fonctionnalités couvertes :
- Connexion à un serveur Xtream + mémorisation sécurisée des identifiants
- Lecture Live TV avec EPG court
- Guide TV global + Replay / Catch-up TV
- VOD et Séries avec catalogues complets
- Favoris persistants (Live, VOD, Séries)
- Chaîne épinglée au démarrage
- Navigation complète à la télécommande Google TV
- Support multilingue (français, anglais, arabe)
- Cache local EPG pour performances
2. Architecture
2.1. Diagramme de flux
flowchart TB
subgraph UI ["Couche UI (Compose TV)"]
Login[LoginScreen]
Home[HomeScreen]
Player[PlayerScreen]
Guide[ProgramGuideScreen]
Replay[ReplayGuideScreen]
Vod[VodScreen]
Series[SeriesScreen]
end
subgraph ViewModel ["Couche ViewModel"]
VM_Home[HomeViewModel]
VM_Player[PlayerViewModel]
VM_Vod[VodViewModel]
VM_Series[SeriesViewModel]
end
subgraph Repository ["Couche Repository"]
Repo_Auth[AuthRepository]
Repo_Live[LiveRepository]
Repo_Vod[VodRepository]
Repo_Series[SeriesRepository]
Repo_Epg[EpgRepository]
end
subgraph Data ["Couche Data"]
API[XtreamApi<br/>Retrofit]
Cache[EpgCache<br/>Room / SQLite]
Storage[ConfigStorage<br/>EncryptedSharedPreferences]
end
subgraph External ["Externe"]
Xtream[Xtream Server]
end
Login --> VM_Home
Home --> VM_Home
Player --> VM_Player
Guide --> VM_Player
Replay --> VM_Player
Vod --> VM_Vod
Series --> VM_Series
VM_Home --> Repo_Auth
VM_Home --> Repo_Live
VM_Home --> Repo_Epg
VM_Player --> Repo_Live
VM_Player --> Repo_Epg
VM_Vod --> Repo_Vod
VM_Series --> Repo_Series
Repo_Auth --> Storage
Repo_Live --> API
Repo_Vod --> API
Repo_Series --> API
Repo_Epg --> API
Repo_Epg --> Cache
API --> Xtream
Storage -.->|Fallback| API
2.2. Flux de navigation
flowchart LR
Splash[Splash<br/>iMedia TV+] --> Login[LoginScreen]
Login --> Home[HomeScreen]
Home -->|Live TV| LiveList[Liste Chaînes]
Home -->|Guide TV| GuideScreen[Guide TV Global]
Home -->|VOD| VodScreen[Catalogue VOD]
Home -->|Séries| SeriesScreen[Catalogue Séries]
LiveList --> Player[PlayerScreen]
GuideScreen --> Player
ReplayGuide --> Player
VodScreen --> Player
SeriesScreen --> Player
Player -->|Retour 1| Overlay
Player -->|Retour 2| PreviousScreen
Home -->|Retour| ConfirmQuit{Confirmer?}
2.3. Structure des dossiers
app/
└── src/
├── main/
│ ├── AndroidManifest.xml
│ ├── java/ma/tkgraph/xtreamtv/
│ │ ├── MainActivity.kt
│ │ ├── data/
│ │ │ ├── model/ ← DTOs Xtream
│ │ │ ├── network/ ← Retrofit API + interceptors
│ │ │ ├── repository/ ← Live, VOD, Series, EPG, Auth
│ │ │ └── storage/ ← EncryptedSharedPreferences
│ │ ├── ui/
│ │ │ ├── components/ ← ChannelLogo, CategoryRow, etc.
│ │ │ ├── screens/ ← Login, Home, Player, Guide, etc.
│ │ │ └── theme/ ← Thème Material 3
│ │ └── util/ ← UrlBuilder, CategorySort, Extensions
│ └── res/
│ ├── drawable/ ← launch_background.xml
│ ├── drawable-nodpi/ ← iMedia TV+ splash PNG
│ ├── mipmap-*/ ← icône app
│ ├── values/ ← strings.xml (default = EN)
│ ├── values-fr/ ← strings.xml (français)
│ └── values-ar/ ← strings.xml (العربية)
├── test/ ← Tests unitaires (JUnit + MockK)
└── androidTest/ ← Tests UI (Compose Test)
3. Stack technique détaillée
| Couche | Technologie | Justification |
|---|---|---|
| Langage | Kotlin 2.x | Moderne, sûr, natif Android |
| UI | Jetpack Compose + Compose TV (1.7+) | Déclaratif, natif TV |
| Lecteur | AndroidX Media3 ExoPlayer 1.5+ | Standard Google, HLS/DASH/MP4 |
| Réseau | Retrofit 2.11+ / OkHttp 4.12+ | Robuste, interceptable |
| Images | Coil 3.x | Asynchrone, cache, fallback |
| Cache EPG | Room 2.7+ (SQLite) | Performant, requêtes typées |
| Stockage | EncryptedSharedPreferences + AES-256 | Sécurité des credentials |
| Tests unitaires | JUnit 5 / MockK / Turbine | Kotlin-friendly, Flow test |
| Tests UI | Compose UI Test + Espresso | Automatisation UI TV |
| Logging | Timber | Structuré, tags, crash |
| Crash reporting | Firebase Crashlytics | Monitoring production |
4. Environnement de développement
| Composant | Valeur |
|---|---|
| OS de développement | Windows 11 |
| IDE | Android Studio (Ladybug+) |
| Terminal | PowerShell |
| Appareil cible | Google TV / Android TV 12+ (API 31+) |
| Connexion | ADB Wi-Fi ou USB |
| JDK | OpenJDK 21 (via Android Studio) |
| SDK Android | API 36, Build-Tools 36.x |
| Gradle | 9.1+ (wrapper) |
4.1. Variables d'environnement
$env:JAVA_HOME = "D:\Program Files\Android\Android Studio\jbr"
$env:ANDROID_HOME = "$env:LOCALAPPDATA\Android\Sdk"
$env:Path = "$env:JAVA_HOME\bin;$env:ANDROID_HOME\platform-tools;$env:ANDROID_HOME\cmdline-tools\latest\bin;D:\Tools\Gradle\gradle-9.1.0\bin;$env:Path"
4.2. Compilation
cd "D:\07-Logiciels\12-IPTV Andoid TV HERMES"
.\gradlew.bat clean --no-daemon
.\gradlew.bat :app:assembleDebug --no-daemon
APK générée : app\build\outputs\apk\debug\app-debug.apk
5. Sécurité
5.1. Stockage des identifiants
Problème de la v1 : identifiants stockés en clair dans SharedPreferences.
Solution Hermes : EncryptedSharedPreferences avec AES-256 GCM.
// data/storage/SecureStorage.kt
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val prefs = EncryptedSharedPreferences.create(
context,
"imedia_secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
5.2. Règles de sécurité
- Aucun log contenant
username,passwordouserver_url - Timeout réseau configuré (15s connect, 30s read)
- Validation côté client avant envoi : URL bien formée, champs non vides
- Pas de stockage en cache HTTP des credentials
- OkHttp interceptor pour masquer les auth dans les logs debug
- Préparation au HTTPS (certificats, SSR)
6. Gestion d'erreurs
6.1. Stratégie générale
| Scénario | Comportement | Message utilisateur |
|---|---|---|
| Réseau indisponible | Toast + fallback cache EPG | "Connexion impossible. Vérifiez votre réseau." |
| Timeout API (15s) | Retry 1x, puis message | "Le serveur ne répond pas. Réessayez." |
| Auth échouée | Effacer champs, focus sur login | "Identifiants incorrects ou serveur invalide." |
| Flux vidéo mort | 503 overlay, retour menu | "Flux indisponible pour cette chaîne." |
| EPG vide | Afficher "Aucun programme" | "Aucun programme trouvé pour cette chaîne." |
| Données corrompues | Fallback valeurs par défaut | "Des données sont manquantes — certains affichages peuvent être incomplets." |
6.2. État UI avec sealed class
sealed class UiState<out T> {
object Idle : UiState<Nothing>()
object Loading : UiState<Nothing>()
data class Success<T>(val data: T) : UiState<T>()
data class Error(val message: String, val retry: Boolean = true) : UiState<Nothing>()
}
6.3. Intercepteur réseau
class ErrorInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
return try {
val response = chain.proceed(request)
if (!response.isSuccessful) {
throw XtreamHttpException(response.code, response.message)
}
response
} catch (e: SocketTimeoutException) {
throw XtreamTimeoutException("Le serveur Xtream est injoignable")
} catch (e: UnknownHostException) {
throw XtreamNetworkException("Aucune connexion réseau")
}
}
}
7. Cache EPG
7.1. Problème
Le guide TV global peut nécessiter des centaines d'appels API (1 par chaîne). Sans cache, l'écran est inutilisable.
7.2. Solution : Room (SQLite)
@Entity(tableName = "epg_cache")
data class EpgCacheEntry(
@PrimaryKey val id: Long,
val streamId: Int,
val channelName: String,
val title: String,
val description: String?,
val startTimestamp: Long,
val endTimestamp: Long,
val cachedAt: Long = System.currentTimeMillis()
)
7.3. Politique de cache
| Type | Durée | Invalidation |
|---|---|---|
| EPG court (live) | 2 minutes | Rafraîchi au scroll |
| EPG complet (guide) | 15 minutes | Pull-to-refresh manuel |
| Catégories | 1 heure | Au lancement |
| Listes chaînes | 5 minutes | Changement de catégorie |
7.4. Flux EPG
flowchart TD
A[Ouvre Guide TV] --> B{Cache valide?}
B -->|Oui < 15min| C[Afficher depuis Room]
B -->|Non| D[Requête API par chaîne]
D --> E[Stocker dans Room]
E --> C
8. Tests
8.1. Tests unitaires (JUnit 5 + MockK)
| Fichier | Test | Ce qu'on vérifie |
|---|---|---|
AuthRepositoryTest.kt |
Connexion valide/invalide | Repository retourne Success ou Error |
AuthRepositoryTest.kt |
Timeout réseau | Erreur lisible, pas de crash |
EpgRepositoryTest.kt |
Cache hit/miss | Appel API si cache expiré, sinon données locales |
CategorySortUtilsTest.kt |
Tri FR/AR/autres | Ordre exact des catégories |
XtreamUrlBuilderTest.kt |
URLs Live/VOD/Series | Format correct de chaque URL |
SecureStorageTest.kt |
Lecture/écriture chiffrée | Données diffférentes en clair vs stocké |
PlayerViewModelTest.kt |
Zapping gauche/droite | Chaîne suivante/précédente correcte |
FavoritesRepositoryTest.kt |
Ajout/suppression favoris | Persistance après redémarrage |
8.2. Tests UI (Compose UI Test)
| Fichier | Test |
|---|---|
LoginScreenTest.kt |
Remplissage formulaire → bouton actif |
LoginScreenTest.kt |
Erreur → message d'erreur affiché |
HomeScreenTest.kt |
Navigation entre catégories OK |
HomeScreenTest.kt |
Favori accessible via télécommande |
PlayerScreenTest.kt |
Overlay disparaît après 3s |
8.3. Lancer les tests
# Tests unitaires uniquement
.\gradlew.bat test --no-daemon
# Tests UI (appareil/émulateur connecté)
.\gradlew.bat connectedAndroidTest --no-daemon
# Les deux
.\gradlew.bat test connectedAndroidTest --no-daemon
9. Internationalisation (i18n)
9.1. Langues supportées
| Langue | Dossier | Statut |
|---|---|---|
| Anglais (défaut) | values/ |
✅ Prévu |
| Français | values-fr/ |
✅ Prévu |
| Arabe | values-ar/ |
✅ Prévu (RTL) |
9.2. Exemple
<!-- values/strings.xml -->
<string name="app_name">iMedia TV+</string>
<string name="live_tv">Live TV</string>
<string name="connect">Connect</string>
<string name="network_error">Connection lost. Check your network.</string>
<!-- values-fr/strings.xml -->
<string name="app_name">iMedia TV+</string>
<string name="live_tv">Direct TV</string>
<string name="connect">Connexion</string>
<string name="network_error">Connexion perdue. Vérifiez votre réseau.</string>
<!-- values-ar/strings.xml -->
<string name="app_name">iMedia TV+</string>
<string name="live_tv">البث المباشر</string>
<string name="connect">اتصال</string>
<string name="network_error">انقطع الاتصال. تحقق من شبكتك.</string>
10. Logging et Monitoring
10.1. Timber
// Application.kt
class XtreamApplication : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
} else {
Timber.plant(CrashReportingTree())
}
}
}
Règles :
Timber.d/Timber.ipour debug et infosTimber.wpour anomalies non bloquantesTimber.epour erreurs utilisateur- Jamais de log de credentials, tokens, ou données sensibles
10.2. Crash reporting
Firebase Crashlytics est prévu pour la version release :
- Rapports de crash automatiques
- Logs non-sensibles attachés aux rapports
- Clés custom : écran actif, dernier état réseau
11. Roadmap
Phase 1 — Fondations (immédiat)
- Structure du projet
- Stack technique définie
- Connexion Xtream + SecureStorage
- Live TV avec Media3
Phase 2 — Fonctionnalités cœur
- Catégories + Favoris Live
- EPG court + Replay
- Guide TV global
- VOD + Séries
Phase 3 — Qualité
- Tests unitaires (couverture > 70%)
- Cache EPG (Room)
- Gestion d'erreur complète
- i18n (FR, EN, AR)
Phase 4 — Production
- Signing + ProGuard
- Firebase Crashlytics
- Bannière Android TV + icônes finales
- Politique de confidentialité
- Publication Play Store
12. Conclusion
Cette version Hermes reprend l'excellente base de la v1 et y ajoute :
- 🔐 Sécurité : chiffrement AES-256 des credentials
- 📦 Cache EPG : Room SQLite pour des performances réelles
- 🧪 Tests : stratégie complète (unitaire + UI)
- 🌍 i18n : support FR/EN/AR
- 📋 Gestion d'erreur : sealed class + intercepteurs + messages lisibles
- 📊 Monitoring : Timber + Crashlytics
- 📐 Architecture : flux documentés en Mermaid
Le logiciel fonctionnait déjà en v1. Cette version le rend fiable, sécurisé et prêt pour la production.