Skip to content

Android feature: multiple files upload in one shot via multipart, issue #240 #266

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.||
Expand Down Expand Up @@ -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)?

Expand Down
33 changes: 30 additions & 3 deletions android/src/main/java/com/vydia/RNUploader/UploaderModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> = 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
Expand All @@ -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."))
Expand Down Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down