Skip to content

4.x Usage

Alex Gotev edited this page Jun 4, 2021 · 19 revisions

Contents

Foreword

All the upload requests are non blocking. They trigger a background upload service, so you can fire requests directly from your fragments, activities or services without concerns.

All the examples are in Kotlin, but the library is 100% interoperable with Java, so you can have the same functionality (with a slightly different syntax) even if you have 100% Java codebase, without worries.

If you know Java and want to learn Kotlin, this will get you up to speed: https://developer.android.com/kotlin/learn-kotlin-java-pathway

What is the Upload ID?

When you create an upload request and call startUpload(), you will get a unique string which identifies the upload task. Using that string you can monitor the upload or stop it using Management APIs.

If you need it, you can generate an upload ID yourself and set it in the upload request by calling .setUploadID("yourID") before startUpload(). When doing that, be careful to always generate unique strings to avoid problems.

HTTP multipart/form-data upload (RFC2388)

When in trouble, follow the troubleshooting procedure

This is the most common way to upload files on a server. It's the same kind of request that browsers do when you use the <form> tag with one or more files. Here's a minimal example:

MultipartUploadRequest(context, serverUrl = "https://my.server.com")
    .setMethod("POST")
    .addFileToUpload(
        filePath = filePath,
        parameterName = "myFile"
    ).startUpload()

Check the other methods available in MultipartUploadRequest class and their docs. You can also add multiple headers, files and parameters. To monitor upload progress and status, check: https://github.com/gotev/android-upload-service/wiki/Monitor-Uploads

By default, the global notification configuration and retry policy will be applied. You can override both in each request using setNotificationConfig and setMaxRetries methods.

feature description
multiple files in a single request yes. There are many ways to do it. Example.
support for HTTP Basic and Bearer Auth yes. Add .setBasicAuth("username", "password") or .setBearerAuth("bearer-token") when you build the request
add custom request headers yes. You can also set them with request interceptors if you are using OkHttp stack.
add custom request parameters yes
default charset UTF-8. Non latin characters are supported out of the box.
resuming uploads no. If an upload fails at some point, the temporary data will be discarded automatically by your server and the upload will start from the beginning on the next request. The server sees a multipart request as a single stream of data, as per RFC specs. There's no way to resume a multipart upload. You have to start over.

HTTP binary upload

When in trouble, follow the troubleshooting procedure

The binary upload uses a single file as the raw body of the upload request. Here's a minimal example:

BinaryUploadRequest(context, serverUrl = "https://my.server.com")
    .setMethod("POST")
    .setFileToUpload(filePath)
    .startUpload()

Check the other methods available in BinaryUploadRequest class and their docs. You can also add multiple headers. To monitor upload progress and status, check: https://github.com/gotev/android-upload-service/wiki/Monitor-Uploads

By default, the global notification configuration and retry policy will be applied. You can override both in each request using setNotificationConfig and setMaxRetries methods.

feature description
multiple files in a single request no. Only one file per request, which will be in the request body. It is more bandwidth efficient than HTTP/Multipart if all you need is to upload only one file to a server, without passing additional data in the request. If you want to pass the original file name to your server using this kind of request, the only way you can do it is by setting a custom header. Bear in mind that HTTP headers are encoded in US-ASCII, so don't use non-latin values.
support for HTTP Basic and Bearer Auth yes. Add .setBasicAuth("username", "password") or .setBearerAuth("bearer-token") when you build the request
add custom request headers yes. You can also set them with request interceptors if you are using OkHttp stack.
add custom request parameters no, the request body consists only of the selected file to upload. There's no room for parameters like multipart requests. Calling addParameter and addArrayParameter methods will have no effect and you'll see a log message.
default charset US-ASCII. UTF-8 is not supported because you can only set request headers, which must be in US-ASCII encoding
resuming uploads no. If an upload fails at some point, the temporary data will be discarded automatically by your server and the upload will start from the beginning on the next request. The server sees the request as a single stream of data. There's no way to resume a binary upload. You have to start over.

Persistent upload requests

Starting from version 4.5.0 it's possible to serialize and deserialize upload requests, to be able to save them persistently and run them later.

All the Upload Requests (Multipart, binary, FTP and also custom ones) have the method .toPersistableData() which creates a PersistableData object containing all the necessary data to recreate the upload request later. PersistableData is Parcelable and can also be converted to a standard android Bundle or a JSON string. The JSON string version is not meant to be human readable, but a convenient way to pass complex structured data using a string.

To recreate a request from serialized data:

