diff --git a/README.md b/README.md index 1c2cf558..bc25d6fc 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,25 @@ const options = { Note the `field` property is required for multipart uploads. +## Android only, multiple files upload in one shot via Multipart + +Send all the files in `files` param. In this case `path`, `field` & `type` will be ignored. Example: + +``` +const options = { + url: 'https://myservice.com/path/to/post', + files: [ + { + path: 'file://path/to/file%20on%20device.png', + field: 'uploaded_media' + } + ], + method: 'POST' +} +``` + +Note that `type` will always be multipart when `files` is passed + # API ## Top Level Functions @@ -160,6 +179,7 @@ Returns a promise with the string ID of the upload. Will reject if there is a c |---|---|---|---|---|---| |`url`|string|Required||URL to upload to|`https://myservice.com/path/to/post`| |`path`|string|Required||File path on device|`file://something/coming/from%20the%20device.png`| +|`files`|array|Optional||Android only, to upload multiple files in one request|`[{path: 'file://path/to/file%20on%20device.png', field: 'uploaded_media'}, {path: '', field: ''}]` |`type`|'raw' or 'multipart'|Optional|`raw`|Primary upload type.|| |`method`|string|Optional|`POST`|HTTP method|| |`customUploadId`|string|Optional||`startUpload` returns a Promise that includes the upload ID, which can be used for future status checks. By default, the upload ID is automatically generated. This parameter allows a custom ID to use instead of the default.|| @@ -304,7 +324,9 @@ Does it support iOS camera roll assets? Does it support multiple file uploads? -> Yes and No. It supports multiple concurrent uploads, but only a single upload per request. That should be fine for 90%+ of cases. +> Android: Yes, both multiple concurrent uploads as well as multiple files in one request are supported. + +> ios: Yes and No. It supports multiple concurrent uploads, but only a single upload per request. That should be fine for 90%+ of cases. Why should I use this file uploader instead of others that I've Googled like [react-native-uploader](https://github.com/aroth/react-native-uploader)? diff --git a/android/src/main/java/com/vydia/RNUploader/UploaderModule.kt b/android/src/main/java/com/vydia/RNUploader/UploaderModule.kt index 0258e95c..c10ca42a 100644 --- a/android/src/main/java/com/vydia/RNUploader/UploaderModule.kt +++ b/android/src/main/java/com/vydia/RNUploader/UploaderModule.kt @@ -126,7 +126,24 @@ class UploaderModule(val reactContext: ReactApplicationContext) : ReactContextBa */ @ReactMethod fun startUpload(options: ReadableMap, promise: Promise) { - for (key in arrayOf("url", "path")) { + val mandatoryParamsList: MutableList = mutableListOf("url") + if (options.hasKey("files")) { + if (options.getType("files") != ReadableType.Array) { + promise.reject(java.lang.IllegalArgumentException("files must be an array.")) + return + } + val files = options.getArray("files") + for (i in 0 until files!!.size()) { + val file = files.getMap(i) + if (!file.hasKey("path")) { + promise.reject(java.lang.IllegalArgumentException("Missing path field in files")) + return + } + } + } else { + mandatoryParamsList.add("path") + } + for (key in mandatoryParamsList) { if (!options.hasKey(key)) { promise.reject(java.lang.IllegalArgumentException("Missing '$key' field.")) return @@ -146,7 +163,10 @@ class UploaderModule(val reactContext: ReactApplicationContext) : ReactContextBa } configureUploadServiceHTTPStack(options, promise) var requestType: String? = "raw" - if (options.hasKey("type")) { + val files = options.getArray("files") + if (files != null) { + requestType = "multipart"; + } else if (options.hasKey("type")) { requestType = options.getString("type") if (requestType == null) { promise.reject(java.lang.IllegalArgumentException("type must be string.")) @@ -186,7 +206,14 @@ class UploaderModule(val reactContext: ReactApplicationContext) : ReactContextBa val maxRetries = if (options.hasKey("maxRetries") && options.getType("maxRetries") == ReadableType.Number) options.getInt("maxRetries") else 2 val customUploadId = if (options.hasKey("customUploadId") && options.getType("method") == ReadableType.String) options.getString("customUploadId") else null try { - val request = if (requestType == "raw") { + val request = if (files != null) { + var request = MultipartUploadRequest(this.reactApplicationContext, url!!) + for (i in 0 until files.size()) { + val file = files.getMap(i) + request = request.addFileToUpload(file.getString("path")!!, file.getString("field") ?: "file${i}") + } + request + } else if (requestType == "raw") { BinaryUploadRequest(this.reactApplicationContext, url!!) .setFileToUpload(filePath!!) } else { diff --git a/index.d.ts b/index.d.ts index 8b2a07ce..2a8c8601 100644 --- a/index.d.ts +++ b/index.d.ts @@ -81,6 +81,15 @@ declare module "react-native-background-upload" { export interface UploadOptions { url: string; path: string; + /** + * Android only, to upload multiple files in one request via multipart + * `path` & `field` will be ignored and `type` will be multipart if `files` is available + */ + files?: { + path: string; + // Fallback to file0, file1, file2 etc + field?: string; + }; type?: 'raw' | 'multipart'; method?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE'; customUploadId?: string;