Play local video on flutter web

Hitesh Verma
3 min readNov 21, 2020

Using VideoElement and HTMLElementView …

Photo by Jakob Owens on Unsplash

When it comes to playing a video in flutter we often go for the very renowned package video_player, which is suitable for most of the cases.

But at present, this package comes with certain limitations. Since the flutter web platform does not support dart:io, due to which VideoPlayerController.file cannot be used. So we are only left with options to add our videos as an asset or upload them to a server before playing on the web using VideoPlayerController.asset and VideoPlayerController.network respectively.

Here is the good news! Flutter is a very powerful framework that gives us the flexibility to create and display HTML elements on its web platform.

We are going to create a VideoElement and display it as a widget using HTMLElementView in our app. Now, fasten your belts :-)

Play local video on flutter web
Play local video on flutter web

Add some dependencies to your pubspec.yaml file.

universal_html: <latest_version>

Setup your UI.

main.dart file

import 'package:flutter/material.dart';
import 'package:local_video_player/video_setup.dart';
import './main.dart' if (dart.library.html) 'dart:ui' as ui;
void main() => runApp(MyApp());class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> { String _videoSrc;
final String _localVideoPlayerId = 'local-video-player';
// TODO: VideoSetup class to be defined later
final VideoSetup _videoSetup = VideoSetup();
// TODO: to be completed later
Future<void> _registerNativeVideoPlayer() async{}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: (_videoSrc == null)
? FlatButton(
onPressed: () => _registerNativeVideoPlayer(),
child: Text('Upload Video'),
)
: SizedBox(
width: 200,
height: 200,
// This won't work for now
child: HtmlElementView(viewType: _localVideoPlayerId),
),
),
),
);
}
}
/// dummy class to resolve dart:ui and analyzer issues
class platformViewRegistry {
static registerViewFactory(String viewId, dynamic cb) {}
}

Create a class video_setup.dart that contains the logic to upload a video file from the system and to create a video element with src as the uploaded video URL.

import 'dart:async';
import 'package:universal_html/html.dart' as html;
class VideoSetup{ static VideoSetup _videoSetup; VideoSetup._internal(); factory VideoSetup(){
if(_videoSetup == null) _videoSetup = VideoSetup._internal();
return _videoSetup;
}
/// to upload a video from the system
/// and create a url from it

Future<String> getLocalVideoUrl() async{
final completer = Completer<String>(); // create input element to upload video file from the system
html.InputElement uploadInput = html.FileUploadInputElement();
uploadInput.accept = 'video/*';
uploadInput.click();
uploadInput.onChange.listen((e){
final files = uploadInput.files;
if(files.length > 0){
final file = files[0];
String url = html.Url.createObjectUrl(file);
completer.complete(url);
}
});
return completer.future;
}
/// to create a video element with provided src
html.VideoElement createVideoElement(String src){
return html.VideoElement()
..controls = true
..autoplay = true
..src = src;
}
}

To embed the VideoElement as a widget, you need to first register it with the platform.

This method has already been declared in the _MyAppState class.

/// get video src, create a video element and 
/// register the platform view for this element

Future<void> _registerNativeVideoPlayer() async{
_videoSrc = await _videoSetup.getLocalVideoUrl(); final res = await ui.platformViewRegistry.registerViewFactory(
_localVideoPlayerId,
(int id) => _videoSetup.createVideoElement(_videoSrc)
);
if(res) setState((){});
}

Now you can use this _localVideoPlayerId to display the VideoElement as a widget using HTMLElementView.

HtmlElementView(viewType: _localVideoPlayerId)

Useful References

Final Thoughts

The platform view’s lifetime is the same as the lifetime of the State object for this widget and each platform view requires a unique viewType id.

To upload multiple videos you will need different viewType ids for each VideoElement created.

Whenever the video src changes, you will need to create another VideoElement and register it with a new unique viewType id.

CAUTION: Embedding HTML is an expensive operation and should be avoided when a Flutter equivalent is possible.

Know us if this article helped you by clapping :-)

--

--