Uploading Files to AWS S3 with Progress - Kotlin
In this post we’ll use Kotlin Coroutines and Retrofit2 to upload files to S3 Bucket on Android. In our case, we get S3 url from our backend server. So this post will be more about the file uploading part.
First, create a function to choose file :
We used registerForFiles.launch(this)
to get the result of this intent. So now we need to create an ActivityResultLauncher named registerForFiles
:
In the above codes, we got the URI
of selected file. We’ll use this URI to create a RequestBody
. Why we need to create a RequestBody? Well! Normally files can be uploaded to server as MultipartBody.Part
on Android but using MultiPartBody can cause problems as mentioned here.
We will create our own RequestBody
because later we’ll add some code to this class to show the progress of the uploading status. Let’s create a RequestBody:
With that class we can get the media type and content length of the file from the file URI. writeTo()
function opens an inputStream
to the file and it’s used to transmit the file. We’re also using ContentResolver
to access and operate on files.
Now we can create a Retrofit function to upload this RequestBody as a file:
That’s it! Now we can call this function in a Fragment and upload files.
Note: In our case that contentType
was handling from backend. So I didn’t need to send it to server but it might be required in your case. If it’s, you can get contentType
from the file URI.
Now we’re able to send the files to Amazon S3 Bucket. It’s done!!!
If you want you can also add a progressBar
to observe uploading status of the file according to uploaded bytes of the file. To do this we need to make some changes in our FileRequestBody
class. So let’s do this!
First edit FileRequestBody
class like this:
We added a higher-order function as parameter to observe uploading status of the files. writtenBytes
represents the uploaded bytes to server and contentLength
represents the total file size. Due to writeTo()
function runs multiple times we can get proper writtenBytes
values.
Transmitting the request body is performed by writing it to a Sink
, we will wrap the default sink with our own one that counts the bytes that are transmitted and reports them back via a progress callback. We can wrap the default sink into our new CountingSink
and write to a buffered version of that, in order to both transmit the file and observe its progress.
We are able to get written bytes of the file. Now all we have to do is update a progressBar
according to this writtenBytes in UI:
Set android:max="100"
attr of progressBar in XML. So the progressBar will be updated according to uploading status.
Thanks for reading! :)