rn-file-toolkit 1.0.1

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.
Files changed (34) hide show
  1. package/FileToolkit.podspec +22 -0
  2. package/LICENSE +20 -0
  3. package/README.md +522 -0
  4. package/android/build.gradle +61 -0
  5. package/android/src/main/AndroidManifest.xml +13 -0
  6. package/android/src/main/java/com/filetoolkit/FileToolkitModule.kt +1204 -0
  7. package/android/src/main/java/com/filetoolkit/FileToolkitPackage.kt +31 -0
  8. package/android/src/main/res/xml/file_provider_paths.xml +14 -0
  9. package/app.plugin.js +49 -0
  10. package/ios/FileToolkit.h +6 -0
  11. package/ios/FileToolkit.mm +1468 -0
  12. package/lib/commonjs/NativeFileToolkit.js +9 -0
  13. package/lib/commonjs/NativeFileToolkit.js.map +1 -0
  14. package/lib/commonjs/index.js +941 -0
  15. package/lib/commonjs/index.js.map +1 -0
  16. package/lib/commonjs/package.json +1 -0
  17. package/lib/module/NativeFileToolkit.js +5 -0
  18. package/lib/module/NativeFileToolkit.js.map +1 -0
  19. package/lib/module/index.js +905 -0
  20. package/lib/module/index.js.map +1 -0
  21. package/lib/module/package.json +1 -0
  22. package/lib/typescript/commonjs/package.json +1 -0
  23. package/lib/typescript/commonjs/src/NativeFileToolkit.d.ts +29 -0
  24. package/lib/typescript/commonjs/src/NativeFileToolkit.d.ts.map +1 -0
  25. package/lib/typescript/commonjs/src/index.d.ts +635 -0
  26. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  27. package/lib/typescript/module/package.json +1 -0
  28. package/lib/typescript/module/src/NativeFileToolkit.d.ts +29 -0
  29. package/lib/typescript/module/src/NativeFileToolkit.d.ts.map +1 -0
  30. package/lib/typescript/module/src/index.d.ts +635 -0
  31. package/lib/typescript/module/src/index.d.ts.map +1 -0
  32. package/package.json +232 -0
  33. package/src/NativeFileToolkit.ts +29 -0
  34. package/src/index.tsx +1293 -0
