Signed-off-by: Lance Chant <13349722+lancechant@users.noreply.github.com> Co-authored-by: sarendsen <coding-mosses0z@icloud.com> Co-authored-by: Lance Chant <13349722+lancechant@users.noreply.github.com> Co-authored-by: Gauvain <68083474+Gauvino@users.noreply.github.com>
6.3 KiB
Background Downloader Module
A native iOS and Android module for downloading large files in the background using NSURLSession (iOS) and DownloadManager (Android).
Features
- Background Downloads: Downloads continue even when the app is backgrounded or suspended
- Progress Tracking: Real-time progress updates via events
- Multiple Downloads: Support for concurrent downloads
- Cancellation: Cancel individual or all downloads
- Custom Destination: Optionally specify custom file paths
- Error Handling: Comprehensive error reporting
- Cross-Platform: Works on both iOS and Android
Usage
Basic Example
import { BackgroundDownloader } from '@/modules';
// Start a download
const taskId = await BackgroundDownloader.startDownload(
'https://example.com/largefile.mp4'
);
// Listen for progress updates
const progressSub = BackgroundDownloader.addProgressListener((event) => {
console.log(`Progress: ${Math.floor(event.progress * 100)}%`);
console.log(`Downloaded: ${event.bytesWritten} / ${event.totalBytes}`);
});
// Listen for completion
const completeSub = BackgroundDownloader.addCompleteListener((event) => {
console.log('Download complete!');
console.log('File saved to:', event.filePath);
console.log('Task ID:', event.taskId);
});
// Listen for errors
const errorSub = BackgroundDownloader.addErrorListener((event) => {
console.error('Download failed:', event.error);
});
// Cancel a download
BackgroundDownloader.cancelDownload(taskId);
// Get all active downloads
const activeDownloads = await BackgroundDownloader.getActiveDownloads();
// Cleanup listeners when done
progressSub.remove();
completeSub.remove();
errorSub.remove();
Custom Destination Path
import { BackgroundDownloader } from '@/modules';
import * as FileSystem from 'expo-file-system';
const destinationPath = `${FileSystem.documentDirectory}myfile.mp4`;
const taskId = await BackgroundDownloader.startDownload(
'https://example.com/video.mp4',
destinationPath
);
Managing Multiple Downloads
import { BackgroundDownloader } from '@/modules';
const downloads = new Map();
async function startMultipleDownloads(urls: string[]) {
for (const url of urls) {
const taskId = await BackgroundDownloader.startDownload(url);
downloads.set(taskId, { url, progress: 0 });
}
}
// Track progress for each download
const progressSub = BackgroundDownloader.addProgressListener((event) => {
const download = downloads.get(event.taskId);
if (download) {
download.progress = event.progress;
}
});
// Cancel all downloads
BackgroundDownloader.cancelAllDownloads();
API Reference
Methods
startDownload(url: string, destinationPath?: string): Promise<number>
Starts a new background download.
- Parameters:
url: The URL of the file to downloaddestinationPath: (Optional) Custom file path for the downloaded file
- Returns: Promise that resolves to the task ID (number)
cancelDownload(taskId: number): void
Cancels a specific download by task ID.
- Parameters:
taskId: The task ID returned bystartDownload
cancelAllDownloads(): void
Cancels all active downloads.
getActiveDownloads(): Promise<ActiveDownload[]>
Gets information about all active downloads.
- Returns: Promise that resolves to an array of active downloads
Event Listeners
addProgressListener(listener: (event: DownloadProgressEvent) => void): Subscription
Listens for download progress updates.
- Event payload:
taskId: numberbytesWritten: numbertotalBytes: numberprogress: number (0.0 to 1.0)
addCompleteListener(listener: (event: DownloadCompleteEvent) => void): Subscription
Listens for download completion.
- Event payload:
taskId: numberfilePath: stringurl: string
addErrorListener(listener: (event: DownloadErrorEvent) => void): Subscription
Listens for download errors.
- Event payload:
taskId: numbererror: string
addStartedListener(listener: (event: DownloadStartedEvent) => void): Subscription
Listens for download start confirmation.
- Event payload:
taskId: numberurl: string
Types
interface DownloadProgressEvent {
taskId: number;
bytesWritten: number;
totalBytes: number;
progress: number;
}
interface DownloadCompleteEvent {
taskId: number;
filePath: string;
url: string;
}
interface DownloadErrorEvent {
taskId: number;
error: string;
}
interface DownloadStartedEvent {
taskId: number;
url: string;
}
interface ActiveDownload {
taskId: number;
url: string;
state: 'running' | 'suspended' | 'canceling' | 'completed' | 'unknown';
}
Implementation Details
iOS Background Downloads
- Uses
NSURLSessionwith background configuration - Session identifier:
com.fredrikburmester.streamyfin.backgrounddownloader - Downloads continue when app is backgrounded or suspended
- System may terminate downloads if app is force-quit
Android Background Downloads
- Uses Android's
DownloadManagerAPI - Downloads are managed by the system and continue in the background
- Shows download notification in the notification tray
- Downloads continue even if the app is closed
- Requires
INTERNETpermission (automatically added by Expo)
Background Modes
The app's Info.plist already includes the required background mode for iOS:
UIBackgroundModes:["audio", "fetch"]
File Storage
iOS: By default, downloaded files are saved to the app's Documents directory.
Android: By default, files are saved to the app's external files directory (accessible via FileSystem.documentDirectory in Expo).
You can specify a custom path using the destinationPath parameter on both platforms.
Building
After adding this module, rebuild the app:
# iOS
npx expo prebuild -p ios
npx expo run:ios
# Android
npx expo prebuild -p android
npx expo run:android
Or install manually:
# iOS
cd ios
pod install
cd ..
# Android - prebuild handles everything
npx expo prebuild -p android
Notes
- Background downloads may be cancelled if the user force-quits the app (iOS)
- The OS manages download priority and may pause downloads to save battery
- Android shows a system notification for ongoing downloads
- Downloads over cellular are allowed by default on both platforms