When to Choose better_native_video_player
The better_native_video_player Flutter package is designed for apps that need reliable, low‑latency video playback on iOS and Android. It delegates rendering to the native AVPlayer (iOS) and ExoPlayer (Android), which means you get smooth adaptive HLS streaming, DRM support, casting (Chromecast/AirPlay), picture‑in‑picture (PiP), and background playback without the frame‑dropping issues common in pure‑Dart players.
Use this package when you are building:
- Live‑sports or news streaming apps that require adaptive bitrate switching.
- On‑demand video libraries or educational platforms with protected (DRM) content.
- Social apps that display short clips and need fast start‑up times.
- Apps that want to cast video to a TV or use PiP on mobile.
Note: The package does not support web or desktop targets, and it adds native binaries to your app size.
Installation
Add the dependency with the Flutter CLI:
flutter pub add better_native_video_playerAfter the package is fetched, import it where you need the player:
import 'package:better_native_video_player/better_native_video_player.dart';Basic Usage – A Minimal Video Player
The following example shows a complete, runnable widget that plays an HLS stream, toggles fullscreen, and disposes the controller correctly.
import 'package:flutter/material.dart';
import 'package:better_native_video_player/better_native_video_player.dart';
class VideoDemo extends StatefulWidget {
const VideoDemo({Key? key}) : super(key: key);
@override
State<VideoDemo> createState() => _VideoDemoState();
}
class _VideoDemoState extends State<VideoDemo> {
late final BetterNativeVideoController _controller;
@override
void initState() {
super.initState();
_controller = BetterNativeVideoController(
url: 'https://example.com/stream.m3u8',
autoPlay: true,
looping: false,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Better Native Video Player')),
body: Center(
child: BetterNativeVideoView(controller: _controller),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _controller.toggleFullScreen(),
child: const Icon(Icons.fullscreen),
),
);
}
}This snippet demonstrates the core API:
BetterNativeVideoController– creates and configures the native player.BetterNativeVideoView– a widget that renders the video surface.toggleFullScreen()– switches between embedded and fullscreen modes.
Step‑by‑step breakdown
- Controller creation: Provide the stream URL and optional flags such as
autoPlayandlooping. - Dispose correctly: Call
_controller.dispose()indispose()to release native resources. - Render the view: Place
BetterNativeVideoViewanywhere in your widget tree. It respects the surrounding layout constraints. - Full‑screen toggle: Use the controller method or listen to UI events to enter/exit fullscreen.
Platform‑Specific Setup
Because the player uses native SDKs, you must add a few configuration steps for each platform.
iOS
- Add
NSAppTransportSecurityentries if you are loading non‑HTTPS streams. - Enable Background Modes → Audio, AirPlay, and Picture in Picture in Xcode.
- Provide a usage description for the microphone or camera only if you plan to record; otherwise it is not required.
Android
- In
android/app/src/main/AndroidManifest.xml, ensure you have the Internet permission:<uses-permission android:name="android.permission.INTERNET" /> - If you need background playback, add the
android.permission.FOREGROUND_SERVICEpermission and declare a foreground service type. - For casting, include the Google Cast SDK as described in the package README.
Tip: Test on a physical device for both iOS and Android. Emulators may not expose hardware‑accelerated decoding, which can hide performance issues.
Common Pitfalls & How to Avoid Them
- Missing native permissions: Forgetting to add the required Android permissions or iOS background modes will cause playback to stop when the app is backgrounded.
- Using the controller after disposal: Always check
mountedbefore calling controller methods from async callbacks. - Incorrect URL scheme: The player expects a direct HLS (.m3u8) or MP4 URL. Redirects or signed URLs that change after the controller is created may fail.
- Mixing with other video players: Because the native view occupies a platform view, stacking it with other platform views can cause z‑order issues on Android. Keep the video view at the top of the stack or use a dedicated route for fullscreen.
Advanced Features (Optional)
If your project needs more than basic playback, the controller exposes additional flags and methods:
drmLicenseUrl– configure Widevine or FairPlay DRM.enableCasting– turn on Chromecast/AirPlay UI.enablePictureInPicture– activate PiP on supported devices.setPlaybackSpeed(double speed)– change playback rate.
Refer to the official documentation on pub.dev for the exact API signatures and platform‑specific notes.
Next Steps
After you have the basic player working, consider integrating it with your state‑management solution (Provider, Riverpod, Bloc, etc.) to react to network changes, user preferences, or analytics events.
For any uncertainty—especially around DRM licensing or casting—consult the package README and the platform SDK docs.
Frequently Asked Questions
Does better_native_video_player work on web or desktop?
No. The package currently supports only iOS and Android because it relies on AVPlayer and ExoPlayer. For web or desktop you need a different solution such as video_player or better_player.
What permissions are required for background playback on Android?
You must add <code>android.permission.FOREGROUND_SERVICE</code> and declare a foreground service type in the AndroidManifest. Also ensure the <code>INTERNET</code> permission is present.
Can I use the player with Riverpod or Bloc?
Yes. The controller is a regular Dart object, so you can provide it via Provider, Riverpod, Bloc, or any other state‑management approach. Just make sure to dispose the controller when the owning widget is removed.
How do I enable DRM protected streams?
Pass the DRM license URL (e.g., Widevine or FairPlay) to the <code>BetterNativeVideoController</code> constructor using the <code>drmLicenseUrl</code> parameter. Check the package README for the exact property name and platform‑specific requirements.