tauri-plugin-media-session
A Tauri 2 plugin for mobile media session integration. Displays lockscreen controls, album artwork, and transport buttons — with a dead-simple API.
Compatibility
| Tauri build target | Status | Notes |
|---|---|---|
| Android | ✅ Supported | Full plugin support |
| iOS | ✅ Supported | MPNowPlayingInfoCenter + MPRemoteCommandCenter |
| macOS | ❌ Not yet | Not implemented |
| Windows | ❌ Not yet | Not implemented |
| Linux | ❌ Not yet | Not implemented |
Features
- MediaStyle notification with play/pause/skip/seek controls (Android)
- Lockscreen and Control Center media controls (iOS)
- Hardware media button support (headphones, Bluetooth, etc.)
- Album artwork with smart caching and automatic downsampling
- Playback speed support
- Merge semantics — only send what changed, previous values are preserved
- Runtime notification permission handling (Android 13+)
- Full TypeScript bindings with JSDoc
- Typed Rust API for backend consumers
- Automatic lifecycle management
Installation
1. Add the Rust crate
# src-tauri/Cargo.toml
[]
= "0.2"
2. Register the plugin
// src-tauri/lib.rs
3. Add the capability
4. Install the TypeScript bindings
# or
5. iOS: enable background audio
Add audio to UIBackgroundModes in your Info.plist:
UIBackgroundModes
audio
Usage
TypeScript (recommended)
import { updateState, updateTimeline, onAction, clear } from 'tauri-plugin-media-session-api';
// Set the full state on track change
await updateState({
title: 'Bohemian Rhapsody',
artist: 'Queen',
album: 'A Night at the Opera',
artwork: base64ImageData, // JPEG/PNG, no data: prefix
duration: 354,
position: 0,
isPlaying: true,
canPrev: true,
canNext: true,
});
// Later — only update what changed (merge semantics)
await updateState({ isPlaying: false });
// Lightweight timeline sync (no notification rebuild)
await updateTimeline({ position: 120.5 });
await updateTimeline({ playbackSpeed: 1.5 });
// Listen for media actions
const listener = await onAction((event) => {
switch (event.action) {
case 'play': player.play(); break;
case 'pause': player.pause(); break;
case 'next': player.next(); break;
case 'previous': player.previous(); break;
case 'seek': player.seekTo(event.seekPosition!); break;
case 'stop': player.stop(); break;
}
});
// Stop listening when done
await listener.unregister();
// Clear the notification and release resources
await clear();
Rust (backend)
use ;
// From a command or anywhere you have access to the app handle:
app.media_session.update_state?;
app.media_session.clear?;
API Reference
updateState(state: MediaState)
Update the media session and notification. Auto-initializes on first call.
All fields are optional — omitted fields keep their previous values.
| Field | Type | Description |
|---|---|---|
title |
string |
Track title |
artist |
string |
Artist name |
album |
string |
Album name |
artwork |
string |
Base64-encoded image (JPEG/PNG, no data: prefix) |
artworkUrl |
string |
Image URL — downloaded natively (no CORS restrictions) |
duration |
number |
Track duration in seconds |
position |
number |
Current playback position in seconds |
playbackSpeed |
number |
Playback speed multiplier (default: 1.0) |
isPlaying |
boolean |
Whether media is currently playing |
canPrev |
boolean |
Enable "previous track" button |
canNext |
boolean |
Enable "next track" button |
canSeek |
boolean |
Enable seeking (default: true) |
onAction(handler): Promise<PluginListener>
Listen for media control actions. Returns a listener you can unregister.
| Action | Description |
|---|---|
'play' |
Play button pressed |
'pause' |
Pause button pressed |
'stop' |
Stop action triggered |
'next' |
Next track button pressed |
'previous' |
Previous track button pressed |
'seek' |
Seek action — event.seekPosition in seconds |
updateTimeline(timeline: TimelineUpdate)
Lightweight position/speed sync — skips notification rebuild (Android) / updates MPNowPlayingInfoCenter only (iOS).
Use this for frequent updates during playback (seek, speed change). The session must already be initialized via updateState().
| Field | Type | Description |
|---|---|---|
position |
number |
Playback position in seconds |
duration |
number |
Track duration in seconds |
playbackSpeed |
number |
Speed multiplier |
Note: Both Android and iOS automatically extrapolate the playback position while
isPlayingistrue. You don't need to callupdateTimeline()every second — only on seek, track change, or speed change.
clear()
Dismiss the notification (Android) / clear Now Playing info (iOS), release the media session, and free all resources.
The session is automatically re-created on the next updateState() call.
initialize()
Pre-initialize the session and request notification permissions (Android) / configure audio session (iOS).
Optional — updateState() handles this automatically.
Platform notes
Android
- Requires
POST_NOTIFICATIONSpermission (requested automatically on Android 13+) - Notification uses
MediaStylewithMediaSessionCompat
iOS
- Requires
UIBackgroundModes: audioinInfo.plist - Uses
MPNowPlayingInfoCenterfor metadata andMPRemoteCommandCenterfor controls - Configures
AVAudioSessionwith.playbackcategory
License
MIT OR Apache-2.0