Playing videos is a common task in app development, and Flutter apps are noexception. In order to play videos, the Flutter team provides thevideo_player plugin. You canuse the video_player plugin to play videos stored on the file system, as anasset, or from the internet.

On iOS, the video_player plugin makes use ofAVPlayer tohandle playback. On Android, it usesExoPlayer.

This recipe demonstrates how to use the video_player package to stream avideo from the internet with basic play and pause controls.

Directions

  • Add the video_player dependency
  • Add permissions to your app
  • Create and initialize a VideoPlayerController
  • Display the video player
  • Play and pause the video

1. Add the video_player dependency

This recipe depends on one Flutter plugin: video_player. First, add thisdependency to your pubspec.yaml.

  1. dependencies:
  2. flutter:
  3. sdk: flutter
  4. video_player:

2. Add permissions to your app

Next, you need to ensure your app has the correct permissions to stream videosfrom the internet. To do so, update your android and ios configurations.

Android

Add the following permission to the AndroidManifest.xml just after the<application> definition. The AndroidManifest.xml can be found at <projectroot>/android/app/src/main/AndroidManifest.xml

  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android">
  2. <application ...>
  3. </application>
  4. <uses-permission android:name="android.permission.INTERNET"/>
  5. </manifest>

iOS

For iOS, you need to add the following to your Info.plist file found at <project root>/ios/Runner/Info.plist.

  1. <key>NSAppTransportSecurity</key>
  2. <dict>
  3. <key>NSAllowsArbitraryLoads</key>
  4. <true/>
  5. </dict>

Warning:The video_player plugin does not work on iOS simulators. You must test videos on real iOS devices.

3. Create and initialize a VideoPlayerController

Now that you have the video_player plugin installed with the correctpermissions, you need to create a VideoPlayerController. TheVideoPlayerController class allows you to connect to different types ofvideos and control playback.

Before you can play videos, you must also initialize the controller. Thisestablishes the connection to the video and prepare the controller for playback.

To create and initialize the VideoPlayerController, please:

  • Create a StatefulWidget with a companion State class
  • Add a variable to the State class to store the VideoPlayerController
  • Add a variable to the State class to store the Future returned from VideoPlayerController.initialize
  • Create and initialize the controller in the initState method
  • Dispose of the controller in the dispose method
  1. class VideoPlayerScreen extends StatefulWidget {
  2. VideoPlayerScreen({Key key}) : super(key: key);
  3. @override
  4. _VideoPlayerScreenState createState() => _VideoPlayerScreenState();
  5. }
  6. class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  7. VideoPlayerController _controller;
  8. Future<void> _initializeVideoPlayerFuture;
  9. @override
  10. void initState() {
  11. // Create an store the VideoPlayerController. The VideoPlayerController
  12. // offers several different constructors to play videos from assets, files,
  13. // or the internet.
  14. _controller = VideoPlayerController.network(
  15. 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
  16. );
  17. _initializeVideoPlayerFuture = _controller.initialize();
  18. super.initState();
  19. }
  20. @override
  21. void dispose() {
  22. // Ensure you dispose the VideoPlayerController to free up resources
  23. _controller.dispose();
  24. super.dispose();
  25. }
  26. @override
  27. Widget build(BuildContext context) {
  28. // Show the video in the next step
  29. }
  30. }

4. Display the video player

Now, it’s time to display the video. The video_player plugin provides theVideoPlayerWidget to display the video initialized by the VideoPlayerController. Bydefault, the VideoPlayer Widget takes up as much space as possible. Thisoften isn’t ideal for videos because they are meant to be displayed in aspecific aspect ratio, such as 16x9 or 4x3.

Therefore, you can wrap the VideoPlayer widget in anAspectRatiowidget to ensure the video is the correct proportions.

Furthermore, you must display the VideoPlayer widget after the_initializeVideoPlayerFuture completes. You can use a FutureBuilder todisplay a loading spinner until finishes initializing. Note: initializing thecontroller does not begin playback.

  1. // Use a FutureBuilder to display a loading spinner while you wait for the
  2. // VideoPlayerController to finish initializing.
  3. FutureBuilder(
  4. future: _initializeVideoPlayerFuture,
  5. builder: (context, snapshot) {
  6. if (snapshot.connectionState == ConnectionState.done) {
  7. // If the VideoPlayerController has finished initialization, use
  8. // the data it provides to limit the Aspect Ratio of the VideoPlayer
  9. return AspectRatio(
  10. aspectRatio: _controller.value.aspectRatio,
  11. // Use the VideoPlayer widget to display the video
  12. child: VideoPlayer(_controller),
  13. );
  14. } else {
  15. // If the VideoPlayerController is still initializing, show a
  16. // loading spinner
  17. return Center(child: CircularProgressIndicator());
  18. }
  19. },
  20. )

