flutter_media_controller

A Flutter plugin that leverages Android's built-in APIs to detect and control media playback from your Flutter application.

Features

  • Detect currently playing media information (title, artist, playing status, thumbnail)
  • Control media playback (play/pause, next track, previous track)
  • Works with most media apps that show media notifications

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_media_controller: ^1.0.0

Then run:

flutter pub get

Setup

Android

1. Add Service to AndroidManifest.xml

Add the following service declaration inside the <application> tag in your android/app/src/main/AndroidManifest.xml file:

<service
    android:name="com.example.flutter_media_controller.MediaNotificationListener"
    android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
    android:exported="false">
    <intent-filter>
        <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>
</service>

2. Add Permissions

Add the following permission to your android/app/src/main/AndroidManifest.xml file:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

Usage

Request Permissions

The plugin requires notification listener permission to work. You need to request this permission before using other functions:

// Request notification listener permission
await FlutterMediaController.requestPermissions();

This will open the system settings page where the user needs to enable notification access for your app.

Get Current Media Information

To get information about the currently playing media:

Future<void> fetchMediaInfo() async {
  final mediaInfo = await FlutterMediaController.getCurrentMediaInfo();
  setState(() {
    title = mediaInfo.track;
    artist = mediaInfo.artist;
    isPlaying = mediaInfo.isPlaying;
    thumbnail = mediaInfo.thumbnail; // ByteArray that can be used with Image.memory
  });
}

Control Media Playback

Toggle Play/Pause

await FlutterMediaController.togglePlayPause();

Skip to Next Track

await FlutterMediaController.nextTrack();

Go to Previous Track

await FlutterMediaController.previousTrack();

Example

import 'package:flutter/material.dart';
import 'package:flutter_media_controller/flutter_media_controller.dart';

class MediaControlExample extends StatefulWidget {
  @override
  _MediaControlExampleState createState() => _MediaControlExampleState();
}

class _MediaControlExampleState extends State<MediaControlExample> {
  String title = 'Unknown';
  String artist = 'Unknown';
  bool isPlaying = false;
  Uint8List? thumbnail;

  @override
  void initState() {
    super.initState();
    requestPermissionAndFetchData();
  }

  Future<void> requestPermissionAndFetchData() async {
    await FlutterMediaController.requestPermissions();
    fetchMediaInfo();
  }

  Future<void> fetchMediaInfo() async {
    final mediaInfo = await FlutterMediaController.getCurrentMediaInfo();
    setState(() {
      title = mediaInfo.track;
      artist = mediaInfo.artist;
      isPlaying = mediaInfo.isPlaying;
      thumbnail = mediaInfo.thumbnail;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Media Controller')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            if (thumbnail != null)
              Image.memory(
                thumbnail!,
                width: 200,
                height: 200,
                fit: BoxFit.cover,
              ),
            SizedBox(height: 20),
            Text('Now Playing: $title', style: TextStyle(fontSize: 18)),
            Text('Artist: $artist', style: TextStyle(fontSize: 16)),
            SizedBox(height: 30),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                IconButton(
                  icon: Icon(Icons.skip_previous, size: 36),
                  onPressed: () async {
                    await FlutterMediaController.previousTrack();
                    fetchMediaInfo();
                  },
                ),
                IconButton(
                  icon: Icon(
                    isPlaying ? Icons.pause : Icons.play_arrow,
                    size: 36,
                  ),
                  onPressed: () async {
                    await FlutterMediaController.togglePlayPause();
                    fetchMediaInfo();
                  },
                ),
                IconButton(
                  icon: Icon(Icons.skip_next, size: 36),
                  onPressed: () async {
                    await FlutterMediaController.nextTrack();
                    fetchMediaInfo();
                  },
                ),
              ],
            ),
            ElevatedButton(
              onPressed: fetchMediaInfo,
              child: Text('Refresh Media Info'),
            ),
          ],
        ),
      ),
    );
  }
}

Limitations

  • This plugin currently only supports Android
  • Not all media apps expose their information through the notification system

License

This project is licensed under the MIT License - see the LICENSE file for details.