Skip to main content

Downloading files in the background

Downloading a file

import { Platform } from 'react-native'
import { createDownloadTask, completeHandler, directories } from '@kesha-antonov/react-native-background-downloader'

const jobId = 'file123'

let task = createDownloadTask({
id: jobId,
url: 'https://link-to-very.large/file.zip',
destination: `${directories.documents}/file.zip`,
metadata: {}
}).begin(({ expectedBytes, headers }) => {
console.log(`Going to download ${expectedBytes} bytes!`)
}).progress(({ bytesDownloaded, bytesTotal }) => {
console.log(`Downloaded: ${bytesDownloaded / bytesTotal * 100}%`)
}).done(({ bytesDownloaded, bytesTotal }) => {
console.log('Download is done!', { bytesDownloaded, bytesTotal })

// PROCESS YOUR STUFF

// FINISH DOWNLOAD JOB
completeHandler(jobId)
}).error(({ error, errorCode }) => {
console.log('Download canceled due to error: ', { error, errorCode });
})

// starts download
task.start()

// ...later

// Pause the task
await task.pause()

// Resume after pause
await task.resume()

// Cancel the task
await task.stop()

Re-Attaching to background tasks

The killer feature of this library: reconnect to downloads and uploads that continued running while your app was closed, or resume paused tasks from a previous session.

When the OS terminates your app to free memory, background transfers keep running. When your app restarts, call getExistingDownloadTasks() or getExistingUploadTasks() to get back in sync. Paused tasks are also preserved and can be resumed with task.resume().

💡 Tip: Use meaningful task IDs (not random UUIDs) so you can match tasks to your UI components after restart.

Downloads:

import { getExistingDownloadTasks } from '@kesha-antonov/react-native-background-downloader'

const lostTasks = await getExistingDownloadTasks()

for (const task of lostTasks) {
console.log(`Found download: ${task.id}`)

task.progress(({ bytesDownloaded, bytesTotal }) => {
console.log(`Downloaded: ${bytesDownloaded / bytesTotal * 100}%`)
}).done(({ location, bytesDownloaded, bytesTotal }) => {
console.log('Download complete!', { location, bytesDownloaded, bytesTotal })
}).error(({ error, errorCode }) => {
console.log('Download failed:', { error, errorCode })
})
}

Uploads:

import { getExistingUploadTasks } from '@kesha-antonov/react-native-background-downloader'

const lostUploads = await getExistingUploadTasks()

for (const task of lostUploads) {
console.log(`Found upload: ${task.id}`)

task.progress(({ bytesUploaded, bytesTotal }) => {
console.log(`Uploaded: ${bytesUploaded / bytesTotal * 100}%`)
}).done(({ responseCode, responseBody }) => {
console.log('Upload complete!', { responseCode, responseBody })
}).error(({ error, errorCode }) => {
console.log('Upload failed:', { error, errorCode })
})
}
Uploading a file
import { Platform } from 'react-native'
import { createUploadTask, completeHandler, directories } from '@kesha-antonov/react-native-background-downloader'

const jobId = 'upload123'

let task = createUploadTask({
id: jobId,
url: 'https://your-server.com/upload',
source: `${directories.documents}/photo.jpg`,
method: 'POST', // or 'PUT', 'PATCH'
fieldName: 'file', // multipart form field name
mimeType: 'image/jpeg',
parameters: {
userId: '123',
description: 'My photo'
},
metadata: {}
}).begin(({ expectedBytes }) => {
console.log(`Going to upload ${expectedBytes} bytes!`)
}).progress(({ bytesUploaded, bytesTotal }) => {
console.log(`Uploaded: ${bytesUploaded / bytesTotal * 100}%`)
}).done(({ responseCode, responseBody, bytesUploaded, bytesTotal }) => {
console.log('Upload is done!', { responseCode, responseBody })

// PROCESS YOUR STUFF

// FINISH UPLOAD JOB
completeHandler(jobId)
}).error(({ error, errorCode }) => {
console.log('Upload canceled due to error: ', { error, errorCode })
})

// starts upload
task.start()

// ...later

// Pause the task (platform support may vary)
await task.pause()

// Resume after pause
await task.resume()

// Cancel the task
await task.stop()
Updating headers on paused downloads

If your download uses authentication tokens that expire, you can update the headers of a paused download before resuming it. This is useful when auth tokens refresh while a download is paused:

import { getExistingDownloadTasks } from '@kesha-antonov/react-native-background-downloader'

// Get paused downloads
const tasks = await getExistingDownloadTasks()

for (const task of tasks) {
if (task.state === 'PAUSED') {
// Update headers with new auth token before resuming
await task.setDownloadParams({
...task.downloadParams,
headers: {
...task.downloadParams?.headers,
Authorization: 'Bearer new-refreshed-token'
}
})

// Now resume with the updated headers
await task.resume()
}
}

Notes:

  • setDownloadParams() is async and returns true if native headers were updated
  • Headers are only updated in the native layer when the task is in PAUSED state
  • On iOS, the download will resume using HTTP Range headers with the new headers
  • On Android, both in-memory and persisted paused state are updated

Use case: User pauses a large download, closes the app, and returns hours or days later. By then, the auth token has expired. This feature allows refreshing the token and updating headers before resuming, without restarting the download from scratch.