DEV Community

Cover image for React Native Background Downloads, ZIP Extraction & Notifications
PEAKIQ
PEAKIQ

Posted on • Originally published at peakiq.in

React Native Background Downloads, ZIP Extraction & Notifications

Originally published on PEAKIQ

Source: https://www.peakiq.in/blog/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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Or via yarn:

yarn add @kesha-antonov/react-native-background-downloader \
  react-native-zip-archive \
  react-native-notifications \
  react-native-fs
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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)