Skip to main content

playstack 0.1.0-dev.9 copy "playstack: ^0.1.0-dev.9" to clipboard
playstack: ^0.1.0-dev.9 copied to clipboard

Short-video feeds and native video playback for Flutter: a one-widget reels feed with replaceable controls, player pooling, preloading and lifecycle management.

playstack #

Short-video feeds and native video playback for Flutter. Put a Reels/Shorts/TikTok-style feed on screen with one widget, or drive single players yourself. PlayStack handles the native players, preloading, memory, network and lifecycle.

Engines: AndroidX Media3 ExoPlayer (Android), AVFoundation (iOS) and HTMLVideoElement (web).

The demo app: a reels feed with likes, then a drama series with a locked episode

Features #

  • One-widget feed. PlayStackFeedView takes your items and does the rest: paging, playing the video in view, preparing the next ones, loading more, posters, fullscreen.
  • Instant swipes. A bounded pool of native players reused by priority. The next videos are prepared ahead within network, memory and decoder limits, and stale preparations are cancelled when the user swipes fast.
  • Replaceable controls. Default controls (tap or hold to pause, sound, fullscreen, speed and subtitles, a seekable progress bar, buffering, retry), your own layer on top, or your own controls from reusable parts.
  • Mixed feeds. Ads and cards between videos, locked (paid) episodes, and feeds prepared on the splash screen.
  • Transitions and direction. Slide, parallax, stack, fade, zoom, cube or your own; vertical or horizontal, normal or reversed.
  • App-aware. Pauses under pushed routes, in hidden tabs and in the background. Pull to refresh and watch-time reports are one callback each.
  • Disk cache, fullscreen with orientation restore, audio focus and interruptions, automatic retry, tracks and subtitles, typed errors.

Install #

flutter pub add playstack
Minimum
Flutter / Dart 3.47 / 3.13
Android API 24
iOS 15.0

No platform setup is needed for HTTPS videos. For http:// URLs, HLS in non-Safari browsers and the iOS silent switch, see Installation.

A feed in one widget #

import 'package:playstack/playstack.dart';

PlayStackFeedView<Post>(
  items: posts,
  videoUrl: (post) => post.videoUrl,
  posterUrl: (post) => post.thumbnailUrl,  // optional: shown until the first frame
  onLoadMore: () => api.fetchMorePosts(),  // optional: return [] at the end
)

A list of URL strings needs nothing else: PlayStackFeedView(items: urls).

Your UI on top #

controlsBuilder gets each page, with your item typed as page.data:

PlayStackFeedView<Post>(
  items: posts,
  videoUrl: (post) => post.videoUrl,
  controlsBuilder: (context, page) => PlayStackDefaultControls(
    page: page,
    onDoubleTap: () => like(page.data),
    child: PostCaption(post: page.data),   // your caption, buttons, avatar
  ),
)

Replace the defaults completely with your own widget; PlayStackProgressBar, PlayStackBufferingIndicator and PlayStackMuteButton are there to reuse.

Everything else is optional #

PlayStackFeedView<Post>(
  items: posts,
  videoUrl: (post) => post.videoUrl,
  transition: PlayStackFeedTransition.stack,         // slide, parallax, stack, fade, zoom, cube, custom
  scrollDirection: Axis.horizontal,             // stories, carousels
  onRefresh: () => api.fetchPosts(page: 0),     // pull to refresh; off when null
  onItemViewed: (view) => analytics.watched(    // called when the user leaves a video
    view.data.id, view.watchTime, view.completed,
  ),
  controller: viewController,                   // nextPage, jumpToItem, fullscreen, mute, pause
)

Ads, locked episodes and splash preloading #

PlayStackFeedView<Entry>(
  items: entries,
  videoUrl: (e) => e is Video ? e.url : null,        // null: a page without video
  pageBuilder: (context, e, isActive) => AdCard(e as Ad),
  isLocked: (e) => e is Video && !e.unlocked,        // never prepared or played
  lockedBuilder: (context, e, isActive) => Paywall(e as Video),
)

// On the splash screen: the first videos are ready before the feed opens.
final reels = PlayStackFeedPreload<Post>(items: posts, videoUrl: (p) => p.url);
PlayStackFeedView<Post>.preloaded(reels);

Series #

The same widget plays a series: open it at an episode, continue where the user stopped and move on when an episode ends.

PlayStackFeedView<Episode>(
  items: series.episodes,
  videoUrl: (episode) => episode.url,
  initialIndex: series.episodes.indexOf(tapped),
  startPosition: (episode) => progress[episode.id],           // continue watching
  onItemViewed: (view) => progress[view.data.id] = view.position,
  autoAdvance: true,                                          // next episode
)

viewController.jumpToItem(series.episodes[7]);               // episode list

A single player #

final manager = PlayStackManager();
await manager.initialize();
final controller = manager.createController(
  PlayStackSource.network('https://example.com/video.m3u8'),
);

PlayStackVideoView(controller: controller, fit: BoxFit.cover);  // frames only, no controls
await controller.play();                                   // prepares on demand

await manager.dispose();                                   // releases every player

PlayStackPlayerController is a ValueListenable<PlayStackPlaybackState>: build your controls from it.

Platform support #

Android iOS Web
HLS / DASH Yes / Yes Yes / No Safari or HLS.js / No
Network, asset, memory sources Yes Yes Yes (no custom headers)
File sources Yes Yes No
Disk cache Progressive + HLS/DASH segments Progressive Browser cache
Fullscreen and orientation Yes Yes Fullscreen API

Full matrix. PlayStackPlatformCapabilities reports what the running engine supports.

Learn more #

  • Guides: feeds, controller, manager, preloading, caching, fullscreen, audio, subtitles, errors, performance
  • Demo app: a reels app (likes, comments, explore grid, live stats) and a drama app (episodes, continue watching, episode list)
  • Benchmarks
  • Issues

Development preview: verified on an Android emulator, an iOS simulator and headless Chromium; not yet on physical devices.

0
likes
160
points
--
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Short-video feeds and native video playback for Flutter: a one-widget reels feed with replaceable controls, player pooling, preloading and lifecycle management.

Homepage
Repository (GitHub)
View/report issues

Topics

#video #video-player #media #feed #preload

License

MIT (license)

Dependencies

flutter, playstack_android, playstack_ios, playstack_platform_interface, playstack_web

More

Packages that depend on playstack

Packages that implement playstack