Perché la riproduzione video è importante
Sempre più applicazioni integrano contenuti video: tutorial, corsi online, feed social, streaming di eventi. In Flutter la gestione dei video passa dal pacchetto ufficiale video_player, mantenuto dal team di Google, che sfrutta le API native (ExoPlayer su Android e AVPlayer su iOS) e HTML5 sul Web.
In questa guida vedremo come riprodurre video locali e in streaming, come gestire il ciclo di vita del controller e come aggiungere una UI di controlli professionale con il pacchetto chewie.
Installazione delle dipendenze
Aggiungi i pacchetti al tuo pubspec.yaml:
dependencies:
video_player: ^2.9.1
chewie: ^1.8.5
Configurazione delle piattaforme
Per riprodurre video da internet su Android, assicurati di avere il permesso di rete in android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
Su iOS, se il video usa HTTP (non HTTPS), devi abilitare le eccezioni ATS nel file ios/Runner/Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Riproduzione base con video_player
Il cuore del pacchetto è il VideoPlayerController. Va inizializzato in modo asincrono e va sempre rilasciato con dispose() per evitare memory leak.
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class VideoBaseScreen extends StatefulWidget {
const VideoBaseScreen({super.key});
@override
State<VideoBaseScreen> createState() => _VideoBaseScreenState();
}
class _VideoBaseScreenState extends State<VideoBaseScreen> {
late final VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.networkUrl(
Uri.parse(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
),
)..initialize().then((_) {
setState(() {}); // ridisegna quando il video è pronto
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: const CircularProgressIndicator(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
}
Costruttori disponibili
Il controller offre diverse sorgenti:
VideoPlayerController.networkUrl(Uri)— video in streaming da URL.VideoPlayerController.asset('assets/video.mp4')— video incluso nell'app.VideoPlayerController.file(File)— video dal file system del dispositivo.
Ricorda di dichiarare gli asset video nel pubspec.yaml:
flutter:
assets:
- assets/video.mp4
Aggiungere la barra di avanzamento
Il pacchetto include il widget VideoProgressIndicator, che mostra lo stato di buffering e permette lo scrubbing:
VideoProgressIndicator(
_controller,
allowScrubbing: true,
colors: const VideoProgressColors(
playedColor: Colors.red,
bufferedColor: Colors.grey,
),
)
Controlli professionali con Chewie
Costruire da zero una UI completa (play/pausa, fullscreen, timeline, velocità di riproduzione) è laborioso. chewie fornisce tutto questo con pochissimo codice, avvolgendo il VideoPlayerController.
import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class ChewieScreen extends StatefulWidget {
const ChewieScreen({super.key});
@override
State<ChewieScreen> createState() => _ChewieScreenState();
}
class _ChewieScreenState extends State<ChewieScreen> {
late final VideoPlayerController _videoController;
ChewieController? _chewieController;
@override
void initState() {
super.initState();
_init();
}
Future<void> _init() async {
_videoController = VideoPlayerController.networkUrl(
Uri.parse(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
),
);
await _videoController.initialize();
_chewieController = ChewieController(
videoPlayerController: _videoController,
autoPlay: false,
looping: false,
allowPlaybackSpeedChanging: true,
aspectRatio: _videoController.value.aspectRatio,
errorBuilder: (context, errorMessage) {
return Center(child: Text(errorMessage));
},
);
setState(() {});
}
@override
void dispose() {
_videoController.dispose();
_chewieController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Chewie Player')),
body: Center(
child: _chewieController != null &&
_chewieController!
.videoPlayerController.value.isInitialized
? Chewie(controller: _chewieController!)
: const CircularProgressIndicator(),
),
);
}
}
Opzioni utili di ChewieController
autoPlayeloopingper il comportamento di riproduzione.allowFullScreenedeviceOrientationsOnEnterFullScreenper gestire il fullscreen.allowPlaybackSpeedChangingconplaybackSpeedsper le velocità.materialProgressColors/cupertinoProgressColorsper personalizzare i colori.showControlsOnInitializeper mostrare i controlli all'avvio.
Gestire il ciclo di vita
Un errore comune è non mettere in pausa il video quando l'app va in background o quando l'utente naviga altrove. Con WidgetsBindingObserver puoi intercettare i cambi di stato:
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) {
_videoController.pause();
}
}
Non dimenticare di registrare (addObserver) e rimuovere (removeObserver) l'observer rispettivamente in initState e dispose.
Consigli pratici
- Non ricreare il controller a ogni build: inizializzalo una sola volta in
initState. - Chiama sempre
dispose()su entrambi i controller per liberare risorse native. - Per lo streaming HLS/DASH usa direttamente l'URL del manifest (
.m3u8); le piattaforme native lo supportano nativamente. - Gestisci gli errori tramite
errorBuilderdi Chewie o ascoltandocontroller.value.hasError. - Su liste con molti video, valuta il lazy loading e metti in pausa quelli fuori dallo schermo per non saturare la memoria.
Conclusioni
Con video_player hai il controllo completo e a basso livello sulla riproduzione, mentre chewie ti offre un'interfaccia pronta all'uso e altamente personalizzabile. La combinazione dei due copre la maggior parte dei casi d'uso, dai semplici video introduttivi ai player di streaming completi. La chiave per un'esperienza fluida resta sempre la corretta gestione del ciclo di vita dei controller.
