Local Audio Scan

An Android-only Flutter plugin to scan and retrieve local music/audio files from the device's storage using MediaStore. It extracts metadata and album artwork efficiently.

Note: This plugin does not support iOS.

Features

  • Scan Audio Files: Retrieve all music files from MediaStore.
  • Extract Metadata: Get ID, title, artist, album, duration, file path, MIME type, size, and date added.
  • Album Artwork: Extracts embedded or album-level artwork.
  • Permissions Handling: Gracefully requests READ_MEDIA_AUDIO (Android 13+) or READ_EXTERNAL_STORAGE (pre-Android 13).
  • Efficient: Uses Kotlin coroutines to perform scanning off the UI thread.

Installation

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

dependencies:
  local_audio_scan: ^0.0.1

Then, run flutter pub get.

Android Configuration

You must add the necessary permissions to your android/app/src/main/AndroidManifest.xml file.

For Android 13 (API 33) and above:

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

For older versions (below API 33):

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

Your manifest should include both to support a wide range of devices:

<manifest ...>
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
    ...
</manifest>

Usage

Here's a basic example of how to use the plugin:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _localAudioScanPlugin = LocalAudioScanner();
  List<AudioTrack> _audioTracks = [];
  bool _hasPermission = false;

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

  Future<void> _checkAndRequestPermission() async {
    var granted = await _localAudioScanPlugin.checkPermission();
    if (!granted) {
      granted = await _localAudioScanPlugin.requestPermission();
    }
    setState(() {
      _hasPermission = granted;
    });
    if (granted) {
      _scanAudio();
    }
  }

  Future<void> _scanAudio() async {
    if (!_hasPermission) return;
    final tracks = await _localAudioScanPlugin.scanTracks();
    setState(() {
      _audioTracks = tracks;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Local Audio Scanner Example'),
        ),
        body: ListView.builder(
          itemCount: _audioTracks.length,
          itemBuilder: (context, index) {
            final track = _audioTracks[index];
            return ListTile(
              leading: track.artwork != null
                  ? Image.memory(track.artwork!, width: 50, height: 50, fit: BoxFit.cover)
                  : const Icon(Icons.music_note, size: 50),
              title: Text(track.title),
              subtitle: Text(track.artist),
            );
          },
        ),
      ),
    );
  }
}

Data Model: AudioTrack

The scanTracks method returns a List<AudioTrack>.

class AudioTrack {
  final String id;
  final String title;
  final String artist;
  final String album;
  final int duration; // in milliseconds
  final String filePath;
  final String mimeType;
  final int size; // in bytes
  final DateTime dateAdded;
  final Uint8List? artwork;
}

API

  • Future<bool> checkPermission(): Checks if storage permission is already granted.
  • Future<bool> requestPermission(): Requests the necessary storage permission from the user.
  • Future<List<AudioTrack>> scanTracks({bool includeArtwork = true}): Scans the device for audio files. Set includeArtwork to false to speed up the scan if you don't need album art.

Contributing

Contributions are welcome! Please feel free to submit a pull request.

Libraries

local_audio_scan