val request = CreateUploadRequest.fromPersistableData(context, persistableData)
val requestFromJson = CreateUploadRequest.fromJson(context, jsonString)
val requestFromParcel = CreateUploadRequest.fromParcel(context, parcel)

UploadNotificationConfig is not included in the serialized form because it's not serializable, as it may contain PendingIntents used for notification actions and Bitmap icons. When you recreate the request using CreateUploadRequest, UploadServiceConfig.notificationConfigFactory is used automatically to get an UploadNotificationConfig, which you can override before starting the upload using the setNotificationConfig method.

Examples

MultipartUploadRequest to PersistableData and back

val multipartUploadData = MultipartUploadRequest(context, "https://my.server.com")
    .addFileToUpload(
        filePath = "/path/to/file",
        parameterName = "file",
        fileName = "testing",
        contentType = "application/octet-stream"
    ).toPersistableData()

CreateUploadRequest.fromPersistableData(context, multipartUploadData).startUpload()

BinaryUploadRequest to JSON and back

val jsonData = BinaryUploadRequest(context, "https://my.server.com")
    .setFileToUpload("/path/to/file")
    .addHeader(
        headerName = "headerName",
        headerValue = "headerValue"
    ).toPersistableData().toJson()

CreateUploadRequest.fromJson(context, jsonData).startUpload()

BinaryUploadRequest to Parcel and back

val parcel = Parcel.obtain()
BinaryUploadRequest(context, "https://my.server.com")
    .setFileToUpload("/path/to/file")
    .addHeader(
        headerName = "headerName",
        headerValue = "headerValue"
    ).toPersistableData().writeToParcel(parcel, 0)
parcel.setDataPosition(0)

CreateUploadRequest.fromParcel(context, parcel).startUpload()

FTPUploadRequest to PersistableData and back

val ftpData = FTPUploadRequest(context, "https:://my.server.url", 1234)
    .addFileToUpload(
        filePath = "/path/to/file",
        remotePath = "/remote/path",
        permissions = UnixPermissions("644")
    )
    .setConnectTimeout(2000)
    .setSocketTimeout(10000)
    .setCreatedDirectoriesPermissions(UnixPermissions("777"))
    .useSSL(true)
    .setSecureSocketProtocol("TLS")
    .setUsernameAndPassword(username = "user", password = "pass")
    .setSecurityModeImplicit(true)
    .useCompressedFileTransferMode(true)
    .setMaxRetries(2)
    .toPersistableData()

CreateUploadRequest.fromPersistableData(context, ftpData).startUpload()

Management APIs. Programmatically get running uploads and stop them.

You can call the following methods from anywhere you want in your code.

Method Description
UploadService.taskList Gets all the currently active upload tasks
UploadService.stopAllUploads() Stops all the active upload tasks. Listening RequestObserver's onError method will be fired with UserCancelledUploadException for each upload you are monitoring.
UploadService.stopUpload(uploadId) Stops a specific upload task. Listening RequestObserver's onError method will be fired with UserCancelledUploadException
UploadService.stop(context) Stops UploadService if no tasks are currently running. It returns a boolean which indicates if the service is shutting down.
UploadService.stop(context, forceStop = true) Force stops UploadService aborting any currently running tasks. It calls stopAllUploads() and returns a boolean which indicates if the service is shutting down.

Multiple Uploads

In some cases you want to upload several files to your server at once. You have the following options:

  • Add many files to a single upload request (supported in Multipart and FTP Upload Request)
  • Create an upload request for each file

We assume this is the list of files to upload:

val files = listOf(
  "/path/to/my/files/file1.png",
  "/path/to/my/files/file2.png",
  "/path/to/my/files/file3.png"
)

Multiple uploads with a single file for each upload

In this case you may want to tune the number of parallel uploads: https://github.com/gotev/android-upload-service/wiki/Configuration#number-of-parallel-uploads

Multipart

files.forEach { file ->
    MultipartUploadRequest(context, serverUrl = "https://my.server.com")
        .addFileToUpload(file, parameterName = "file")
        .startUpload()
}

Binary

files.forEach { file ->
    BinaryUploadRequest(context, serverUrl = "https://my.server.com")
        .setFileToUpload(file)
        .startUpload()
}

Multiple files in a single Multipart Upload

MultipartUploadRequest(context, serverUrl = "https://my.server.com").apply {
    files.forEach { file ->
        addFileToUpload(file, parameterName = "files[]")
    }
}.startUpload()

in this case the parameterName used is files[] because it's a common standard which indicates an array of files with the same parameter name. For example, PHP has an out of the box support for this kind of uploads. This may vary based on the server-side technology you're using. Use what's appropriate for you. Listing all the available standards is beyond the scope of this library and this example.