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:

Code
flutter pub add better_native_video_player

After the package is fetched, import it where you need the player:

Code
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.

Dart / Flutter
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 autoPlay and looping.
  • Dispose correctly: Call _controller.dispose() in dispose() to release native resources.
  • Render the view: Place BetterNativeVideoView anywhere 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 NSAppTransportSecurity entries 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:
    Code
    <uses-permission android:name="android.permission.INTERNET" />
  • If you need background playback, add the android.permission.FOREGROUND_SERVICE permission 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 mounted before 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.