bunny_video_player

A Flutter plugin for Bunny Stream playback with native rendering on Android and iOS.

  • Android: Bunny Stream Android player integration
  • iOS: AVPlayer-based native implementation
  • Robust Native -> Dart and Dart -> Native communication
  • PiP, lifecycle handling, playback events, source switching

Supported Platforms

  • Android
  • iOS

Features

  • Native platform view rendering (BunnyVideoView)
  • Controller API (BunnyVideoController)
  • Type-safe Pigeon API (no more manual MethodChannel)
  • Playback controls: play, pause, seek, speed, volume, looping
  • Picture in Picture (Android/iOS)
  • Signed URL refresh
  • Granular native control visibility (show/hide individual buttons)
  • Per-element color customization (progress bar, play/pause, time labels)
  • Flutter overlay controls with auto-hide
  • Real-time streams:
    • playback state
    • position
    • buffered position
    • errors
    • PiP mode state

Requirements

  • Flutter >=3.22.0
  • Dart >=3.0.0 <4.0.0
  • Android minSdk 26
  • iOS 12.0+

Installation

Add dependency:

dependencies:
  bunny_video_player: ^0.2.0

Then run:

flutter pub get

Platform Setup

Android

No manual plugin registration is needed in MainActivity — just use the default FlutterActivity:

class MainActivity : FlutterActivity()

Add android:hardwareAccelerated="true" on the activity for smooth native rendering.

PiP support in your app AndroidManifest.xml activity:

<activity
    android:name=".MainActivity"
    android:hardwareAccelerated="true"
    android:supportsPictureInPicture="true"
    android:resizeableActivity="true"
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" />

iOS

For background playback/PiP behavior, enable audio background mode in Info.plist:

<key>UIBackgroundModes</key>
<array>
  <string>audio</string>
</array>

Example App Secret Handling

Do not hardcode production Bunny credentials in source control.

Run the example with a runtime define:

flutter run \
  --dart-define=BUNNY_LIBRARY_ID=your_library_id \
  --dart-define=BUNNY_VIDEO_ID=your_video_id \
  --dart-define=BUNNY_ACCESS_KEY=your_access_key

Quick Start

import 'package:bunny_video_player/bunny_video_player.dart';

final controller = BunnyVideoController(playerId: 0);

await controller.initialize(
  libraryId: 'your-library-id',
  videoId: 'your-video-id',
  accessKey: 'your-access-key',
  autoPlay: false,
  looping: false,
  allowBackgroundPlayback: true,
);

Render native view:

BunnyVideoView(
  playerId: 0,
  config: const BunnyPlayerViewConfig(),
)

Controller API

await controller.play();
await controller.pause();
await controller.seekTo(const Duration(seconds: 10));
await controller.setPlaybackSpeed(1.25);
await controller.setVolume(0.8);
await controller.setLooping(true);
await controller.enterPictureInPicture();
await controller.exitPictureInPicture();
await controller.refreshSignedUrl('https://...');
await controller.dispose();

Switch to another video source on same controller:

await controller.switchSource(
  libraryId: '596670',
  videoId: 'another-video-id',
  accessKey: 'your-access-key',
  keepPlaybackState: true,
);

Event Streams

controller.playbackStateStream.listen((state) {});
controller.positionStream.listen((position) {});
controller.bufferedStream.listen((buffered) {});
controller.errorStream.listen((message) {});
controller.pipModeStream.listen((isInPip) {});

BunnyPlaybackState values:

  • idle
  • loading
  • ready
  • playing
  • paused
  • buffering
  • completed
  • error

View Configuration

BunnyPlayerViewConfig supports:

Control visibility toggles:

  • showNativeControls — master toggle for all native controls
  • showFullscreenButton, showSettingsButton, showVolumeButton, showSubtitleButton
  • showPlayPauseButton, showRewindButton, showForwardButton
  • showProgressBar, showTimeLabels
  • iosShowsPlaybackControls

General options:

  • applyWhiteIcons, keepScreenOn

Color customization (ARGB integers 0xAARRGGBB):

  • playerBackgroundColorArgb — video surface background
  • controlsIconColorArgb — icon tint color
  • playPauseColorArgb — play/pause button color
  • timeLabelColorArgb — time label text color
  • progressBarColorArgb — progress bar played track color
  • controlsTrackColorArgb — seek track color
  • controlsBufferedColorArgb — buffered stream color
  • controlsBackgroundColorArgb — unplayed track/background color

Layout tuning:

  • controlsIconPaddingDp
  • progressBarTranslationDp
  • progressBarBottomMarginDp

Custom Color Config Example

BunnyPlayerViewConfig(
  showNativeControls: true,
  showProgressBar: true,
  showTimeLabels: true,
  playerBackgroundColorArgb: 0xFF000000,
  progressBarColorArgb: 0xFFFF5722,
  playPauseColorArgb: 0xFFFFFFFF,
  timeLabelColorArgb: 0xFFCCCCCC,
  controlsBufferedColorArgb: 0x66FFFFFF,
  controlsBackgroundColorArgb: 0x33000000,
)

BunnyVideoPlayer Widget

Use BunnyVideoPlayer for a ready-made widget with Flutter overlay controls:

BunnyVideoPlayer(
  controller: controller,
  config: const BunnyPlayerViewConfig(),
  useOverlayControls: true,
  aspectRatio: 16 / 9,
)

Video-Only Surface (videoOnly Config)

To render just the video surface with no controls (useful for custom UI):

BunnyVideoView(
  config: const BunnyPlayerViewConfig.videoOnly(),
)

Error Notes

A Bunny API 404 Not Found means the video is not available for the provided:

  • libraryId
  • videoId
  • accessKey

Validate all three before playback.

Publishing

See PUBLISHING.md for release and pub.dev publish steps.

License

MIT