rn-file-toolkit 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -432
- package/android/src/main/java/com/filetoolkit/FileToolkitModule.kt +142 -12
- package/ios/FileToolkit.mm +219 -110
- package/lib/commonjs/index.js +147 -562
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +147 -562
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +27 -443
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +27 -443
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +10 -3
- package/src/index.tsx +177 -783
package/README.md
CHANGED
|
@@ -1,522 +1,242 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/rn-file-toolkit)
|
|
6
|
+
[](https://www.npmjs.com/package/rn-file-toolkit)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://github.com/chavan-labs/rn-file-toolkit)
|
|
9
|
+
[](https://github.com/chavan-labs/rn-file-toolkit/blob/main/LICENSE)
|
|
10
|
+
</div>
|
|
54
11
|
|
|
55
12
|
---
|
|
56
13
|
|
|
57
|
-
|
|
14
|
+
**rn-file-toolkit** is the modern replacement for legacy file libraries. Download, upload, manage queues, extract archives, and interact with the filesystem—all powered by pure native implementations (Kotlin + Swift) with **zero third-party dependencies**.
|
|
58
15
|
|
|
59
|
-
|
|
60
|
-
npm install rn-file-toolkit
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## API
|
|
66
|
-
|
|
67
|
-
### `download(options)`
|
|
68
|
-
|
|
69
|
-
```javascript
|
|
70
|
-
import { download } from 'rn-file-toolkit';
|
|
71
|
-
|
|
72
|
-
const result = await download({
|
|
73
|
-
url: 'https://example.com/file.pdf',
|
|
74
|
-
fileName: 'my_file.pdf',
|
|
75
|
-
headers: { Authorization: 'Bearer <token>' },
|
|
76
|
-
destination: 'documents', // 'downloads' | 'cache' | 'documents'
|
|
77
|
-
checksum: {
|
|
78
|
-
hash: 'd41d8cd98f00b204e9800998ecf8427e',
|
|
79
|
-
algorithm: 'md5',
|
|
80
|
-
},
|
|
81
|
-
onProgress: ({
|
|
82
|
-
percent,
|
|
83
|
-
bytesDownloaded,
|
|
84
|
-
totalBytes,
|
|
85
|
-
speedBps,
|
|
86
|
-
etaSeconds,
|
|
87
|
-
}) => {
|
|
88
|
-
console.log(
|
|
89
|
-
`${percent.toFixed(1)}% — ${(speedBps / 1024).toFixed(
|
|
90
|
-
1
|
|
91
|
-
)} KB/s — ETA ${etaSeconds.toFixed(0)}s`
|
|
92
|
-
);
|
|
93
|
-
},
|
|
94
|
-
// Auto-retry on network failure (optional)
|
|
95
|
-
retry: {
|
|
96
|
-
attempts: 3, // max retry attempts
|
|
97
|
-
delay: 1000, // base delay in ms; doubles each attempt: 1s → 2s → 4s (capped at 30s)
|
|
98
|
-
onRetry: (attempt, error) => console.log(`Retry #${attempt}: ${error}`),
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
```
|
|
16
|
+
⭐ **Star this repo if you find it useful to help others discover it!**
|
|
102
17
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
18
|
+
## 📖 Table of Contents
|
|
19
|
+
- [Why rn-file-toolkit?](#-why-rn-file-toolkit)
|
|
20
|
+
- [Installation](#-installation)
|
|
21
|
+
- [Quick Start: `useDownload`](#-quick-start-usedownload)
|
|
22
|
+
- [Core APIs](#-core-apis)
|
|
23
|
+
- [Background Downloads](#background-downloads)
|
|
24
|
+
- [Multipart Uploads](#multipart-uploads)
|
|
25
|
+
- [File System (FS)](#file-system-fs)
|
|
26
|
+
- [Zip & Unzip Archives](#zip--unzip-archives)
|
|
27
|
+
- [Media & Utilities](#media--utilities)
|
|
28
|
+
- [API Reference](#-api-reference)
|
|
29
|
+
- [Expo Support](#-expo-support)
|
|
30
|
+
- [Contributing](#-contributing)
|
|
109
31
|
|
|
110
32
|
---
|
|
111
33
|
|
|
112
|
-
|
|
34
|
+
## 🚀 Why rn-file-toolkit?
|
|
113
35
|
|
|
114
|
-
|
|
36
|
+
Most React Native file solutions (`rn-fetch-blob`, `react-native-fs`) are fragmented, lightly maintained, or lack modern features. **rn-file-toolkit** gives you a unified, **TurboModule-ready** API utilizing OS-native managers (`URLSession` on iOS, `DownloadManager` on Android) for reliable, battery-efficient operations.
|
|
115
37
|
|
|
116
|
-
|
|
117
|
-
|
|
38
|
+
### ✨ Highlights
|
|
39
|
+
- 🪝 **Drop-in React Hooks:** Built-in state management (`useDownload`) for progress and controls.
|
|
40
|
+
- 📥 **Background Ready:** Downloads and uploads survive app suspension with automatic re-attachment.
|
|
41
|
+
- 🚦 **Smart Queueing:** Cap concurrency and set priorities without touching native code.
|
|
42
|
+
- 🛡️ **Resilient:** Auto-retries on network errors with exponential backoff and HTTP resume.
|
|
43
|
+
- 🗜️ **Zero-Dependency Zip:** Uses native `java.util.zip` and iOS `zlib`.
|
|
44
|
+
- 🗄️ **Rich File System API:** Comprehensive FS methods (`readFile`, `writeFile`, `copyFile`, `mkdir`, `stat`, etc.).
|
|
45
|
+
- 🛠️ **Expo Compatible:** Seamless integration with Expo custom dev clients.
|
|
118
46
|
|
|
119
|
-
|
|
120
|
-
setQueueOptions({ maxConcurrent: 3 }); // default is 3
|
|
47
|
+
---
|
|
121
48
|
|
|
122
|
-
|
|
123
|
-
const promises = urls.map((url) =>
|
|
124
|
-
download({
|
|
125
|
-
url,
|
|
126
|
-
destination: 'documents',
|
|
127
|
-
queue: true, // join the managed queue
|
|
128
|
-
priority: 'normal', // 'high' | 'normal' (default)
|
|
129
|
-
onProgress: (p) => console.log(`${url}: ${p.percent}%`),
|
|
130
|
-
})
|
|
131
|
-
);
|
|
49
|
+
## 📦 Installation
|
|
132
50
|
|
|
133
|
-
|
|
51
|
+
```bash
|
|
52
|
+
# npm
|
|
53
|
+
npm install rn-file-toolkit
|
|
134
54
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
url: 'https://example.com/urgent.pdf',
|
|
138
|
-
queue: true,
|
|
139
|
-
priority: 'high',
|
|
140
|
-
});
|
|
55
|
+
# yarn
|
|
56
|
+
yarn add rn-file-toolkit
|
|
141
57
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
console.log(`Running: ${active} Waiting: ${pending} Limit: ${maxConcurrent}`);
|
|
58
|
+
# pnpm
|
|
59
|
+
pnpm add rn-file-toolkit
|
|
145
60
|
```
|
|
146
61
|
|
|
147
|
-
|
|
148
|
-
>
|
|
149
|
-
> - `queue: false` (default) — download starts immediately, bypassing the queue entirely. All existing behaviour is unchanged.
|
|
150
|
-
> - `queue: true` — the download is placed in the JS queue. It starts as soon as an active slot is free.
|
|
151
|
-
> - `priority: 'high'` — item is inserted at the **front** of the pending list, so it runs before any `'normal'` items.
|
|
152
|
-
> - `priority: 'normal'` (default) — item is appended to the **back**.
|
|
153
|
-
> - `setQueueOptions` can be called at any time; if `maxConcurrent` is increased, idle slots are filled immediately.
|
|
154
|
-
> - All other `DownloadOptions` (`onProgress`, `retry`, `checksum`, `headers`, etc.) work exactly the same inside the queue.
|
|
62
|
+
*(Optional) If you are not using Expo or an auto-linking setup, run `pod install` in your `ios` directory.*
|
|
155
63
|
|
|
156
64
|
---
|
|
157
65
|
|
|
158
|
-
|
|
66
|
+
## ⚡ Quick Start: `useDownload`
|
|
159
67
|
|
|
160
|
-
The easiest way to manage a download inside a React component. Get status, rich progress (with speed & ETA), and full controls
|
|
68
|
+
The easiest way to manage a download inside a React component. Get status, rich progress (with speed & ETA), and full controls instantly.
|
|
161
69
|
|
|
162
70
|
```tsx
|
|
71
|
+
import React from 'react';
|
|
72
|
+
import { View, Text, Button } from 'react-native';
|
|
163
73
|
import { useDownload } from 'rn-file-toolkit';
|
|
164
74
|
|
|
165
|
-
function DownloadScreen() {
|
|
166
|
-
const { start, pause, resume, cancel, status, progress, result } =
|
|
167
|
-
useDownload();
|
|
75
|
+
export default function DownloadScreen() {
|
|
76
|
+
const { start, pause, resume, cancel, status, progress, result } = useDownload();
|
|
168
77
|
|
|
169
78
|
return (
|
|
170
|
-
<View>
|
|
171
|
-
<Button
|
|
172
|
-
title="Download"
|
|
173
|
-
onPress={() =>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
})
|
|
178
|
-
}
|
|
79
|
+
<View style={{ padding: 20 }}>
|
|
80
|
+
<Button
|
|
81
|
+
title="Start Download"
|
|
82
|
+
onPress={() => start({
|
|
83
|
+
url: 'https://example.com/large-video.mp4',
|
|
84
|
+
destination: 'documents'
|
|
85
|
+
})}
|
|
179
86
|
/>
|
|
180
87
|
|
|
181
88
|
{status === 'downloading' && progress && (
|
|
182
|
-
<View>
|
|
183
|
-
<Text>{progress.percent.toFixed(1)}%</Text>
|
|
184
|
-
<Text>Speed: {(progress.speedBps / 1024).toFixed(
|
|
185
|
-
<Text>ETA: {progress.etaSeconds.toFixed(0)}
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
{
|
|
189
|
-
|
|
190
|
-
</Text>
|
|
191
|
-
<Button title="Pause" onPress={pause} />
|
|
192
|
-
<Button title="Cancel" onPress={cancel} />
|
|
89
|
+
<View style={{ marginTop: 20 }}>
|
|
90
|
+
<Text>Progress: {progress.percent.toFixed(1)}%</Text>
|
|
91
|
+
<Text>Speed: {(progress.speedBps / 1024 / 1024).toFixed(2)} MB/s</Text>
|
|
92
|
+
<Text>ETA: {progress.etaSeconds.toFixed(0)} seconds</Text>
|
|
93
|
+
<View style={{ flexDirection: 'row', gap: 10, marginTop: 10 }}>
|
|
94
|
+
<Button title="Pause" onPress={pause} />
|
|
95
|
+
<Button title="Cancel" onPress={cancel} color="red" />
|
|
96
|
+
</View>
|
|
193
97
|
</View>
|
|
194
98
|
)}
|
|
195
99
|
|
|
196
100
|
{status === 'paused' && <Button title="Resume" onPress={resume} />}
|
|
197
|
-
|
|
198
|
-
{status === '
|
|
199
|
-
<Text>✅ Saved to: {result.filePath}</Text>
|
|
200
|
-
)}
|
|
201
|
-
|
|
202
|
-
{status === 'error' && <Text>❌ {result?.error}</Text>}
|
|
101
|
+
{status === 'done' && <Text style={{ color: 'green' }}>✅ Saved: {result?.filePath}</Text>}
|
|
102
|
+
{status === 'error' && <Text style={{ color: 'red' }}>❌ Error: {result?.error}</Text>}
|
|
203
103
|
</View>
|
|
204
104
|
);
|
|
205
105
|
}
|
|
206
106
|
```
|
|
207
107
|
|
|
208
|
-
| Property | Type | Description |
|
|
209
|
-
| ---------------- | ---------------------------------------------------------- | ------------------------------- |
|
|
210
|
-
| `start(options)` | `(options: DownloadOptions) => Promise<DownloadResult>` | Start a download |
|
|
211
|
-
| `pause()` | `() => Promise<void>` | Pause the active download |
|
|
212
|
-
| `resume()` | `() => Promise<void>` | Resume a paused download |
|
|
213
|
-
| `cancel()` | `() => Promise<void>` | Cancel and discard the download |
|
|
214
|
-
| `status` | `'idle' \| 'downloading' \| 'paused' \| 'done' \| 'error'` | Current state |
|
|
215
|
-
| `progress` | `ProgressInfo \| null` | Live progress info (see below) |
|
|
216
|
-
| `result` | `DownloadResult \| null` | Final result once complete |
|
|
217
|
-
| `downloadId` | `string \| null` | Active download ID |
|
|
218
|
-
|
|
219
108
|
---
|
|
220
109
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
```javascript
|
|
224
|
-
import { upload } from 'rn-file-toolkit';
|
|
225
|
-
|
|
226
|
-
const result = await upload({
|
|
227
|
-
url: 'https://example.com/api/upload',
|
|
228
|
-
filePath: '/path/to/my_image.jpg',
|
|
229
|
-
fieldName: 'avatar', // default: 'file'
|
|
230
|
-
parameters: {
|
|
231
|
-
userId: '123',
|
|
232
|
-
},
|
|
233
|
-
headers: { 'X-Custom-Header': 'value' },
|
|
234
|
-
onProgress: (p) => console.log(`Uploading: ${p}%`),
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
if (result.success) {
|
|
238
|
-
console.log('Response:', result.data);
|
|
239
|
-
}
|
|
240
|
-
```
|
|
110
|
+
## 🛠️ Core APIs
|
|
241
111
|
|
|
242
|
-
|
|
112
|
+
### Background Downloads
|
|
113
|
+
For programmatic, queue-aware background downloads outside of React components.
|
|
243
114
|
|
|
244
|
-
|
|
115
|
+
```typescript
|
|
116
|
+
import { download, setQueueOptions } from 'rn-file-toolkit';
|
|
245
117
|
|
|
246
|
-
|
|
118
|
+
// Optimize global concurrency
|
|
119
|
+
setQueueOptions({ maxConcurrent: 3 });
|
|
247
120
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
// From data URI (auto-detects file extension)
|
|
252
|
-
const result = await saveBase64AsFile({
|
|
253
|
-
base64Data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...',
|
|
254
|
-
fileName: 'photo.png',
|
|
121
|
+
const result = await download({
|
|
122
|
+
url: 'https://example.com/file.pdf',
|
|
255
123
|
destination: 'documents', // 'downloads' | 'cache' | 'documents'
|
|
124
|
+
queue: true, // Join the managed queue
|
|
125
|
+
priority: 'high', // 'high' | 'normal'
|
|
126
|
+
retry: { attempts: 3, delay: 1000 },
|
|
127
|
+
onProgress: (p) => console.log(`${p.percent.toFixed(1)}% downloaded`),
|
|
256
128
|
});
|
|
257
|
-
|
|
258
|
-
// From plain base64 string
|
|
259
|
-
const result = await saveBase64AsFile({
|
|
260
|
-
base64Data: 'SGVsbG8gV29ybGQ=',
|
|
261
|
-
fileName: 'hello.txt',
|
|
262
|
-
destination: 'cache',
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
if (result.success) {
|
|
266
|
-
console.log('File saved at:', result.filePath);
|
|
267
|
-
}
|
|
268
129
|
```
|
|
269
130
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
### `urlToBase64(options)`
|
|
131
|
+
### Multipart Uploads
|
|
132
|
+
Robust, memory-efficient multipart file uploading for large media or documents.
|
|
273
133
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
```javascript
|
|
277
|
-
import { urlToBase64 } from 'rn-file-toolkit';
|
|
134
|
+
```typescript
|
|
135
|
+
import { upload } from 'rn-file-toolkit';
|
|
278
136
|
|
|
279
|
-
const result = await
|
|
280
|
-
url: 'https://example.com/
|
|
281
|
-
|
|
137
|
+
const result = await upload({
|
|
138
|
+
url: 'https://api.example.com/v1/upload',
|
|
139
|
+
filePath: '/path/to/local/image.jpg',
|
|
140
|
+
fieldName: 'file',
|
|
141
|
+
parameters: { userId: '123', folder: 'avatars' },
|
|
142
|
+
onProgress: (percent) => console.log(`Uploading: ${percent}%`),
|
|
282
143
|
});
|
|
283
|
-
|
|
284
|
-
if (result.success) {
|
|
285
|
-
console.log('Base64:', result.base64);
|
|
286
|
-
console.log('Data URI:', result.dataUri);
|
|
287
|
-
console.log('MIME Type:', result.mimeType); // e.g., 'image/jpeg'
|
|
288
|
-
|
|
289
|
-
// Use in Image component
|
|
290
|
-
// <Image source={{ uri: result.dataUri }} />
|
|
291
|
-
}
|
|
292
144
|
```
|
|
293
145
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
### `shareFile(options)`
|
|
146
|
+
### File System (FS)
|
|
147
|
+
Perform native filesystem operations securely.
|
|
297
148
|
|
|
298
|
-
|
|
149
|
+
```typescript
|
|
150
|
+
import { fs } from 'rn-file-toolkit';
|
|
299
151
|
|
|
300
|
-
|
|
301
|
-
|
|
152
|
+
// Check & Inspect
|
|
153
|
+
const exists = await fs.exists('/path/to/data.json');
|
|
154
|
+
const stats = await fs.stat('/path/to/data.json'); // { size, modified, isDir }
|
|
302
155
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
subject: 'Check this out', // Android only
|
|
307
|
-
});
|
|
156
|
+
// Read & Write
|
|
157
|
+
await fs.writeFile('/path/to/data.txt', 'Hello World', 'utf8'); // Also supports 'base64'
|
|
158
|
+
const content = await fs.readFile('/path/to/data.txt', 'utf8');
|
|
308
159
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
160
|
+
// Manage Folders & Files
|
|
161
|
+
await fs.mkdir('/path/to/new_folder');
|
|
162
|
+
const files = await fs.ls('/path/to/new_folder');
|
|
163
|
+
await fs.copyFile('/path/src.txt', '/path/dest.txt');
|
|
164
|
+
await fs.moveFile('/path/old.txt', '/path/new.txt');
|
|
165
|
+
await fs.deleteFile('/path/unwanted.txt');
|
|
312
166
|
```
|
|
313
167
|
|
|
314
|
-
|
|
168
|
+
### Zip & Unzip Archives
|
|
169
|
+
Compress and extract archives directly on the device.
|
|
315
170
|
|
|
316
|
-
|
|
171
|
+
```typescript
|
|
172
|
+
import { unzip, zip } from 'rn-file-toolkit';
|
|
317
173
|
|
|
318
|
-
|
|
174
|
+
// Extract a downloaded zip
|
|
175
|
+
await unzip('/path/to/bundle.zip', '/path/to/extract-folder');
|
|
319
176
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const result = await openFile({
|
|
324
|
-
filePath: '/path/to/document.pdf',
|
|
325
|
-
mimeType: 'application/pdf', // optional, auto-detected if not provided
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
if (result.success) {
|
|
329
|
-
console.log('File opened');
|
|
330
|
-
}
|
|
177
|
+
// Compress user data before uploading
|
|
178
|
+
await zip('/path/to/user-data-folder', '/path/to/backup.zip');
|
|
331
179
|
```
|
|
332
180
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
### `unzip(sourcePath, destDir)` · `zip(sourcePath, destPath)`
|
|
336
|
-
|
|
337
|
-
Compress and extract ZIP archives natively — **no third-party library required**.
|
|
181
|
+
### Media & Utilities
|
|
182
|
+
Helpful tools for sharing, opening, and encoding files.
|
|
338
183
|
|
|
339
|
-
|
|
340
|
-
|
|
184
|
+
```typescript
|
|
185
|
+
import { saveBase64AsFile, urlToBase64, shareFile, openFile } from 'rn-file-toolkit';
|
|
341
186
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
url: 'https://example.com/assets.zip',
|
|
348
|
-
destination: 'cache',
|
|
187
|
+
// Base64 to File
|
|
188
|
+
await saveBase64AsFile({
|
|
189
|
+
base64Data: 'data:image/png;base64,...',
|
|
190
|
+
destination: 'documents',
|
|
191
|
+
fileName: 'image.png'
|
|
349
192
|
});
|
|
350
193
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
dl.filePath, // absolute path to the .zip file
|
|
354
|
-
'/path/to/output-folder' // destination directory (created if it doesn't exist)
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
if (result.success) {
|
|
358
|
-
console.log('Destination:', result.destDir);
|
|
359
|
-
console.log('Extracted files:', result.files);
|
|
360
|
-
// result.files → ['/path/to/output-folder/image.png', ...]
|
|
361
|
-
} else {
|
|
362
|
-
console.log('Error:', result.error);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// ── Zip a single file ───────────────────────────────────────────────────────
|
|
367
|
-
const zipResult = await zip(
|
|
368
|
-
'/path/to/document.pdf', // source file
|
|
369
|
-
'/path/to/document.zip' // output archive path
|
|
370
|
-
);
|
|
194
|
+
// URL to Base64 (Great for caching small images)
|
|
195
|
+
const b64 = await urlToBase64({ url: 'https://example.com/icon.png' });
|
|
371
196
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
197
|
+
// Native Share Sheet
|
|
198
|
+
await shareFile({ filePath: '/path/to/report.pdf' });
|
|
375
199
|
|
|
376
|
-
//
|
|
377
|
-
|
|
378
|
-
'/path/to/my-folder', // source directory
|
|
379
|
-
'/path/to/my-folder.zip' // output archive path
|
|
380
|
-
);
|
|
200
|
+
// Open with default system app
|
|
201
|
+
await openFile({ filePath: '/path/to/report.pdf', mimeType: 'application/pdf' });
|
|
381
202
|
```
|
|
382
203
|
|
|
383
|
-
> **Notes:**
|
|
384
|
-
>
|
|
385
|
-
> - `unzip` auto-creates the destination directory including any intermediate folders.
|
|
386
|
-
> - `unzip` on Android protects against [zip-slip attacks](https://snyk.io/research/zip-slip-vulnerability) by validating each entry path.
|
|
387
|
-
> - `zip` supports both single files and entire directory trees (recursive).
|
|
388
|
-
> - Both functions run on a background thread and never block the JS thread.
|
|
389
|
-
> - Supported compression methods: **Deflate** (method 8) and **Store** (method 0) — the two methods used by virtually every ZIP file.
|
|
390
|
-
|
|
391
204
|
---
|
|
392
205
|
|
|
393
|
-
|
|
206
|
+
## 📚 API Reference
|
|
394
207
|
|
|
395
|
-
|
|
396
|
-
|
|
208
|
+
| Interface | Key Properties | Description |
|
|
209
|
+
| :--- | :--- | :--- |
|
|
210
|
+
| `DownloadOptions` | `url`, `destination`, `queue`, `retry`, `onProgress` | Configuration for downloading a file. |
|
|
211
|
+
| `UploadOptions` | `url`, `filePath`, `fieldName`, `parameters`, `onProgress` | Configuration for multipart uploads. |
|
|
212
|
+
| `ProgressInfo` | `percent`, `bytesDownloaded`, `speedBps`, `etaSeconds` | Rich real-time progress payload. |
|
|
213
|
+
| `UseDownloadReturn` | `start`, `pause`, `resume`, `cancel`, `status`, `progress` | Hook state and control methods. |
|
|
214
|
+
| `FsStat` | `size`, `modified`, `isDir` | Output of the filesystem `stat` method. |
|
|
397
215
|
|
|
398
|
-
|
|
399
|
-
await resumeDownload(downloadId);
|
|
400
|
-
await cancelDownload(downloadId);
|
|
401
|
-
```
|
|
216
|
+
*For advanced types and detailed parameter documentation, please refer to the source TypeScript definitions.*
|
|
402
217
|
|
|
403
218
|
---
|
|
404
219
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
```javascript
|
|
408
|
-
import { getCachedFiles, deleteFile, clearCache } from 'rn-file-toolkit';
|
|
220
|
+
## 🎪 Expo Support
|
|
409
221
|
|
|
410
|
-
|
|
411
|
-
const { files } = await getCachedFiles();
|
|
222
|
+
**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.
|
|
412
223
|
|
|
413
|
-
|
|
414
|
-
await deleteFile('/path/to/file.pdf');
|
|
415
|
-
|
|
416
|
-
// Clear all managed files
|
|
417
|
-
await clearCache();
|
|
418
|
-
```
|
|
224
|
+
An Expo config plugin is included automatically. No extra configuration is needed in your `app.json` unless you want to customize permissions.
|
|
419
225
|
|
|
420
226
|
---
|
|
421
227
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
Use built-in file system helpers without adding another dependency.
|
|
425
|
-
|
|
426
|
-
```javascript
|
|
427
|
-
import { fs } from 'rn-file-toolkit';
|
|
428
|
-
|
|
429
|
-
await fs.exists('/path/to/file.pdf'); // → true/false
|
|
430
|
-
|
|
431
|
-
await fs.stat('/path/to/file.pdf');
|
|
432
|
-
// → { path, name, size, modified, isDir }
|
|
433
|
-
|
|
434
|
-
await fs.readFile('/path/to/file.txt'); // utf8 by default
|
|
435
|
-
await fs.readFile('/path/to/file.bin', 'base64');
|
|
436
|
-
|
|
437
|
-
await fs.writeFile('/path/to/file.txt', 'hello');
|
|
438
|
-
await fs.writeFile('/path/to/file.bin', 'SGVsbG8=', 'base64');
|
|
439
|
-
|
|
440
|
-
await fs.copyFile('/src/file.pdf', '/dst/file.pdf');
|
|
441
|
-
await fs.moveFile('/src/file.pdf', '/dst/file.pdf');
|
|
442
|
-
await fs.deleteFile('/path/to/file.pdf');
|
|
443
|
-
|
|
444
|
-
await fs.mkdir('/path/to/folder');
|
|
445
|
-
await fs.ls('/path/to/folder'); // → string[]
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
> `readFile` / `writeFile` support encodings: `'utf8'` (default) and `'base64'`.
|
|
449
|
-
|
|
450
|
-
---
|
|
451
|
-
|
|
452
|
-
## Use Cases
|
|
453
|
-
|
|
454
|
-
### Download from URLs
|
|
455
|
-
|
|
456
|
-
Perfect for downloading files from remote servers with progress tracking, background support, and resume capability.
|
|
457
|
-
|
|
458
|
-
### Convert URLs to Base64
|
|
459
|
-
|
|
460
|
-
Convert remote media (images, videos, gifs) to base64 strings for:
|
|
461
|
-
|
|
462
|
-
- Display in Image components without downloading to disk
|
|
463
|
-
- Inline embedding in HTML/emails
|
|
464
|
-
- Upload to APIs requiring base64 format
|
|
465
|
-
- Cross-platform data transfer
|
|
466
|
-
|
|
467
|
-
### Save Base64/Data URIs
|
|
468
|
-
|
|
469
|
-
Convert base64-encoded data (like images from canvas, camera, or API responses) directly to files:
|
|
470
|
-
|
|
471
|
-
- Canvas-generated images (`canvas.toDataURL()`)
|
|
472
|
-
- Camera/photo library base64 outputs
|
|
473
|
-
- API responses with base64-encoded files
|
|
474
|
-
- Email attachments in base64 format
|
|
475
|
-
|
|
476
|
-
---
|
|
477
|
-
|
|
478
|
-
## Type Reference
|
|
479
|
-
|
|
480
|
-
| Type | Fields |
|
|
481
|
-
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
482
|
-
| `DownloadOptions` | `url`, `fileName?`, `background?`, `headers?`, `destination?`, `notificationTitle?`, `notificationDescription?`, `checksum?`, `onProgress?`, `retry?`, `queue?`, `priority?` |
|
|
483
|
-
| `ProgressInfo` | `percent`, `bytesDownloaded`, `totalBytes`, `speedBps`, `etaSeconds` |
|
|
484
|
-
| `RetryOptions` | `attempts`, `delay?`, `onRetry?` |
|
|
485
|
-
| `QueueOptions` | `maxConcurrent?` |
|
|
486
|
-
| `QueueStatus` | `active`, `pending`, `maxConcurrent` |
|
|
487
|
-
| `DownloadStatus` | `'idle' \| 'downloading' \| 'paused' \| 'done' \| 'error'` |
|
|
488
|
-
| `UseDownloadReturn` | `start`, `pause`, `resume`, `cancel`, `status`, `progress`, `result`, `downloadId` |
|
|
489
|
-
| `FsEncoding` | `'utf8' \| 'base64'` |
|
|
490
|
-
| `FsStat` | `path`, `name`, `size`, `modified`, `isDir` |
|
|
491
|
-
| `FsApi` | `exists`, `stat`, `readFile`, `writeFile`, `copyFile`, `moveFile`, `deleteFile`, `mkdir`, `ls` |
|
|
492
|
-
| `UploadOptions` | `url`, `filePath`, `fieldName?`, `headers?`, `parameters?`, `onProgress?` |
|
|
493
|
-
| `SaveBase64Options` | `base64Data`, `fileName?`, `destination?` |
|
|
494
|
-
| `UrlToBase64Options` | `url`, `headers?` |
|
|
495
|
-
| `ShareFileOptions` | `filePath`, `title?`, `subject?` |
|
|
496
|
-
| `OpenFileOptions` | `filePath`, `mimeType?` |
|
|
497
|
-
| `DownloadResult` | `success`, `filePath?`, `downloadId?`, `error?` |
|
|
498
|
-
| `UploadResult` | `success`, `status?`, `data?`, `error?` |
|
|
499
|
-
| `UnzipResult` | `success`, `destDir?`, `files?`, `error?` |
|
|
500
|
-
| `ZipResult` | `success`, `zipPath?`, `error?` |
|
|
501
|
-
| `SaveBase64Result` | `success`, `filePath?`, `error?` |
|
|
502
|
-
| `UrlToBase64Result` | `success`, `base64?`, `mimeType?`, `dataUri?`, `error?` |
|
|
503
|
-
| `ShareFileResult` | `success`, `completed?`, `error?` |
|
|
504
|
-
| `OpenFileResult` | `success`, `error?` |
|
|
505
|
-
| `Checksum` | `hash`, `algorithm: 'md5' \| 'sha1' \| 'sha256'` |
|
|
506
|
-
|
|
507
|
-
---
|
|
508
|
-
|
|
509
|
-
## Articles & Resources
|
|
510
|
-
|
|
511
|
-
- [**I Got Tired of React Native File Downloads Being a Mess — So I Built rn-file-toolkit**](https://medium.com/@chavanrohit413/i-got-tired-of-react-native-file-downloads-being-a-mess-so-i-built-rn-file-toolkit-29b7a8b5c743) — Deep dive into the problems with existing solutions and how rn-file-toolkit solves them
|
|
512
|
-
|
|
513
|
-
---
|
|
228
|
+
## 🤝 Contributing
|
|
514
229
|
|
|
515
|
-
|
|
230
|
+
Contributions are welcome! If you find a bug or want to request a feature, please [open an issue](https://github.com/chavan-labs/rn-file-toolkit/issues).
|
|
516
231
|
|
|
517
|
-
|
|
518
|
-
-
|
|
232
|
+
1. Fork the repository
|
|
233
|
+
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
234
|
+
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
235
|
+
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
236
|
+
5. Open a Pull Request
|
|
519
237
|
|
|
520
238
|
---
|
|
521
239
|
|
|
522
|
-
|
|
240
|
+
<div align="center">
|
|
241
|
+
<i>Built with ❤️ for the React Native community by <a href="https://github.com/chavan-labs">Rohit Chavan</a></i>
|
|
242
|
+
</div>
|