5. Play and pause the video

By default, the video starts in a paused state. To begin playback,call theplaymethod provided by the VideoPlayerController. To pause playback, call thepausemethod.

For this example, add a FloatingActionButton to your app that displays a playor pause icon depending on the situation. When the user taps the button, playthe video if it’s currently paused, or pause the video if it’s playing.

  1. FloatingActionButton(
  2. onPressed: () {
  3. // Wrap the play or pause in a call to `setState`. This ensures the correct
  4. // icon is shown
  5. setState(() {
  6. // If the video is playing, pause it.
  7. if (_controller.value.isPlaying) {
  8. _controller.pause();
  9. } else {
  10. // If the video is paused, play it
  11. _controller.play();
  12. }
  13. });
  14. },
  15. // Display the correct icon depending on the state of the player.
  16. child: Icon(
  17. _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
  18. ),
  19. )

Complete Example

  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:video_player/video_player.dart';
  4. void main() => runApp(VideoPlayerApp());
  5. class VideoPlayerApp extends StatelessWidget {
  6. @override
  7. Widget build(BuildContext context) {
  8. return MaterialApp(
  9. title: 'Video Player Demo',
  10. home: VideoPlayerScreen(),
  11. );
  12. }
  13. }
  14. class VideoPlayerScreen extends StatefulWidget {
  15. VideoPlayerScreen({Key key}) : super(key: key);
  16. @override
  17. _VideoPlayerScreenState createState() => _VideoPlayerScreenState();
  18. }
  19. class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  20. VideoPlayerController _controller;
  21. Future<void> _initializeVideoPlayerFuture;
  22. @override
  23. void initState() {
  24. // Create and store the VideoPlayerController. The VideoPlayerController
  25. // offers several different constructors to play videos from assets, files,
  26. // or the internet.
  27. _controller = VideoPlayerController.network(
  28. 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
  29. );
  30. // Initialize the controller and store the Future for later use
  31. _initializeVideoPlayerFuture = _controller.initialize();
  32. // Use the controller to loop the video
  33. _controller.setLooping(true);
  34. super.initState();
  35. }
  36. @override
  37. void dispose() {
  38. // Ensure you dispose the VideoPlayerController to free up resources
  39. _controller.dispose();
  40. super.dispose();
  41. }
  42. @override
  43. Widget build(BuildContext context) {
  44. return Scaffold(
  45. appBar: AppBar(
  46. title: Text('Butterfly Video'),
  47. ),
  48. // Use a FutureBuilder to display a loading spinner while you wait for the
  49. // VideoPlayerController to finish initializing.
  50. body: FutureBuilder(
  51. future: _initializeVideoPlayerFuture,
  52. builder: (context, snapshot) {
  53. if (snapshot.connectionState == ConnectionState.done) {
  54. // If the VideoPlayerController has finished initialization, use
  55. // the data it provides to limit the Aspect Ratio of the Video
  56. return AspectRatio(
  57. aspectRatio: _controller.value.aspectRatio,
  58. // Use the VideoPlayer widget to display the video
  59. child: VideoPlayer(_controller),
  60. );
  61. } else {
  62. // If the VideoPlayerController is still initializing, show a
  63. // loading spinner
  64. return Center(child: CircularProgressIndicator());
  65. }
  66. },
  67. ),
  68. floatingActionButton: FloatingActionButton(
  69. onPressed: () {
  70. // Wrap the play or pause in a call to `setState`. This ensures the
  71. // correct icon is shown
  72. setState(() {
  73. // If the video is playing, pause it.
  74. if (_controller.value.isPlaying) {
  75. _controller.pause();
  76. } else {
  77. // If the video is paused, play it
  78. _controller.play();
  79. }
  80. });
  81. },
  82. // Display the correct icon depending on the state of the player.
  83. child: Icon(
  84. _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
  85. ),
  86. ), // This trailing comma makes auto-formatting nicer for build methods.
  87. );
  88. }
  89. }