@beatsphere/expo-music-detector
v0.1.0
Published
Expo native module for detecting currently playing music on Android via MediaSession and NotificationListener
Maintainers
Readme
@beatsphere/expo-music-detector
Expo native module that detects currently playing music on Android. Uses MediaSession and NotificationListenerService to detect tracks from 10+ music apps in real-time. Battle-tested in BeatSphere.
Supported Apps
| App | Package Name |
|-----|-------------|
| Spotify | com.spotify.music |
| YouTube | com.google.android.youtube |
| YouTube Music | com.google.android.apps.youtube.music |
| Apple Music | com.apple.android.music |
| SoundCloud | com.soundcloud.android |
| Last.fm | fm.last.android |
| Amazon Music | com.amazon.mp3 |
| Pandora | com.pandora.android |
| Tidal | com.aspiro.tidal |
| Deezer | deezer.android.app |
Any other app using Android's MediaSession API will be detected as unknown provider.
Install
npm install @beatsphere/expo-music-detectorAdd the plugin to your app.config.js:
export default {
plugins: [
'@beatsphere/expo-music-detector',
],
};Run prebuild:
npx expo prebuild --cleanQuick Start
import {
isSupported,
isNotificationAccessGranted,
openNotificationSettings,
getCurrentTrack,
addTrackChangedListener,
} from '@beatsphere/expo-music-detector';
// Check platform support (Android only)
if (!isSupported) {
console.log('Music detection is only supported on Android');
}
// Check and request permission
const hasAccess = isNotificationAccessGranted();
if (!hasAccess) {
// Opens system settings — user must manually enable
openNotificationSettings();
}
// Get current track
const track = getCurrentTrack();
if (track) {
console.log(`${track.title} by ${track.artist} (${track.provider})`);
}
// Listen for track changes
const subscription = addTrackChangedListener((event) => {
if (event.track) {
console.log(`Now playing: ${event.track.title} by ${event.track.artist}`);
console.log(`Provider: ${event.track.provider}`);
console.log(`Playing: ${event.track.isPlaying}`);
} else {
console.log('Playback stopped');
}
});
// Clean up
subscription.remove();How It Works
On Android, the module uses two detection mechanisms:
MediaSessionManager (primary) — Listens for active media sessions and registers callbacks for metadata and playback state changes. This provides the most reliable detection.
NotificationListenerService (fallback) — Parses music notifications for apps that don't use MediaSession properly. Extracts title, artist, and album from notification extras.
The module requires Notification Listener Access, which the user must grant manually in system settings. This is an Android system-level permission that cannot be requested via a dialog.
API Reference
| Function | Description |
|----------|-------------|
| isSupported | boolean — Whether the current platform supports music detection (Android only) |
| isNotificationAccessGranted() | Check if notification listener permission is granted |
| openNotificationSettings() | Open system settings for notification access |
| startMonitoring() | Start monitoring (service starts automatically with permission) |
| stopMonitoring() | Stop monitoring |
| getCurrentTrack() | Get the currently playing track, or null |
| addTrackChangedListener(cb) | Subscribe to track changes. Returns { remove() } |
Track Type
interface Track {
title: string;
artist: string;
album?: string;
albumArt?: string;
provider: MusicProvider;
isPlaying: boolean;
}
type MusicProvider =
| 'spotify'
| 'youtube'
| 'apple_music'
| 'soundcloud'
| 'lastfm'
| 'amazon_music'
| 'pandora'
| 'tidal'
| 'deezer'
| 'unknown';Platform Notes
Android
- API 21+ (Lollipop) required
- Uses
MediaSessionManagerfor reliable detection on API 22+ - Falls back to notification parsing on older versions
- Requires
BIND_NOTIFICATION_LISTENER_SERVICEpermission - The
NotificationListenerServiceruns as long as the user grants access - Automatically detects track changes across all supported music apps
iOS
- Music detection is not supported on iOS
- All functions return safe defaults (
null,false, no-ops) - The iOS module stub is included so your app builds cross-platform without conditional imports
License
MIT
