Originally published on PEAKIQ
A complete guide to handling background file downloads, extracting ZIP archives, and notifying users in React Native. Published on peakiq.in.
1. Create a React Native Project
If you don't already have a project initialized, scaffold one using the React Native CLI:
npx react-native init MyApp
2. Install Required Libraries
Four libraries power this implementation, each handling a distinct responsibility:
| Library | Purpose |
|---|---|
@kesha-antonov/react-native-background-downloader |
Background downloads that persist across app restarts |
react-native-zip-archive |
Extracting ZIP files after download completes |
react-native-notifications |
Local push alerts when download finishes |
react-native-fs |
File system operations and recursive path traversal |
Install via npm:
npm install @kesha-antonov/react-native-background-downloader \
react-native-zip-archive \
react-native-notifications \
react-native-fs
Or via yarn:
yarn add @kesha-antonov/react-native-background-downloader \
react-native-zip-archive \
react-native-notifications \
react-native-fs
3. Platform Configuration
Android
- Add required permissions in
AndroidManifest.xml - Enable background services if needed
- Grant internet and storage permissions
iOS
- Configure notification permissions in your app settings
- Enable Background Fetch mode
- Enable Background Processing under Background Modes
4. Full Implementation
A complete component handling the full download lifecycle — background download, ZIP extraction, progress tracking, and local notifications:
import React, { useState, useEffect } from 'react';
import { View } from 'react-native';
import * as Progress from 'react-native-progress';
import { Notifications } from 'react-native-notifications';
import RNBackgroundDownloader from '@kesha-antonov/react-native-background-downloader';
import { unzip } from 'react-native-zip-archive';
import RNFS from 'react-native-fs';
// Recursively collect all file paths inside a directory
const collectFilePaths = async (
dirPath: string,
filePaths: string[] = []
): Promise<string[]> => {
const contents = await RNFS.readDir(dirPath);
for (const item of contents) {
if (item.isDirectory()) {
await collectFilePaths(item.path, filePaths);
} else {
filePaths.push(item.path);
}
}
return filePaths;
};
const DownloadScreen: React.FC = () => {
const [progress, setProgress] = useState<number>(0);
useEffect(() => {
Notifications.registerRemoteNotifications();
checkExistingDownloads();
}, []);
// Resume any downloads that were interrupted by an app restart
const checkExistingDownloads = async () => {
const tasks = await RNBackgroundDownloader.checkForExistingDownloads();
const task = tasks.find(t => t.id === 'file_11111');
if (task) {
task
.progress(({ bytesDownloaded, bytesTotal }) =>
setProgress(bytesDownloaded / bytesTotal)
)
.done(() => console.log('Resumed download completed'))
.error(console.error);
}
};
const sendNotification = () => {
Notifications.postLocalNotification({
body: 'File Uploaded!',
title: 'Download Completed',
sound: 'chime.aiff',
silent: false,
});
};
const downloadFile = (url: string): Promise<string> => {
return new Promise((resolve, reject) => {
const destination = `${RNBackgroundDownloader.directories.documents}/file_11111.zip`;
RNBackgroundDownloader.download({ id: 'file_11111', url, destination })
.progress(({ bytesDownloaded, bytesTotal }) =>
setProgress(bytesDownloaded / bytesTotal)
)
.done(() => resolve(destination))
.error(reject);
});
};
const downloadAndUnzip = async () => {
try {
const filePath = await downloadFile('http://localhost:5005/download');
const unzipPath = await unzip(
filePath,
`${RNBackgroundDownloader.directories.documents}/file_${Date.now()}`
);
const files = await collectFilePaths(unzipPath);
console.log(files);
sendNotification();
} catch (err) {
console.error(err);
}
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
{progress > 0 && (
<>
<Text>{`Progress: ${(progress * 100).toFixed(2)}%`}</Text>
<Progress.Bar progress={progress} width={350} />
</>
)}
<Text onPress={downloadAndUnzip}>Download & Extract</Text>
</View>
);
};
export default DownloadScreen;
5. How It Works
Background Downloads
Uses react-native-background-downloader to handle downloads that survive app restarts. The checkForExistingDownloads() call on mount automatically resumes any interrupted tasks.
ZIP Extraction
Once the download resolves, react-native-zip-archive's unzip() extracts the archive into a uniquely named directory using Date.now() to avoid collisions.
File Traversal
react-native-fs recursively walks the extracted directory tree, collecting every file path into a flat array.
Notifications
A local push notification fires immediately after extraction completes, letting the user know their content is ready — even if the app is in the background.
Use Cases
This pattern works well for any app dealing with large file downloads:
- Offline content bundles
- Media and video downloads
- PDF and document packs
- SDS and compliance files
- Course or educational materials
- Map tile packages
Published on peakiq.in — React Native guides and tutorials.
Top comments (0)