React Native Nitro Player supports downloading tracks and playlists for offline playback. This feature enables users to save music locally and play it without an internet connection.
Add the following to your AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<application>
<!-- Required for background downloads with notifications -->
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
android:exported="false" />
</application>
</manifest>Important
The SystemForegroundService with foregroundServiceType="dataSync" is required for downloads to work properly in the background and display download progress notifications.
No additional setup required for iOS.
import { DownloadManager } from 'react-native-nitro-player'
DownloadManager.configure({
maxConcurrentDownloads: 3,
autoRetry: true,
maxRetryAttempts: 3,
backgroundDownloadsEnabled: true,
downloadArtwork: true,
wifiOnlyDownloads: false,
storageLocation: 'private', // 'private' or 'public'
})import { DownloadManager } from 'react-native-nitro-player'
import type { TrackItem } from 'react-native-nitro-player'
const track: TrackItem = {
id: '1',
title: 'Song Title',
artist: 'Artist Name',
album: 'Album Name',
duration: 180.0,
url: 'https://example.com/song.mp3',
artwork: 'https://example.com/artwork.jpg',
}
// Download a single track
const downloadId = await DownloadManager.downloadTrack(track)
// Download a track as part of a playlist
const downloadId = await DownloadManager.downloadTrack(track, 'playlist-id')import { PlayerQueue, DownloadManager } from 'react-native-nitro-player'
const playlist = PlayerQueue.getPlaylist('playlist-id')
const downloadIds = await DownloadManager.downloadPlaylist(
playlist.id,
playlist.tracks
)import { useDownloadProgress } from 'react-native-nitro-player'
function DownloadProgressView() {
const { progressList, overallProgress, isDownloading } = useDownloadProgress()
return (
<View>
<Text>Overall Progress: {Math.round(overallProgress * 100)}%</Text>
<Text>Downloading: {isDownloading ? 'Yes' : 'No'}</Text>
{progressList.map((progress) => (
<View key={progress.trackId}>
<Text>{progress.trackId}</Text>
<Text>Progress: {Math.round(progress.progress * 100)}%</Text>
<Text>State: {progress.state}</Text>
</View>
))}
</View>
)
}Track download progress for one or more tracks.
Options:
trackIds?: string[]- Track specific track IDsdownloadIds?: string[]- Track specific download IDsactiveOnly?: boolean- Only track active downloads
Returns:
progressMap: Map<string, DownloadProgress>- Map of trackId to progressprogressList: DownloadProgress[]- Array of all tracked progressoverallProgress: number- Overall progress (0-1)isDownloading: boolean- Whether any download is in progressgetProgress: (trackId: string) => DownloadProgress | undefined- Get progress for a specific track
Example:
import { useDownloadProgress } from 'react-native-nitro-player'
function TrackDownloadProgress({ trackId }: { trackId: string }) {
const { getProgress } = useDownloadProgress({ trackIds: [trackId] })
const progress = getProgress(trackId)
if (!progress) return null
return (
<View>
<Text>{Math.round(progress.progress * 100)}%</Text>
<ProgressBar progress={progress.progress} />
</View>
)
}Access all downloaded tracks and playlists.
Returns:
downloadedTracks: DownloadedTrack[]- All downloaded tracksdownloadedPlaylists: DownloadedPlaylist[]- All downloaded playlistsisTrackDownloaded: (trackId: string) => boolean- Check if track is downloadedisPlaylistDownloaded: (playlistId: string) => boolean- Check if playlist is fully downloadedisPlaylistPartiallyDownloaded: (playlistId: string) => boolean- Check if playlist is partially downloadedgetDownloadedTrack: (trackId: string) => DownloadedTrack | undefined- Get downloaded track infogetDownloadedPlaylist: (playlistId: string) => DownloadedPlaylist | undefined- Get downloaded playlist inforefresh: () => void- Refresh downloaded content listisLoading: boolean- Loading state
Example:
import { useDownloadedTracks } from 'react-native-nitro-player'
function DownloadedTracksView() {
const { downloadedTracks, isTrackDownloaded, refresh } = useDownloadedTracks()
return (
<View>
<Button title="Refresh" onPress={refresh} />
{downloadedTracks.map((track) => (
<View key={track.trackId}>
<Text>{track.originalTrack.title}</Text>
<Text>Size: {(track.fileSize / 1024 / 1024).toFixed(2)} MB</Text>
</View>
))}
</View>
)
}Configure the download manager.
Config Options:
storageLocation?: 'private' | 'public'- Where to store downloadsmaxConcurrentDownloads?: number- Max simultaneous downloads (default: 3)autoRetry?: boolean- Auto-retry failed downloads (default: true)maxRetryAttempts?: number- Max retry attempts (default: 3)backgroundDownloadsEnabled?: boolean- Enable background downloads (default: true)downloadArtwork?: boolean- Download artwork images (default: true)customDownloadPath?: string | null- Custom download directorywifiOnlyDownloads?: boolean- Only download on WiFi (default: false)
Get current configuration.
Download a single track. Returns the download ID for tracking.
Download an entire playlist. Returns array of download IDs.
Pause an active download.
Resume a paused download.
Cancel a download and remove partial files.
Retry a failed download.
Pause all active downloads.
Resume all paused downloads.
Cancel all downloads.
Get download task information by download ID.
Get all active download tasks.
Get overall download queue status.
Returns:
{
pendingCount: number
activeCount: number
completedCount: number
failedCount: number
totalBytesToDownload: number
totalBytesDownloaded: number
overallProgress: number // 0.0 to 1.0
}Check if a track is currently downloading.
Get download state for a track. States: 'pending', 'downloading', 'paused', 'completed', 'failed', 'cancelled'.
Check if a track is downloaded.
Check if all tracks in a playlist are downloaded.
Check if at least one track in a playlist is downloaded.
Get downloaded track information.
Get all downloaded tracks.
Get downloaded playlist information.
Get all downloaded playlists.
Get local file path for a downloaded track.
Delete a downloaded track and its files.
Delete all tracks in a downloaded playlist.
Delete all downloaded content.
Get storage usage information.
Returns:
{
totalDownloadedSize: number // bytes
trackCount: number
playlistCount: number
availableSpace: number // bytes
totalSpace: number // bytes
}Validate all downloads and remove orphaned records. Returns the number of orphaned records cleaned up.
Set playback source preference: 'auto', 'download', or 'network'.
'auto'- Use downloaded version if available, otherwise stream'download'- Only play downloaded tracks'network'- Always stream from network
Get current playback source preference.
Get the effective URL for a track (local or network based on preference and availability).
Listen to download progress updates.
DownloadManager.onDownloadProgress(progress => {
console.log(`${progress.trackId}: ${Math.round(progress.progress * 100)}%`)
})Listen to download state changes.
DownloadManager.onDownloadStateChange((downloadId, trackId, state, error) => {
console.log(`${trackId} is now ${state}`)
if (error) {
console.error('Download error:', error.message)
}
})Listen to download completion events.
DownloadManager.onDownloadComplete(downloadedTrack => {
console.log(`Downloaded: ${downloadedTrack.originalTrack.title}`)
})interface DownloadProgress {
trackId: string
downloadId: string
bytesDownloaded: number
totalBytes: number
progress: number // 0.0 to 1.0
state: DownloadState
}interface DownloadedTrack {
trackId: string
originalTrack: TrackItem
localPath: string
localArtworkPath?: string | null
downloadedAt: number // Unix timestamp
fileSize: number // bytes
storageLocation: 'private' | 'public'
}interface DownloadedPlaylist {
playlistId: string
originalPlaylist: Playlist
downloadedTracks: DownloadedTrack[]
totalSize: number // bytes
downloadedAt: number // Unix timestamp
isComplete: boolean // All tracks downloaded
}interface DownloadTask {
downloadId: string
trackId: string
playlistId?: string | null
state: DownloadState
progress: DownloadProgress
createdAt: number
startedAt?: number | null
completedAt?: number | null
error?: DownloadError | null
retryCount: number
}interface DownloadError {
code: string
message: string
reason: DownloadErrorReason
isRetryable: boolean
}
type DownloadErrorReason =
| 'network_error'
| 'storage_full'
| 'file_not_found'
| 'permission_denied'
| 'invalid_url'
| 'timeout'
| 'unknown'import { DownloadManager, useDownloadProgress } from 'react-native-nitro-player'
function DownloadButton({ track }: { track: TrackItem }) {
const [downloadId, setDownloadId] = useState<string | null>(null)
const { getProgress } = useDownloadProgress({
trackIds: [track.id],
})
const handleDownload = async () => {
const id = await DownloadManager.downloadTrack(track)
setDownloadId(id)
}
const progress = getProgress(track.id)
return (
<View>
{!progress ? (
<Button title="Download" onPress={handleDownload} />
) : (
<View>
<Text>{Math.round(progress.progress * 100)}%</Text>
<Text>{progress.state}</Text>
</View>
)}
</View>
)
}import { DownloadManager, TrackPlayer } from 'react-native-nitro-player'
// Set preference to use downloaded tracks when available
DownloadManager.setPlaybackSourcePreference('auto')
// Play a track (will use local file if downloaded)
await TrackPlayer.playSong('track-id')
// Check what URL will be used
const track = { id: 'track-id', url: 'https://...' /* ... */ }
const effectiveUrl = DownloadManager.getEffectiveUrl(track)
console.log('Playing from:', effectiveUrl) // Local path or network URLimport { DownloadManager } from 'react-native-nitro-player'
async function showStorageInfo() {
const info = await DownloadManager.getStorageInfo()
console.log(`Downloaded: ${info.trackCount} tracks`)
console.log(
`Total size: ${(info.totalDownloadedSize / 1024 / 1024).toFixed(2)} MB`
)
console.log(`Available: ${(info.availableSpace / 1024 / 1024).toFixed(2)} MB`)
}
// Clean up orphaned records
const cleaned = DownloadManager.syncDownloads()
console.log(`Cleaned up ${cleaned} orphaned records`)import { DownloadManager } from 'react-native-nitro-player'
// Get queue status
const status = DownloadManager.getQueueStatus()
console.log(`Active: ${status.activeCount}`)
console.log(`Pending: ${status.pendingCount}`)
console.log(`Overall: ${Math.round(status.overallProgress * 100)}%`)
// Pause all downloads
await DownloadManager.pauseAllDownloads()
// Resume all downloads
await DownloadManager.resumeAllDownloads()
// Cancel all downloads
await DownloadManager.cancelAllDownloads()-
Configure on App Start: Configure the download manager when your app initializes.
-
Handle Errors: Always listen to
onDownloadStateChangeto handle download errors gracefully. -
WiFi-Only for Large Downloads: Enable
wifiOnlyDownloadsfor better user experience. -
Monitor Storage: Regularly check
getStorageInfo()to avoid running out of space. -
Sync Downloads: Call
syncDownloads()periodically to clean up orphaned records. -
Use Auto Playback Source: Set playback source to
'auto'to seamlessly use downloaded tracks when available. -
Background Downloads: Enable
backgroundDownloadsEnabledfor better user experience on Android.