@@ -0,0 +1,22 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "FileToolkit"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/chavan-labs/rn-file-toolkit.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
17
+ s.private_header_files = "ios/**/*.h"
18
+
19
+ s.libraries = "z"
20
+
21
+ install_modules_dependencies(s)
22
+ end
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Developer
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,522 @@
1
+ # rn-file-toolkit
2
+
3
+ [![npm version](https://img.shields.io/npm/v/rn-file-toolkit.svg?style=flat-square)](https://www.npmjs.com/package/rn-file-toolkit)
4
+ [![npm downloads](https://img.shields.io/npm/dm/rn-file-toolkit.svg?style=flat-square)](https://www.npmjs.com/package/rn-file-toolkit)
5
+ [![license](https://img.shields.io/npm/l/rn-file-toolkit.svg?style=flat-square)](https://github.com/chavan-labs/rn-file-toolkit/blob/main/LICENSE)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg?style=flat-square)](https://www.typescriptlang.org/)
7
+ [![platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20Android-lightgrey.svg?style=flat-square)](https://github.com/chavan-labs/rn-file-toolkit)
8
+
9
+ The easiest way to download **and manage files** in React Native — with background support, pause/resume, upload, queueing, and built-in filesystem APIs.
10
+
11
+ > 100% pure native code (Kotlin + Swift). Zero third-party dependencies.
12
+
13
+ **Keywords:** react native download, react native file download, react native background download, react native download manager, react native file upload, react native download progress, react native pause resume download, react native cache manager, react native turbo module, expo download, iOS URLSession, Android DownloadManager, react native checksum validation, base64 converter, url to base64, data uri, share file, open file, file sharing, native share, document viewer, download queue, concurrent downloads, queue concurrency, priority queue, batch download, max concurrent downloads, react native filesystem, read file, write file, copy file, move file, stat file, file exists, useDownload hook, download speed, download eta, download progress bytes
14
+
15
+ ⭐ **Star this repo if you found it useful** — it helps others discover the project!
16
+
17
+ ## Problems?
18
+
19
+ Most React Native file download solutions have one or more of these problems:
20
+
21
+ - **Complexity** — require configuring native modules, background tasks, and notification channels separately
22
+ - **Dependencies** — rely on heavy third-party libraries that bloat your app size
23
+ - **Limited features** — lack pause/resume, checksum validation, or proper background support
24
+ - **No queue** — spawn 20 downloads and you'll crash or saturate the network; libraries like `react-native-blob-util` have no queue at all
25
+ - **Split libraries** — downloading is in one package, filesystem operations in another (read/write/copy/stat/exists), adding extra dependency and complexity
26
+ - **Poor DX** — complicated APIs that require managing multiple IDs, listeners, and cleanup logic
27
+
28
+ **rn-file-toolkit** was built to solve these issues. It provides a simple, unified API while leveraging platform-native download managers (URLSession on iOS, DownloadManager on Android) for reliable, battery-efficient downloads. Everything works out of the box — background downloads, progress tracking, pause/resume — without wrestling with native configuration.
29
+
30
+ ## ✨ Features
31
+
32
+ - **`useDownload()` hook** — drop-in React hook with built-in state: `status`, `progress`, `result`, `pause`, `resume`, `cancel` — no competitors have this
33
+ - **Rich progress info** — `onProgress` gives you `percent`, `bytesDownloaded`, `totalBytes`, `speedBps`, and `etaSeconds` — not just a plain number
34
+ - **Zip & Unzip** — compress files/directories and extract ZIP archives natively with **zero third-party dependencies** (`java.util.zip` on Android, system `zlib` on iOS)
35
+ - **Download with progress** — clean `0 → 100` progress natively, no UI freezing
36
+ - **Background downloads** — survive app suspension (iOS background URLSession + Android DownloadManager)
37
+ - **Download Queue** — built-in concurrency-limited queue with `maxConcurrent` control and `high`/`normal` priority
38
+ - **Pause & Resume** — resume mid-download using HTTP Range requests
39
+ - **Auto-Retry** — automatic retry on network errors with exponential backoff
40
+ - **Cancel** — cancel any active download, partial files are cleaned up automatically
41
+ - **Re-attach** — reconnect to background downloads after app restart
42
+ - **Custom Headers** — support for Authorization tokens and custom metadata
43
+ - **Custom Destinations** — save to `downloads`, `cache`, or `documents` folders
44
+ - **Multipart Upload** — simple, native file uploading
45
+ - **Checksum Validation** — verify file integrity (MD5, SHA1, SHA256) after download
46
+ - **Base64 & Data URI Support** — convert base64 strings and data URIs to files natively
47
+ - **URL to Base64** — convert remote URLs (images, videos, gifs) to base64 strings
48
+ - **Share Files** — share files with other apps using native share dialog
49
+ - **Open Files** — open files with default apps or app chooser
50
+ - **Filesystem API (`fs`)** — `exists`, `stat`, `readFile`, `writeFile`, `copyFile`, `moveFile`, `mkdir`, `ls`, `deleteFile`
51
+ - **Expo Support** — includes a config plugin for zero-config integration
52
+ - **TurboModules** — built on the React Native New Architecture
53
+ - **File management** — list, delete individual files, or clear all downloads
54
+
55
+ ---
56
+
57
+ ## Installation
58
+
59
+ ```sh
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
+ ```
102
+
103
+ > **Retry behaviour:**
104
+ >
105
+ > - Only retries on **network errors** (timeouts, connection drops, socket errors).
106
+ > - Server errors (`4xx`/`5xx`) and checksum mismatches are **not** retried.
107
+ > - Delay doubles each attempt (exponential backoff), capped at 30 seconds.
108
+ > - Works on both iOS and Android for foreground downloads.
109
+
110
+ ---
111
+
112
+ ### `setQueueOptions(options)` · `getQueueStatus()` · Queue-aware `download()`
113
+
114
+ Avoid crashing your app (or saturating the network) when kicking off many simultaneous downloads. The built-in queue lets you cap concurrency and prioritise individual items — all in pure JavaScript, with zero native changes required.
115
+
116
+ ```javascript
117
+ import { download, setQueueOptions, getQueueStatus } from 'rn-file-toolkit';
118
+
119
+ // 1. Configure the global queue (call once, e.g. at app startup)
120
+ setQueueOptions({ maxConcurrent: 3 }); // default is 3
121
+
122
+ // 2. Enqueue downloads — at most 3 will run at the same time
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
+ );
132
+
133
+ const results = await Promise.all(promises);
134
+
135
+ // High-priority item jumps ahead of all 'normal' pending items
136
+ download({
137
+ url: 'https://example.com/urgent.pdf',
138
+ queue: true,
139
+ priority: 'high',
140
+ });
141
+
142
+ // 3. Inspect queue state at any time
143
+ const { active, pending, maxConcurrent } = getQueueStatus();
144
+ console.log(`Running: ${active} Waiting: ${pending} Limit: ${maxConcurrent}`);
145
+ ```
146
+
147
+ > **Queue behaviour:**
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.
155
+
156
+ ---
157
+
158
+ ### `useDownload()` hook
159
+
160
+ The easiest way to manage a download inside a React component. Get status, rich progress (with speed & ETA), and full controls — all with zero boilerplate.
161
+
162
+ ```tsx
163
+ import { useDownload } from 'rn-file-toolkit';
164
+
165
+ function DownloadScreen() {
166
+ const { start, pause, resume, cancel, status, progress, result } =
167
+ useDownload();
168
+
169
+ return (
170
+ <View>
171
+ <Button
172
+ title="Download"
173
+ onPress={() =>
174
+ start({
175
+ url: 'https://example.com/video.mp4',
176
+ destination: 'documents',
177
+ })
178
+ }
179
+ />
180
+
181
+ {status === 'downloading' && progress && (
182
+ <View>
183
+ <Text>{progress.percent.toFixed(1)}%</Text>
184
+ <Text>Speed: {(progress.speedBps / 1024).toFixed(1)} KB/s</Text>
185
+ <Text>ETA: {progress.etaSeconds.toFixed(0)}s</Text>
186
+ <Text>
187
+ {(progress.bytesDownloaded / 1024 / 1024).toFixed(1)} MB
188
+ {' / '}
189
+ {(progress.totalBytes / 1024 / 1024).toFixed(1)} MB
190
+ </Text>
191
+ <Button title="Pause" onPress={pause} />
192
+ <Button title="Cancel" onPress={cancel} />
193
+ </View>
194
+ )}
195
+
196
+ {status === 'paused' && <Button title="Resume" onPress={resume} />}
197
+
198
+ {status === 'done' && result?.success && (
199
+ <Text>✅ Saved to: {result.filePath}</Text>
200
+ )}
201
+
202
+ {status === 'error' && <Text>❌ {result?.error}</Text>}
203
+ </View>
204
+ );
205
+ }
206
+ ```
207
+
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
+ ---
220
+
221
+ ### `upload(options)`
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
+ ```
241
+
242
+ ---
243
+
244
+ ### `saveBase64AsFile(options)`
245
+
246
+ Save a base64 string or data URI as a file. Perfect for handling base64 images, documents, or any binary data.
247
+
248
+ ```javascript
249
+ import { saveBase64AsFile } from 'rn-file-toolkit';
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',
255
+ destination: 'documents', // 'downloads' | 'cache' | 'documents'
256
+ });
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
+ ```
269
+
270
+ ---
271
+
272
+ ### `urlToBase64(options)`
273
+
274
+ Convert a web URL (image, video, gif, etc.) to base64 string. Perfect for converting remote media to base64 for local processing.
275
+
276
+ ```javascript
277
+ import { urlToBase64 } from 'rn-file-toolkit';
278
+
279
+ const result = await urlToBase64({
280
+ url: 'https://example.com/photo.jpg',
281
+ headers: { Authorization: 'Bearer <token>' }, // optional
282
+ });
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
+ ```
293
+
294
+ ---
295
+
296
+ ### `shareFile(options)`
297
+
298
+ Share a file with other apps using the native share dialog.
299
+
300
+ ```javascript
301
+ import { shareFile } from 'rn-file-toolkit';
302
+
303
+ const result = await shareFile({
304
+ filePath: '/path/to/document.pdf',
305
+ title: 'Share Document', // Android only
306
+ subject: 'Check this out', // Android only
307
+ });
308
+
309
+ if (result.success) {
310
+ console.log('File shared successfully');
311
+ }
312
+ ```
313
+
314
+ ---
315
+
316
+ ### `openFile(options)`
317
+
318
+ Open a file with the default app or app chooser.
319
+
320
+ ```javascript
321
+ import { openFile } from 'rn-file-toolkit';
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
+ }
331
+ ```
332
+
333
+ ---
334
+
335
+ ### `unzip(sourcePath, destDir)` · `zip(sourcePath, destPath)`
336
+
337
+ Compress and extract ZIP archives natively — **no third-party library required**.
338
+
339
+ - **Android** uses `java.util.zip` (built into the Android SDK, every API level).
340
+ - **iOS** uses `zlib` (system framework, linked via `s.libraries = 'z'` in the podspec — ships on every iPhone/iPad).
341
+
342
+ ```javascript
343
+ import { download, unzip, zip } from 'rn-file-toolkit';
344
+
345
+ // ── Unzip a downloaded archive ──────────────────────────────────────────────
346
+ const dl = await download({
347
+ url: 'https://example.com/assets.zip',
348
+ destination: 'cache',
349
+ });
350
+
351
+ if (dl.success) {
352
+ const result = await unzip(
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
+ );
371
+
372
+ if (zipResult.success) {
373
+ console.log('Archive created at:', zipResult.zipPath);
374
+ }
375
+
376
+ // ── Zip an entire directory ─────────────────────────────────────────────────
377
+ const dirResult = await zip(
378
+ '/path/to/my-folder', // source directory
379
+ '/path/to/my-folder.zip' // output archive path
380
+ );
381
+ ```
382
+
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
+ ---
392
+
393
+ ### Pause / Resume / Cancel
394
+
395
+ ```javascript
396
+ import { pauseDownload, resumeDownload, cancelDownload } from 'rn-file-toolkit';
397
+
398
+ await pauseDownload(downloadId);
399
+ await resumeDownload(downloadId);
400
+ await cancelDownload(downloadId);
401
+ ```
402
+
403
+ ---
404
+
405
+ ### Cache Management
406
+
407
+ ```javascript
408
+ import { getCachedFiles, deleteFile, clearCache } from 'rn-file-toolkit';
409
+
410
+ // List all files in the cache/documents folders
411
+ const { files } = await getCachedFiles();
412
+
413
+ // Delete a specific file
414
+ await deleteFile('/path/to/file.pdf');
415
+
416
+ // Clear all managed files
417
+ await clearCache();
418
+ ```
419
+
420
+ ---
421
+
422
+ ### `fs` (filesystem namespace)
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
+ ---
514
+
515
+ ## Links
516
+
517
+ - [GitHub](https://github.com/chavan-labs/rn-file-toolkit)
518
+ - [npm](https://www.npmjs.com/package/rn-file-toolkit)
519
+
520
+ ---
521
+
522
+ _Made natively for the community 🤝 by Rohit Chavan_
@@ -0,0 +1,61 @@
1
+ def FileToolkitConfig = [
2
+ kotlinVersion: "2.0.21",
3
+ minSdkVersion: 24,
4
+ compileSdkVersion: 35,
5
+ targetSdkVersion: 35
6
+ ]
7
+
8
+ def getExtOrDefault(prop) {
9
+ return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : FileToolkitConfig[prop]
10
+ }
11
+
12
+ buildscript {
13
+ repositories {
14
+ google()
15
+ mavenCentral()
16
+ }
17
+
18
+ dependencies {
19
+ classpath "com.android.tools.build:gradle:8.7.2"
20
+ // noinspection DifferentKotlinGradleVersion
21
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21"
22
+ }
23
+ }
24
+
25
+ apply plugin: "com.android.library"
26
+ apply plugin: "kotlin-android"
27
+ apply plugin: "com.facebook.react"
28
+
29
+ android {
30
+ namespace "com.filetoolkit"
31
+
32
+ compileSdk getExtOrDefault("compileSdkVersion")
33
+
34
+ defaultConfig {
35
+ minSdk getExtOrDefault("minSdkVersion")
36
+ targetSdk getExtOrDefault("targetSdkVersion")
37
+ }
38
+
39
+ buildFeatures {
40
+ buildConfig true
41
+ }
42
+
43
+ buildTypes {
44
+ release {
45
+ minifyEnabled false
46
+ }
47
+ }
48
+
49
+ lint {
50
+ disable "GradleCompatible"
51
+ }
52
+
53
+ compileOptions {
54
+ sourceCompatibility JavaVersion.VERSION_1_8
55
+ targetCompatibility JavaVersion.VERSION_1_8
56
+ }
57
+ }
58
+
59
+ dependencies {
60
+ implementation "com.facebook.react:react-android"
61
+ }
@@ -0,0 +1,13 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <application>
3
+ <provider
4
+ android:name="androidx.core.content.FileProvider"
5
+ android:authorities="${applicationId}.fileprovider"
6
+ android:exported="false"
7
+ android:grantUriPermissions="true">
8
+ <meta-data
9
+ android:name="android.support.FILE_PROVIDER_PATHS"
10
+ android:resource="@xml/file_provider_paths" />
11
+ </provider>
12
+ </application>
13
+ </manifest>