aves_mio0.31/plugins/google_cast/ARCHITETTURA_PLUGIN.md
2026-07-18 13:39:22 +02:00

11 KiB
Raw Permalink Blame History

Plugin plugins/google_cast Come funziona

Questo documento descrive larchitettura e il flusso di funzionamento del plugin plugins/google_cast del progetto, sulla base della struttura riportata e dei file analizzati durante il debug.


1. Obiettivo del plugin

Il plugin google_cast fa da ponte tra Flutter/Dart e il layer nativo Android per gestire:

  • Google Cast standard (Chromecast / Android TV con receiver standard)
  • Custom Receiver (receiver web / CAF)
  • il dialog nativo di selezione device
  • comandi media (play, pause, seek, queue, volume, mute)
  • eventi di ritorno verso Flutter (cast connesso, cast fermato, cambio item queue, errori, ecc.)

In pratica:

  • Flutter decide quando connettersi e quale media mandare
  • il plugin Android parla con le API Google Cast
  • il receiver (standard o custom) riproduce davvero i contenuti sul TV/device Cast

2. Struttura del plugin

plugins/google_cast
|-- android
|   |-- build.gradle.kts
|   |-- settings.gradle.kts
|   `-- src/main/kotlin/com/aves/google_cast
|       |-- CastActivityProvider.kt
|       |-- CastOptionsProvider.kt
|       |-- FlutterCastFrameworkPlugin.kt
|       `-- cast
|           |-- CastContextManager.kt
|           |-- CastCustomReceiver.kt
|           |-- CastDialogLauncher.kt
|           |-- CastMediaClient.kt
|           |-- CastQueueManager.kt
|           `-- CastSessionHandler.kt
|-- lib
|   `-- google_cast.dart
`-- pubspec.yaml

3. Ruolo dei file principali

lib/google_cast.dart

È lentry point Dart del package/plugin.

In molti plugin Flutter questo file fa una o più di queste cose:

  • espone API pubbliche al codice Dart
  • definisce wrapper leggeri verso il MethodChannel
  • centralizza eventuali modelli / helper lato Flutter

Nel tuo progetto, il vero orchestratore lato app non è qui ma nei controller di app (cast_controller.dart, google_cast_controller.dart, custom_cast_controller.dart).


android/src/main/kotlin/com/aves/google_cast/FlutterCastFrameworkPlugin.kt

È il file principale del plugin Flutter lato Android.

Responsabilità

  • registra il MethodChannel('google_cast')
  • riceve le chiamate da Flutter (showCastDialog, loadQueue, play, pause, seekTo, getVolume, ecc.)
  • smista ogni metodo verso i componenti modulari del package cast/
  • aggancia il plugin al ciclo di vita dellActivity
  • inizializza i componenti principali del Cast:
    • CastContextManager
    • CastSessionHandler
    • CastMediaClient
    • CastQueueManager
    • CastDialogLauncher
    • CastCustomReceiver

È il router centrale del plugin.


CastContextManager.kt

Gestisce il CastContext e laccesso alla sessione corrente.

In pratica gestisce:

  • lActivity attuale
  • linizializzazione di CastContext
  • il recupero della sessione Cast attiva
  • il recupero del RemoteMediaClient

Metodi tipici/attesi

  • attachActivity(activity)
  • detachActivity()
  • ensureCastContext()
  • getSession()
  • getClient()

È il punto base da cui gli altri oggetti ottengono la sessione Cast corrente e il media client corrente.


CastSessionHandler.kt

Gestisce gli eventi di sessione Cast.

Di solito si occupa di:

  • onSessionStarting
  • onSessionStarted
  • onSessionResumed
  • onSessionEnded
  • invio eventi verso Flutter, ad esempio:
    • onCastReady
    • onCastStopped

Nel tuo flusso attuale, onCastReady viene usato per segnalare una sessione connessa, ma non necessariamente un media già caricato.


CastDialogLauncher.kt

Si occupa di aprire il dialog nativo di scelta dispositivo Cast.

Tipicamente fa:

  • crea/configura un MediaRouteButton
  • invoca il bottone o mostra il picker Cast
  • consente allutente di scegliere il device

Quando Flutter chiama showCastDialog, il plugin passa il comando a CastDialogLauncher, che mostra il picker dispositivo.


CastMediaClient.kt

Gestisce i comandi media e il callback del RemoteMediaClient.

Responsabilità principali

  • play()
  • pause()
  • seek(position)
  • getMediaStatus()
  • getVolume()
  • setVolume(v)
  • setMute(m)
  • registrazione del callback sul RemoteMediaClient

Perché è cruciale

Fa due cose fondamentali:

  1. Comandi verso Google Cast

    • play / pause
    • seek
    • volume / mute
  2. Eventi da Google Cast verso Flutter

    • onQueueIndexChanged
    • onVideoFinished
    • onCastError

È fondamentale per slideshow e sincronizzazione UI.


CastQueueManager.kt

Gestisce la queue dei media Cast.

Responsabilità tipiche

  • loadQueue(items, startIndex)
  • next()
  • prev()
  • costruzione di MediaQueueItem
  • associazione metadati per item (titolo, mimeType, flags foto/video, customData)

È il file che determina come una lista Flutter di media diventa una vera queue Google Cast.


CastCustomReceiver.kt

Gestisce il Custom Receiver CAF / Web Receiver.

Responsabilità

  • avvio del receiver custom con receiverUrl
  • invio messaggi JSON al receiver web
  • ricezione/gestione del namespace custom (se implementato)

Nel tuo progetto, Flutter costruisce un URL tipo:

https://.../cast_receiver/receiver.html?ws=...

e poi chiama startCustomReceiver.


CastActivityProvider.kt

Aiuta a dare accesso allActivity giusta o a integrare il plugin con lhost Android.


CastOptionsProvider.kt

È il provider di configurazione Google Cast lato Android.

Tipicamente definisce:

  • receiver application ID di default
  • eventuali opzioni del framework Cast

4. Flusso end-to-end: Google Cast standard

A. Connessione del device

  1. Flutter preme licona Cast
  2. chiama showCastDialog
  3. FlutterCastFrameworkPlugin.kt inoltra a CastDialogLauncher.kt
  4. lutente sceglie il device
  5. CastSessionHandler.kt riceve onSessionStarted
  6. il plugin manda a Flutter onCastReady

B. Caricamento media

Quando lutente preme:

  • cast manuale
  • fullscreen cast
  • slideshow

Flutter costruisce una queue e chiama loadQueue.

Il plugin passa il tutto a CastQueueManager.loadQueue(...), che crea i MediaQueueItem e li carica nel RemoteMediaClient.

C. Controlli playback

Dai controller Flutter partono metodi come:

  • playCast()
  • pauseCast()
  • seekCast()
  • nextManual()
  • prevManual()
  • setCastVolume()
  • toggleMuteCast()

Questi passano dal MethodChannel, arrivano a FlutterCastFrameworkPlugin.kt e poi vengono gestiti da:

  • CastMediaClient.kt
  • CastQueueManager.kt

D. Eventi di ritorno verso Flutter

Dal native tornano eventi come:

  • onCastReady
  • onCastStopped
  • onQueueIndexChanged
  • onVideoFinished
  • onCastError

Questi aggiornano in Flutter:

  • icona Cast
  • indice corrente
  • stato play/pause
  • posizione/durata
  • slideshow timer foto/video

5. Flusso end-to-end: Custom Receiver

A. Connessione/sessione

Flutter chiama:

  • showCastDialog
  • startCustomReceiver(appId, receiverUrl)

Il plugin passa a CastCustomReceiver.kt, che avvia il receiver web.

B. Caricamento media

Flutter non usa loadQueue standard, ma manda messaggi custom JSON al receiver, ad esempio:

  • LOAD_QUEUE
  • PLAY
  • PAUSE
  • SEEK
  • NEXT
  • PREV
  • SET_VOLUME
  • SET_MUTE
  • GET_VOLUME
  • GET_MEDIA_STATUS

C. Eventi verso Flutter

Il receiver web risponde con messaggi come:

  • MEDIA_STATUS
  • VOLUME_STATUS
  • CAST_READY
  • CAST_STOPPED

che il CustomCastController usa per aggiornare la UI Flutter.


6. Differenza tra Google Cast standard e Custom

Google Cast standard

  • il volume è nativo via CastSession
  • la queue è gestita dal framework Cast
  • il passaggio video → next è naturale se la queue è corretta
  • RemoteMediaClient.Callback è fondamentale

Custom Receiver

  • il volume ha senso solo se il receiver web lo implementa davvero
  • le foto/video vengono gestiti dalla tua logica JS/CAF
  • gli eventi stato/volume dipendono dal receiver
  • è più flessibile ma più facile da rompere

7. Punto delicato emerso nel debug

Durante il refactor si è visto che una distinzione è fondamentale:

Connettere il device != aver già caricato un media

Quindi il comportamento corretto è:

  • onCastReady = sessione pronta
  • NO polling immediato se la queue è ancora vuota
  • il polling deve partire solo dopo loadQueue

Altrimenti il plugin rischia di generare:

  • Invalid Request
  • MediaQueue error
  • IDLE_REASON_ERROR

8. Responsabilità lato Flutter (fuori dal plugin ma essenziali)

Anche se non sono dentro plugins/google_cast, lato app ci sono controller importanti:

  • cast_controller.dart → controller unificato backend
  • google_cast_controller.dart → orchestrazione Google standard
  • custom_cast_controller.dart → orchestrazione custom receiver

Questi file decidono:

  • quando aprire il dialog Cast
  • quando connettere il device
  • quando mandare davvero una queue
  • quando mostrare controlli / slideshow / fullscreen viewer

Il plugin Android da solo non basta: è il layer Dart che decide il flusso UX.


9. Mappa rapida responsabilità

Flutter / UI

  • pulsante Cast
  • selection mode
  • slideshow/manual/fullscreen
  • bottom sheet controlli

cast_controller.dart

  • facade unificata Google / Custom / DLNA

google_cast_controller.dart

  • queue standard Cast
  • slideshow foto/video lato Flutter
  • polling media/volume

custom_cast_controller.dart

  • invio messaggi JSON al receiver custom
  • stato custom receiver

FlutterCastFrameworkPlugin.kt

  • router MethodChannel lato Android

CastContextManager.kt

  • CastContext + session + media client

CastSessionHandler.kt

  • session lifecycle → eventi verso Flutter

CastQueueManager.kt

  • queue standard Google Cast

CastMediaClient.kt

  • play/pause/seek/volume + callback eventi media

CastCustomReceiver.kt

  • custom receiver CAF/web

CastDialogLauncher.kt

  • dialog selezione device

10. Se devi debuggare il plugin in futuro

Ordine consigliato per capire dove si rompe qualcosa:

Se non si connette il device

  • FlutterCastFrameworkPlugin.kt
  • CastDialogLauncher.kt
  • CastSessionHandler.kt
  • CastContextManager.kt

Se si connette ma non parte il media

  • CastQueueManager.kt
  • CastMediaClient.kt
  • google_cast_controller.dart

Se slideshow si ferma o salta male foto/video

  • google_cast_controller.dart
  • CastMediaClient.kt (callback onQueueIndexChanged)
  • eventualmente CastQueueManager.kt

Se il Custom receiver ha problemi UI / progress / volume

  • CastCustomReceiver.kt
  • receiver web (receiver.html, JS)
  • custom_cast_controller.dart

Se il volume non si aggiorna

  • CastMediaClient.kt
  • google_cast_controller.dart
  • widget controlli Flutter (cast_controls_sheet.dart, fullscreen viewer)

11. Conclusione

Il plugin google_cast del progetto è organizzato in modo modulare e separa bene le responsabilità:

  • il file principale FlutterCastFrameworkPlugin.kt riceve i comandi Flutter
  • il package cast/ contiene i moduli Android specializzati
  • i controller Flutter coordinano UX, queue e sincronizzazione stato

Il punto più delicato dellarchitettura è la distinzione tra:

  • sessione Cast connessa
  • media realmente caricato sulla queue

Capire bene questa differenza evita gran parte dei bug visti in debug.