local_audio_scan 0.0.1
local_audio_scan: ^0.0.1 copied to clipboard
Android-only Flutter package for scanning local audio files with album art extraction.
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+) orREAD_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. SetincludeArtworktofalseto speed up the scan if you don't need album art.
Contributing #
Contributions are welcome! Please feel free to submit a pull request.