rn-file-toolkit
The ultimate, unified native file management toolkit for React Native & Expo.
Why rn-file-toolkit?
Most React Native file solutions are fragmented or lightly maintained. rn-file-toolkit gives you a unified, TurboModule-compatible API utilizing OS-native managers for reliable operations.
React Hooks Ready
Built-in state management with useDownload for progress, speeds, and ETA.
Background Persistence
Downloads and uploads survive app suspension with automatic re-attachment.
Smart Queueing
Cap concurrency and set priorities globally without touching native code.
Zero-Dependency Zip
Compress and extract using native java.util.zip and iOS zlib.
Installation
Install the library using your preferred package manager:
# npm
npm install rn-file-toolkit
# yarn
yarn add rn-file-toolkit
# pnpm
pnpm add rn-file-toolkit
(Optional) If you are not using Expo or an auto-linking setup, run pod install in your ios directory.
Quick Start: useDownload
The easiest way to manage a download inside a React component. Get status, rich progress (with speed & ETA), and full controls instantly.
import React from 'react';
import { View, Text, Button } from 'react-native';
import { useDownload } from 'rn-file-toolkit';
export default function DownloadScreen() {
const { start, pause, resume, cancel, status, progress, result } = useDownload();
return (
<View style={{ padding: 20 }}>
<Button
title="Start Download"
onPress={() =>
start({
url: 'https://example.com/large-video.mp4',
destination: 'documents',
})
}
/>
{status === 'downloading' && progress && (
<View style={{ marginTop: 20 }}>
<Text>Progress: {progress.percent.toFixed(1)}%</Text>
<Text>Speed: {(progress.speedBps / 1024 / 1024).toFixed(2)} MB/s</Text>
<Text>ETA: {progress.etaSeconds.toFixed(0)} seconds</Text>
<View style={{ flexDirection: 'row', gap: 10, marginTop: 10 }}>
<Button title="Pause" onPress={pause} />
<Button title="Cancel" onPress={cancel} color="red" />
</View>
</View>
)}
{status === 'done' && <Text style={{ color: 'green' }}>Saved: {result?.filePath}</Text>}
{status === 'error' && <Text style={{ color: 'red' }}>Error: {result?.error}</Text>}
</View>
);
}
Background Downloads
For programmatic, queue-aware background downloads outside of React components.
import { download } from 'rn-file-toolkit';
const result = await download({
url: 'https://example.com/file.pdf',
fileName: 'report.pdf', // Optional custom filename
destination: 'documents', // 'downloads' | 'cache' | 'documents'
background: true, // Survive app suspension
headers: { Authorization: 'Bearer token' },
queue: true, // Join the managed queue
priority: 'high', // 'high' | 'normal'
downloadId: 'my-unique-id', // Optional custom ID for tracking
notificationTitle: 'Downloading report…', // Android notification
notificationDescription: 'Please wait',
checksum: { hash: 'abc123...', algorithm: 'sha256' }, // Verify integrity
retry: {
attempts: 3,
delay: 1000,
onRetry: (attempt, error) => console.warn(`Retry #${attempt}: ${error}`),
},
onProgress: (p) => console.log(`${p.percent.toFixed(1)}% downloaded`),
});
console.log(result.filePath); // Path to the downloaded file
Download Controls
Pause, resume, or cancel any active download by its ID—works both inside and outside React components.
import {
download,
pauseDownload,
resumeDownload,
cancelDownload,
} from 'rn-file-toolkit';
// Start a download with a known ID
const result = download({
url: 'https://example.com/large-video.mp4',
downloadId: 'video-1',
destination: 'documents',
});
// Later… pause, resume, or cancel by ID
await pauseDownload('video-1');
await resumeDownload('video-1');
await cancelDownload('video-1');
Multipart Uploads
Robust, memory-efficient multipart file uploading for large media or documents.
import { upload } from 'rn-file-toolkit';
const result = await upload({
url: 'https://api.example.com/v1/upload',
filePath: '/path/to/local/image.jpg',
fieldName: 'file',
headers: { Authorization: 'Bearer token' },
parameters: { userId: '123', folder: 'avatars' },
uploadId: 'upload-1', // Optional custom ID for tracking
onProgress: (percent) => console.log(`Uploading: ${percent}%`),
});
console.log(result.status); // HTTP status code
console.log(result.data); // Server response body
Queue Management
Control download concurrency globally and inspect the queue state.
import { setQueueOptions, getQueueStatus, getBackgroundDownloads } from 'rn-file-toolkit';
// Set the maximum number of simultaneous downloads
setQueueOptions({ maxConcurrent: 3 });
// Inspect the queue at any time
const status = getQueueStatus();
console.log(status.active); // Currently downloading
console.log(status.pending); // Waiting in queue
console.log(status.maxConcurrent); // Concurrency cap
// Retrieve all background downloads currently running
const active = await getBackgroundDownloads();
console.log(active); // Array of background download descriptors
File System (FS)
Perform native filesystem operations securely. Available via the namespaced fs object.
import { fs } from 'rn-file-toolkit';
// Check & Inspect
const exists = await fs.exists('/path/to/data.json');
const stats = await fs.stat('/path/to/data.json'); // { path, name, size, modified, isDir }
// Read & Write
await fs.writeFile('/path/to/data.txt', 'Hello World', 'utf8');
const content = await fs.readFile('/path/to/data.txt', 'utf8');
// Manage Folders & Files
await fs.mkdir('/path/to/new_folder');
const files = await fs.ls('/path/to/new_folder');
await fs.copyFile('/path/src.txt', '/path/dest.txt');
await fs.moveFile('/path/old.txt', '/path/new.txt');
await fs.deleteFile('/path/unwanted.txt');
Zip & Unzip Archives
Compress and extract archives directly on the device using native java.util.zip (Android) and zlib (iOS).
import { unzip, zip } from 'rn-file-toolkit';
// Extract a downloaded zip
const unzipResult = await unzip('/path/to/bundle.zip', '/path/to/extract-folder');
console.log(unzipResult.files); // List of extracted file paths
// Compress user data before uploading
const zipResult = await zip('/path/to/user-data-folder', '/path/to/backup.zip');
console.log(zipResult.zipPath); // Path to the created archive
Cache Management
Inspect and clear files stored in the cache directory.
import { getCachedFiles, clearCache } from 'rn-file-toolkit';
// List all cached files with metadata
const cache = await getCachedFiles();
cache.files?.forEach((f) => {
console.log(f.fileName, f.filePath, f.size, f.modifiedAt);
});
// Wipe the entire cache directory
await clearCache();
Media & Utilities
Helpful tools for sharing, opening, and encoding files.
import { saveBase64AsFile, urlToBase64, shareFile, openFile } from 'rn-file-toolkit';
// Base64 to File (accepts raw base64 or data URIs)
await saveBase64AsFile({
base64Data: 'data:image/png;base64,...',
destination: 'documents',
fileName: 'image.png',
});
// URL to Base64 (great for caching small images)
const b64 = await urlToBase64({
url: 'https://example.com/icon.png',
headers: { Authorization: 'Bearer token' }, // Optional
});
console.log(b64.dataUri); // Ready-to-use data URI string
// Native Share Sheet
await shareFile({
filePath: '/path/to/report.pdf',
title: 'Share report',
subject: 'Monthly report',
});
// Open with default system app
await openFile({
filePath: '/path/to/report.pdf',
mimeType: 'application/pdf',
});
Disk Space
Check available and total device storage.
import { df } from 'rn-file-toolkit';
const space = await df();
if (space.success) {
console.log(`Free: ${(space.freeBytes! / 1024 / 1024 / 1024).toFixed(2)} GB`);
console.log(`Total: ${(space.totalBytes! / 1024 / 1024 / 1024).toFixed(2)} GB`);
}
File Appending
Append data to the end of a file without overwriting existing content.
import { appendFile } from 'rn-file-toolkit';
// Append a log line
await appendFile('/path/to/log.txt', 'New log entry\n');
// Append base64 data
await appendFile('/path/to/data.bin', base64String, 'base64');
File Hashing
Compute the MD5, SHA-1, or SHA-256 hash of any file on disk.
import { hash } from 'rn-file-toolkit';
const result = await hash('/path/to/file.zip', 'sha256');
if (result.success) {
console.log('SHA-256:', result.hash);
}
Session Management
Group downloaded files into sessions for batch cleanup. Useful for temporary workflows.
import { session, download } from 'rn-file-toolkit';
// Download files and track them in a session
const result = await download({ url: 'https://example.com/tmp1.pdf', destination: 'cache' });
if (result.filePath) session.add('my-workflow', result.filePath);
// List session files
console.log(session.get('my-workflow')); // ['/path/to/tmp1.pdf']
// Clean up everything when done
await session.clear('my-workflow');
MediaStore / Photos Library
Save files directly to the device's shared media gallery (Photos on iOS, MediaStore on Android).
import { saveToMediaStore } from 'rn-file-toolkit';
const result = await saveToMediaStore({
filePath: '/path/to/photo.jpg',
mediaType: 'image',
album: 'MyApp', // Optional album/subfolder
});
console.log(result.uri); // content://... (Android) or file path (iOS)
Note: iOS requires NSPhotoLibraryAddUsageDescription in your Info.plist for image/video saves.
Event Listeners
Subscribe to global download and upload lifecycle events. Each listener returns an unsubscribe function.
import { onDownloadComplete, onDownloadError, onDownloadRetry, onUploadProgress } from 'rn-file-toolkit';
// Subscribe
const unsub1 = onDownloadComplete((event) => console.log('Done:', event));
const unsub2 = onDownloadError((event) => console.error('Failed:', event));
const unsub3 = onDownloadRetry((event) => console.warn(`Retry #${event.attempt}`));
const unsub4 = onUploadProgress((event) => console.log(`Upload ${event.progress}%`));
// Clean up
unsub1();
unsub2();
unsub3();
unsub4();
API Reference
| Interface | Description |
|---|---|
DownloadOptions |
Full configuration for downloading a file (url, priority, background, etc.). |
UploadOptions |
Configuration for multipart uploads. |
ProgressInfo |
Rich real-time download progress payload (percent, speed, eta). |
DownloadResult |
Result returned after a download completes. |
FsApi |
Namespaced filesystem API containing stat, read, write, etc. |
Expo Support
rn-file-toolkit works seamlessly with Expo custom development clients (EAS Build / npx expo run:android / npx expo run:ios). Since it contains native code, it is not compatible with Expo Go.
An Expo config plugin is included automatically. No extra configuration is needed in your app.json unless you want to customize permissions.
How does it compare?
| Feature | rn-file-toolkit |
react-native-fs / rn-fetch-blob |
|---|---|---|
| Background Persistence | Yes | Spotty / Legacy |
| Smart Queueing & Concurrency | Built-in | Write your own |
React Hooks (useDownload) |
Out-of-the-box | Manual |
| Auto-Retries & Resumption | Yes | Manual |
| Expo Support | Seamless (Custom Dev Client) | Requires heavy config |