Advanced Music Player Plugin

A feature-rich Flutter music player plugin providing advanced playback controls, background audio support, local file management, and reactive UI widgets.

Features

  • Background Playback: seamless audio playback even when the app is minimized or the screen is off (powered by MediaSessionService on Android and background modes on iOS).
  • Queue Management: standard queue operations including next, previous, seek, shuffle, and repeat modes.
  • Local Audio Fetching: Automatically scan and play local audio files from the device storage.
  • Duration Synchronization: Accurate, reactive tracking of current playback position and total track duration.
  • Reactive UI Widgets: Built-in state management for position streams and player state, making UI updates smooth and efficient.
  • Permission Handling: built-in methods to request necessary storage/audio permissions, handling Android 13+ differences transparently.

Architecture

This plugin uses a MethodChannel to communicate between Flutter and the native platform:

  • Android: Implemented using androidx.media3 (ExoPlayer) within a MediaSessionService. This ensures the player is identified by the OS as a media playback service, allowing controlling from the notification shade and lock screen.
  • iOS: (Implementation pending/Coming soon) Uses AVAudioPlayer or AVPlayer.

The Flutter side provides a singleton AdvancedMusicPlayer class that exposes streams (playerStateStream, positionStream, durationStream) for reactive UI updates.

Setup

Android

  1. Permissions: Ensure your android/app/src/main/AndroidManifest.xml includes the necessary permissions (automatically handled if you use the plugin's requestStoragePermission()):

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
    <!-- Dynamically requested at runtime -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
    
  2. Service Declaration: The plugin automatically declares its MusicService in its own manifest, which is merged with your app's manifest. No extra manual service declaration is typically needed in your app's AndroidManifest.xml.

iOS

  1. Add the following keys to your Info.plist:
    • UIBackgroundModes: Add audio to allow background playback.
    • NSMicrophoneUsageDescription: (If required by store submission, though typically not used for playback only).
    • NSAppleMusicUsageDescription: For accessing media library.

Usage

Initialization

Initialize the player early in your app lifecycle.

final player = AdvancedMusicPlayer();
await player.initialize();

Permissions & Local Files

To fetch local songs, request permission first. The plugin handles the complexity of Android 13+ vs older versions.

// Request permission
bool granted = await player.requestStoragePermission();

if (granted) {
  // Fetch system audio files
  List<AudioTrack> localSongs = await player.getSystemAudioFiles();
  
  // Set queue and play
  await player.setQueue(localSongs);
}

Playback Controls

// Play specific URL
await player.playUrl(
  'https://example.com/song.mp3',
  title: 'My Song',
  artist: 'Great Artist',
);

// Standard controls
await player.play();
await player.pause();
await player.stop();
await player.next();
await player.previous();
await player.seek(Duration(seconds: 30));

// Modes
player.setShuffleMode(true);
player.setRepeatMode(RepeatMode.all); // none, all, one

Reactive UI Widgets

The plugin includes pre-built widgets that listen to the player's streams, removing the need for setState boilerplate in your UI.

AdvancedPlayerSlider

A slider that automatically updates with playback position and lets the user drag to seek. It now automatically syncs with the track's duration.

AdvancedPlayerSlider(
  activeColor: Colors.blue,
  inactiveColor: Colors.grey,
  thumbColor: Colors.blueAccent,
  timeLabelStyle: TextStyle(color: Colors.black),
)

PlayPauseButton

A button that toggles between Play and Pause states with a smooth transition animation.

PlayPauseButton(
  size: 48.0,
  color: Colors.blue,
  playIcon: Icons.play_arrow,
  pauseIcon: Icons.pause,
  // Optional: Use custom widgets instead of icons
  playWidget: SvgPicture.asset('assets/play.svg'),
  pauseWidget: SvgPicture.asset('assets/pause.svg'),
  animationDuration: Duration(milliseconds: 300),
  // Optional: Custom animation (e.g., Rotation)
  transitionBuilder: (child, animation) {
    return RotationTransition(turns: animation, child: child);
  },
)

API Reference

AdvancedMusicPlayer

  • Future<void> initialize(): Sets up method channels and listeners.
  • Stream<Duration> get positionStream: Emits standard playback position updates.
  • Stream<Duration> get durationStream: Emits the total duration of the current track.
  • Stream<PlayerState> get playerStateStream: Emits stopped, playing, paused, or buffering.
  • Future<bool> requestStoragePermission(): Requests platform-appropriate storage/audio permissions.
  • Future<List<AudioTrack>> getSystemAudioFiles(): Scans device for audio files.
  • Future<void> setQueue(List<AudioTrack> tracks, {int initialIndex}): Replaces current queue and plays.
  • Future<void> playUrl(...): Plays a single track immediately.

AudioTrack

A simple data class for track info:

  • String source: URL or file path.
  • String title: Track title.
  • String artist: Artist name.
  • String artworkUrl: (Optional) URL for album art.