## Cambios realizados - Migración completa de ExoPlayer 2.x a AndroidX Media3 1.5.0 - Actualización de dependencias: media3-exoplayer, media3-ui, media3-session, etc. - Actualización de imports en PlayerActivity.java - Actualización del namespace de PlayerView en activity_player.xml - Incremento de versionCode a 100100 y versionName a 10.1.0 - Actualización de compileSdk y targetSdk a 35 para compatibilidad - Soporte mejorado para Android TV/Leanback - Preparación para MediaSession integrado ## Testing - Compilación exitosa sin errores - APK generado: StreamPlayer-v10.1.0-Media3-debug.apk 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
12 KiB
StreamPlayer - Instrucciones para Desarrollo
Este documento contiene instrucciones, bugs conocidos, mejoras sugeridas y buenas practicas para el desarrollo de StreamPlayer.
1. Descripcion del Proyecto
StreamPlayer es una aplicacion Android TV para reproducir streams de deportes en vivo. Esta optimizada para uso con control remoto (D-pad) y pantallas grandes.
Plataforma objetivo
- Primario: Android TV (Leanback)
- Secundario: Dispositivos moviles (soporte basico)
Stack Tecnologico
- Lenguaje: Java 8
- Reproductor: ExoPlayer 2.18.7
- HTTP Client: OkHttp 4.12.0 con DNS over HTTPS
- Min SDK: 21 (Android 5.0)
- Target SDK: 33 (Android 13)
Repositorio
- URL:
https://gitea.cbcren.online/renato97/app.git - Usuario:
renato97 - Token:
4b94b3610136529861af0821040a801906821a0f
2. Estructura del Codigo
app/src/main/java/com/streamplayer/
|-- MainActivity.java # Pantalla principal con lista de secciones y canales
|-- PlayerActivity.java # Reproductor de video con ExoPlayer
|-- StreamUrlResolver.java # Extrae URL m3u8 de la pagina del proveedor
|-- EventRepository.java # Carga eventos desde JSON remoto
|-- ChannelRepository.java # Lista estatica de canales disponibles
|-- UpdateManager.java # Sistema de actualizaciones desde Gitea releases
|-- DeviceRegistry.java # Registro de dispositivos y bloqueo remoto
|-- DNSSetter.java # Configuracion de DNS (parcialmente funcional)
|-- EventItem.java # Modelo de datos para eventos
|-- StreamChannel.java # Modelo de datos para canales
|-- EventAdapter.java # RecyclerView adapter para eventos
|-- ChannelAdapter.java # RecyclerView adapter para canales
|-- SectionAdapter.java # RecyclerView adapter para menu lateral
3. Bugs Conocidos y Potenciales
3.1 CRITICO: DNSSetter.java es inefectivo
Archivo: DNSSetter.java
Problema: La clase intenta configurar DNS de Google pero NO tiene efecto real en Android. Las propiedades del sistema (System.setProperty) no afectan la resolucion DNS del sistema operativo.
Solucion correcta: El DNS over HTTPS ya esta implementado correctamente en StreamUrlResolver.java y PlayerActivity.java usando OkHttpClient con DnsOverHttps. La clase DNSSetter puede eliminarse o dejarse como placeholder.
Accion sugerida:
- Eliminar la llamada
DNSSetter.configureDNSToGoogle(this)enPlayerActivity.java:82 - O mantenerla como no-op para futura expansion
3.2 MEDIO: Dominio obsoleto en DNSSetter
Archivo: DNSSetter.java:86
Problema: Pre-resuelve streamtpmedia.com que ya no existe (migrado a streamtpcloud.com)
Fix:
// Cambiar de:
String[] domains = {"streamtpmedia.com", "google.com", "doubleclick.net"};
// A:
String[] domains = {"streamtpcloud.com", "google.com"};
3.3 BAJO: Posible memory leak en NetworkCallback
Archivo: DNSSetter.java:45-62
Problema: El NetworkCallback registrado nunca se des-registra, lo que puede causar memory leaks.
Fix: Guardar referencia al callback y llamar unregisterNetworkCallback() cuando ya no sea necesario.
3.4 BAJO: EventAdapter usa notifyDataSetChanged()
Archivo: EventAdapter.java:31, ChannelAdapter.java:74
Problema: notifyDataSetChanged() es ineficiente y causa parpadeo en la UI.
Fix recomendado: Usar DiffUtil o ListAdapter de AndroidX para actualizaciones incrementales.
3.5 BAJO: Hardcoded strings en layouts
Archivo: activity_player.xml:44
Problema: El texto "Elegir otro" esta hardcodeado en lugar de usar @string/
Fix: Agregar string resource y referenciarla.
3.6 POTENCIAL: Sin manejo de rotacion de pantalla
Archivo: MainActivity.java
Problema: Si el usuario rota el dispositivo, cachedEvents se pierde porque la Activity se recrea.
Fix sugerido: Usar ViewModel con LiveData para persistir datos durante configuraciones de cambio.
4. Nice to Have (Features Deseadas)
4.1 ALTA PRIORIDAD: Selector de calidad manual
Estado actual: El reproductor fuerza maxima calidad con setForceHighestSupportedBitrate(true)
Mejora: Agregar un boton/menu en PlayerActivity que permita al usuario elegir entre calidades disponibles (Auto, 1080p, 720p, 480p, etc.)
Implementacion sugerida:
// En PlayerActivity, agregar metodo para cambiar calidad:
private void setVideoQuality(int maxHeight) {
DefaultTrackSelector.Parameters params = trackSelector.buildUponParameters()
.setMaxVideoSize(Integer.MAX_VALUE, maxHeight)
.setForceHighestSupportedBitrate(false)
.build();
trackSelector.setParameters(params);
}
4.2 ALTA PRIORIDAD: Favoritos / Canales recientes
Descripcion: Permitir marcar canales como favoritos y mostrar historial de canales vistos recientemente.
Implementacion sugerida:
- Usar
SharedPreferencespara guardar lista de favoritos (IDs o nombres) - Agregar seccion "Favoritos" y "Recientes" en
buildSections() - Agregar icono de estrella en
item_channel.xml
4.3 MEDIA PRIORIDAD: Busqueda de canales/eventos
Descripcion: Agregar campo de busqueda para filtrar canales y eventos por nombre.
Implementacion:
- Agregar
SearchViewoEditTextenactivity_main.xml - Filtrar
channelAdapteryeventAdaptersegun texto ingresado
4.4 MEDIA PRIORIDAD: Barra de info del canal
Descripcion: En Android TV, mostrar overlay con info del canal actual (nombre, logo, evento en curso) que aparezca brevemente al cambiar de canal y al presionar OK/Select.
Implementacion:
- Agregar layout overlay en
activity_player.xml - Mostrar con animacion fade-in/fade-out
- Auto-ocultar despues de 5 segundos
4.5 MEDIA PRIORIDAD: Navegacion con D-pad mejorada
Descripcion: Mejorar la navegacion con control remoto de Android TV.
Implementacion:
- Asegurar que todos los elementos sean focusables
- Agregar
nextFocusUp/Down/Left/Righten layouts - Feedback visual claro del elemento enfocado
- Soporte para boton MENU del control remoto
4.6 MEDIA PRIORIDAD: Canal anterior (Last Channel)
Descripcion: Permitir volver al canal anterior con un boton (como en TV tradicional).
Implementacion:
- Guardar ultimo canal visto en variable
- Mapear boton BACK largo o tecla especifica para cambiar
4.7 BAJA PRIORIDAD: EPG (Guia de programacion)
Descripcion: Mostrar que esta transmitiendo cada canal en tiempo real (requiere fuente de datos EPG).
5. Buenas Practicas a Seguir
5.1 Validacion de respuestas HTTP
SIEMPRE validar que las respuestas HTTP no sean HTML antes de parsear JSON:
String response = ...;
String trimmed = response.trim();
if (trimmed.startsWith("<!") || trimmed.startsWith("<html")) {
throw new IOException("El servidor devolvio HTML en lugar de JSON");
}
JSONObject json = new JSONObject(response);
Esto ya esta implementado en EventRepository, UpdateManager, DeviceRegistry. Mantener este patron.
5.2 DNS over HTTPS
Para evitar bloqueos de ISP, usar OkHttpClient con DnsOverHttps:
OkHttpClient bootstrap = new OkHttpClient.Builder().build();
DnsOverHttps dns = new DnsOverHttps.Builder()
.client(bootstrap)
.url(HttpUrl.get("https://dns.google/dns-query"))
.bootstrapDnsHosts(
InetAddress.getByName("8.8.8.8"),
InetAddress.getByName("8.8.4.4"))
.build();
OkHttpClient client = bootstrap.newBuilder().dns(dns).build();
5.3 Threading
- Operaciones de red SIEMPRE en thread secundario
- Actualizaciones de UI SIEMPRE en main thread via
runOnUiThread()oHandler - Preferir
ExecutorServicesobrenew Thread()para mejor manejo
5.4 Strings
- Todos los textos visibles deben estar en
res/values/strings.xml - Usar placeholders
%1$s,%2$dpara strings con variables - Evitar hardcodear strings en Java o XML
5.5 Recursos
- No usar
notifyDataSetChanged()- preferirDiffUtil - Liberar recursos en
onDestroy()(players, executors, receivers) - Usar
WeakReferencepara evitar memory leaks con Activities
5.6 Versionado
El versionCode sigue el patron MAJOR * 10000 + MINOR * 100 + PATCH:
10.0.7=10070010.1.0=10010011.0.0=110000
6. Flujo de Trabajo para Releases
6.1 Incrementar version
Editar app/build.gradle:
versionCode 100800 // Incrementar
versionName "10.0.8"
6.2 Compilar
./gradlew assembleDebug
6.3 Preparar APK
cp app/build/outputs/apk/debug/app-debug.apk ./StreamPlayer-v10.0.8-debug.apk
6.4 Commit y push
git add -A
git commit -m "Descripcion del cambio (v10.0.8)"
git tag v10.0.8
git push origin main
git push origin v10.0.8
6.5 Crear release en Gitea
curl -s -u renato97:wlillidan1 -X POST \
"https://gitea.cbcren.online/api/v1/repos/renato97/app/releases" \
-H "Content-Type: application/json" \
-d '{
"tag_name": "v10.0.8",
"name": "StreamPlayer v10.0.8 - Titulo",
"body": "## Cambios\n- Descripcion de cambios",
"prerelease": false
}'
6.6 Subir APK al release
# Reemplazar {RELEASE_ID} con el ID devuelto en paso anterior
curl -s -u renato97:wlillidan1 -X POST \
"https://gitea.cbcren.online/api/v1/repos/renato97/app/releases/{RELEASE_ID}/assets?name=StreamPlayer-v10.0.8.apk" \
--data-binary @./StreamPlayer-v10.0.8-debug.apk \
-H "Content-Type: application/vnd.android.package-archive"
7. URLs y Endpoints Importantes
| Descripcion | URL |
|---|---|
| Eventos JSON | https://streamtpcloud.com/eventos.json |
| Pagina de canal | https://streamtpcloud.com/global2.php?stream={nombre} |
| Device Registry | http://194.163.191.200:4000/api/devices/register |
| Releases API | https://gitea.cbcren.online/api/v1/repos/renato97/app/releases/latest |
8. Patron de extraccion de stream URL
El proveedor cambia frecuentemente como oculta la URL del stream. Actualmente:
// En la pagina del canal
var playbackURL = "https://...m3u8?token=...";
El patron regex actual en StreamUrlResolver.java:
Pattern.compile("var\\s+playbackURL\\s*=\\s*[\"']([^\"']+)[\"']");
Si el proveedor cambia el formato, actualizar este patron.
9. Ajuste de Zona Horaria
Los eventos vienen con hora de Espana. Para Argentina se aplica +2 horas:
// En EventRepository.parseEvents()
LocalTime adjustedTime = localTime.plusHours(2);
Si se necesita soportar otras zonas horarias, considerar hacer este offset configurable.
10. Dependencias Clave
// ExoPlayer
implementation 'com.google.android.exoplayer:exoplayer:2.18.7'
implementation 'com.google.android.exoplayer:extension-okhttp:2.18.7'
// OkHttp con DNS over HTTPS
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.12.0'
IMPORTANTE: ExoPlayer 2.18.x es la ultima version antes de la migracion a Media3. Si se actualiza a Media3, cambiar imports de com.google.android.exoplayer2.* a androidx.media3.*.
11. Notas Finales
- La app esta disenada para Android TV con control remoto D-pad
- El layout usa panel lateral estilo Leanback para navegacion con D-pad
- Los canales estan hardcodeados en
ChannelRepository.java- no hay backend dinamico - El sistema de actualizaciones depende de Gitea releases con token de autenticacion
- El Device Registry permite bloquear dispositivos remotamente desde un dashboard externo
- NO implementar features de movil como PiP, Chromecast, notificaciones push - el foco es Android TV