React Native Background Downloader

repository·main·Indexed 42 days ago

https://github.com/kesha-antonov/react-native-background-downloader

A library for reliable background file downloads and uploads in React Native and Expo applications on iOS and Android. It ensures large file transfers persist even if the app is in the background or terminated by leveraging system-level APIs like NSURLSession and DownloadManager. Features include pause/resume support, progress tracking, the ability to re-attach to tasks after app restarts, TurboModules support, and TypeScript integration. Version 4.6.3 requires React Native >= 0.70.0, iOS >= 15.1, Android API 24+, and Expo SDK 50+.

Tokens
24.4K
Snippets
69
Records
98
Agent score
53%

What's inside React Native Background Downloader

  1. Overview of React Native Background Downloader

    main

    React Native Background Downloader is a library designed to handle large file downloads and uploads on iOS and Android, even when the app is in the background or has been terminated by the operating system.

    Unlike standard React Native network requests that are tied to the app's lifecycle, this library leverages system-level APIs (NSURLSession on iOS and DownloadManager/Foreground Services on Android) to ensure transfers continue reliably. A key differentiator is the ability to re-attach to ongoing transfers after an app restart, allowing the UI to reconnect to live tasks.

  2. Key Features of React Native Background Downloader

    main

    The library provides the following capabilities:

    • Background Downloads & Uploads: Transfers continue even if the app is in the background or terminated by the OS.
    • Pause/Resume: Full support for pausing and resuming transfers on both iOS and Android.
    • Re-attach to Downloads: Reconnect to ongoing downloads after an app restart.
    • Progress Tracking: Real-time progress updates with customizable intervals.
    • Custom Headers: Support for authentication and custom request headers.
    • Platform Support: Full Expo support via config plugin and full TurboModules support for the React Native New Architecture.
  3. Understand DownloadTask states

    main

    Tasks in v4.0.0+ follow a state machine that can be checked via task.state:

    • PENDING: The state after createDownloadTask() but before .start() is called.
    • DOWNLOADING: The task is actively transferring data.
    • DONE: The download completed successfully.
    • PAUSED: The task was paused via task.pause().
    • FAILED: An error occurred during the download.
    • STOPPED: The task was stopped via task.stop().
  4. Re-attach to existing background tasks

    main

    The library allows you to reconnect to downloads or uploads that continued running while your app was closed or terminated by the OS.

    To sync your UI with ongoing background transfers upon app restart, use getExistingDownloadTasks() or getExistingUploadTasks(). This returns an array of task objects that you can then attach listeners (.progress(), .done(), .error()) to.

    Tip: Use meaningful, persistent task IDs instead of random UUIDs so you can easily match tasks to your UI components after a restart.

    import { getExistingDownloadTasks, getExistingUploadTasks } from '@kesha-antonov/react-native-background-downloader'
    
    // Re-attaching to downloads
    const lostTasks = await getExistingDownloadTasks()
    for (const task of lostTasks) {
      task.progress(({ bytesDownloaded, bytesTotal }) => {
        console.log(`Downloaded: ${bytesDownloaded / bytesTotal * 100}%`)
      }).done(({ location, bytesDownloaded, bytesTotal }) => {
        console.log('Download complete!', { location, bytesDownloaded, bytesTotal })
      })
    }
    
    // Re-attaching to uploads
    const lostUploads = await getExistingUploadTasks()
    for (const task of lostUploads) {
      task.progress(({ bytesUploaded, bytesTotal }) => {
        console.log(`Uploaded: ${bytesUploaded / bytesTotal * 100}%`)
      }).done(({ responseCode, responseBody }) => {
        console.log('Upload complete!', { responseCode, responseBody })
      })
    }
  5. iOS: Background Session Handling and Force-Kill Limitations

    main

    iOS uses NSURLSession with background configuration, allowing downloads to continue even if the OS terminates the app due to memory pressure. When the app is relaunched, you can reconnect to these tasks using getExistingDownloadTasks().

    Critical Limitation: If a user force-kills the app via the iOS App Switcher (swiping up to dismiss), iOS immediately cancels all background tasks. This behavior is an intentional iOS system design and cannot be bypassed.

    To mitigate this for critical downloads, consider using silent push notifications to wake the app upon relaunch, then use getExistingDownloadTasks() to capture any progress made before the kill.

  6. Android: Handle Many Concurrent Downloads (Android 14+)

    main

    Android 14+ limits an app to 150 pending JobScheduler jobs. If you attempt to start a batch of downloads that exceeds this quota, the library will automatically route the remaining downloads through a foreground service to ensure they still run, though they will lose certain scheduling privileges.

    Best Practice: If you need to download hundreds of files, queue them within your application logic rather than attempting to start them all simultaneously.

  7. Enable debug logging

    main

    Verbose debug logging is available for both debug and production builds. It is disabled by default.

    Options:

    1. Native Console: Set isLogsEnabled: true to print logs to Xcode (iOS) or Android Studio (Android) consoles.
    2. JavaScript Callback: Set isLogsEnabled: true and provide a logCallback function to capture logs within your app (e.g., for sending to Crashlytics).

    Note: On iOS, the logCallback currently receives the taskId associated with the log.

    import { setConfig } from '@kesha-antonov/react-native-background-downloader'
    
    // Option 1: Native console logging
    setConfig({
      isLogsEnabled: true
    })
    
    // Option 2: Capture logs in JS
    setConfig({
      isLogsEnabled: true,
      logCallback: (log) => {
        console.log('[BackgroundDownloader]', log.message)
      }
    })
  8. Configure iOS AppDelegate for Background Transfers

    main

    To support background transfers on iOS, you must implement the handleEventsForBackgroundURLSession method in your AppDelegate.

    For React Native 0.77+ (Swift):

    1. Import <RNBackgroundDownloader.h> in your bridging header.
    2. Implement the method in AppDelegate.swift using RNBackgroundDownloader.setCompletionHandlerWithIdentifier.

    For React Native < 0.77 (Objective-C):

    1. Import <RNBackgroundDownloader.h> in AppDelegate.m.
    2. Implement the method in AppDelegate.m using [RNBackgroundDownloader setCompletionHandlerWithIdentifier:...].
    // AppDelegate.swift
    func application(
      _ application: UIApplication,
      handleEventsForBackgroundURLSession identifier: String,
      completionHandler: @escaping () -> Void
    ) {
      RNBackgroundDownloader.setCompletionHandlerWithIdentifier(identifier, completionHandler: completionHandler)
    }
    // AppDelegate.m
    #import <RNBackgroundDownloader.h>
    
    - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler
    {
      [RNBackgroundDownloader setCompletionHandlerWithIdentifier:identifier completionHandler:completionHandler];
    }
  9. Setup and run the example project

    main

    To run the provided example application, follow these steps to install dependencies for both the root repository and the example directory, build the native development builds, and start the simulator.

    1. Install Dependencies

    Install the root dependencies, then navigate to the example folder to install its specific dependencies:

    yarn install
    cd example
    yarn install

    2. Build Native Development Builds

    You must install the iOS or Android development build. This is required once initially or whenever native dependencies are rebuilt:

    For iOS:

    yarn installDevBuild:ios

    For Android:

    yarn installDevBuild:android

    3. Start the App

    To launch the example app on an iOS simulator, run:

    yarn start:ios
    yarn install
    cd example
    yarn install
    
    yarn installDevBuild:ios
    
    yarn start:ios
  10. Local development for the documentation site

    main

    To run the documentation site locally, navigate to the website/ directory. Note that website/ is a separate Yarn project from the main library. You can install dependencies, start a development server with hot reload, or create a production build.

    # From the website/ directory
    yarn install
    yarn start   # regenerates the pages, then serves with hot reload
    yarn build   # production build into website/build
  11. Migrate from v4.3.x to v4.4.0: iOS MMKV Dependency

    main

    In v4.4.0, the MMKV dependency was removed from the podspec to prevent symbol conflicts with react-native-mmkv.

    • If you are using react-native-mmkv: No action is required. The dependency is provided automatically.
    • If you are NOT using react-native-mmkv: You must manually add the MMKV dependency to your ios/Podfile:
    pod 'MMKV', '>= 1.0.0', '!= 2.4.1'

    Then run cd ios && pod install.

    Important Note on Versions: This manual step applies to versions v4.4.0 through v4.5.4. Starting from v4.5.5, the podspec declares MMKV again, so you can remove this manual line.

    Note on != 2.4.1: This exclusion is critical because MMKVCore 2.4.1 does not compile on Apple platforms. If you pin MMKV yourself, you should also pin pod 'MMKVCore', '!= 2.4.1' to prevent resolving to the broken version.