PEAKIQ - Software Solutions & Digital Innovation Peakiq Software Development

Peakiq Blog

Managing Background Downloads, Unzipping Files, and Notifications in React Native

A practical guide to background downloads, ZIP extraction, and notifications in React Native with real-world implementation tips.

Editorial4 min read751 words
Managing Background Downloads, Unzipping Files, and Notifications in React Native

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:

LibraryPurpose
@kesha-antonov/react-native-background-downloaderBackground downloads that persist across app restarts
react-native-zip-archiveExtracting ZIP files after download completes
react-native-notificationsLocal push alerts when download finishes
react-native-fsFile 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.