Upload SDK for Android
Let users upload large media files directly to FastPix from a native android app.
Step 1
Step 1: Install the SDK
Step 2
Create an upload URL
Step 3
Start your upload
Step 4
Monitor upload events
Step 5
Manage video uplaods
Step 6
Usage example
The FastPix Android Resumable Uploads SDK helps you efficiently upload large files from the browser by splitting them into chunks and also gives you the ability to pause and resume your uploads.
How resumable uploads work through chunking
Resumable uploads can be effectively handled through a technique called chunking. This method involves breaking down large files into smaller, more manageable pieces, or "chunks." Here's how chunking works:
- Divide the file: Large files are split into smaller, manageable chunks (e.g., 16 MB by default).
- Upload individually: Each chunk is uploaded separately. If a chunk fails, only that specific chunk needs to be re-uploaded.
- Resume capability: If the upload is interrupted, you can resume from the last successfully uploaded chunk instead of starting over.
This approach is important because:
- It reduces the risk: Uploading smaller chunks minimizes the risk of failure. If a chunk fails to upload due to network issues, only that specific chunk needs to be re-uploaded, not the entire file.
- Improves performance: Smaller chunks can be uploaded more quickly and efficiently, especially on slower connections, as they require less time to transfer.
- Easier management: Chunking allows for better tracking of upload progress, making it easier to implement features like pause and resume.
Step 1: Install the Android SDK
Add our repository to your Gradle project
maven(url ="https://maven.pkg.github.com/FastPix/android-uploads-sdk") {
credentials {
username = "your_gihub_username"
password = "your_github_personal_token"
}
}
maven {
url "https://maven.pkg.github.com/FastPix/android-uploads-sdk"
credentials {
username = "your_gihub_username"
password = "your_github_personal_token"
}
}
Add the dependency to your app
Add Fastpix’s library to the dependencies block of your app in module level build.gradle file.
dependencies {
implementation("io.fastpix:uploads:1.0.0")
}
dependencies {
implementation 'io.fastpix:uploads:1.0.0'
}
Step 2: Create an upload URL
In order to upload a video, you will need a signed upload URL.
To get this signed URL, you’ll need a valid Access Token and Secret Key. See the Authentication Guide for details on retrieving these credentials.
After obtaining your credentials, the next step is to generate a signed URL by calling the Upload Media from Device API. Once you have the signed URL, you’re all set to move forward with integrating the SDK into your app.
The example below demonstrates how to retrieve a signed URL using the Upload Media from Device API. You can either use this example directly or refer to our guide on uploading videos directly for more details.
private fun getSignedUrl() {
val client = OkHttpClient()
val mediaType = "application/json; charset=utf-8".toMediaType()
// Construct JSON body using JSONObject
val requestBodyJson = JSONObject().apply {
put("corsOrigin", "*")
put("pushMediaSettings", JSONObject().apply {
put("metadata", JSONObject().apply {
put("key1", "value1")
})
put("accessPolicy", "public")
put("maxResolution", "1080p")
})
}
val requestBody = requestBodyJson.toString().toRequestBody(mediaType)
// Create Authorization header
val credentials = "$tokenId:$secretKey"
val auth = "Basic " + Base64.encodeToString(credentials.toByteArray(), Base64.NO_WRAP)
// Build the HTTP request
val request = Request.Builder()
.url("https://v1.fastpix.io/on-demand/uploads")
.addHeader("Authorization", auth)
.addHeader("Content-Type", "application/json")
.post(requestBody)
.build()
// Execute request
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
LOGGER.log(Level.SEVERE, e.message)
}
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
response.body?.string()?.let {
val jsonObject = JSONObject(it)
val jsonData = jsonObject.getJSONObject("data")
val signedUrl = jsonData.getString("url")
// TODO: use signedUrl and uploadId as needed
}
} else {
LOGGER.log(Level.SEVERE, "Upload URL request failed: ${response.code}")
}
}
})
}
private void getSignedUrl() {
OkHttpClient client = new OkHttpClient();
// Construct JSON body using JSONObject
JSONObject metadata = new JSONObject();
JSONObject pushMediaSettings = new JSONObject();
JSONObject requestBodyJson = new JSONObject();
try {
metadata.put("key1", "value1");
pushMediaSettings.put("metadata", metadata);
pushMediaSettings.put("accessPolicy", "public");
pushMediaSettings.put("maxResolution", "1080p");
requestBodyJson.put("corsOrigin", "*");
requestBodyJson.put("pushMediaSettings", pushMediaSettings);
} catch (JSONException e) {
e.printStackTrace();
return;
}
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
RequestBody requestBody = RequestBody.create(requestBodyJson.toString(), mediaType);
// Create Authorization header
String credentials = tokenId + ":" + secretKey;
String auth = "Basic " + Base64.encodeToString(credentials.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP);
// Build the request
Request request = new Request.Builder()
.url("https://v1.fastpix.io/on-demand/uploads")
.addHeader("Authorization", auth)
.addHeader("Content-Type", "application/json")
.post(requestBody)
.build();
// Execute the request
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.e("UPLOAD", "Failed to get signed URL", e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
String responseBody = response.body() != null ? response.body().string() : null;
if (responseBody != null) {
try {
JSONObject jsonObject = new JSONObject(responseBody);
JSONObject jsonData = jsonObject.getJSONObject("data");
String signedUrl = jsonData.getString("url");
String uploadId = jsonData.getString("uploadId");
// TODO: use signedUrl and uploadId as needed
} catch (JSONException e) {
Log.e("UPLOAD", "Failed to parse response", e);
}
}
} else {
Log.e("UPLOAD", "Upload URL request failed: " + response.code());
}
}
});
}
PLEASE NOTE
When making Basic Auth API calls, securely retrieve the username and password from environment variables (.env) or a protected server endpoint to prevent unauthorized access.
In the API response, you will get a signed URL upon successful API request. Next step is to take the signed URL and pass it to the SDK.
Step 3: Start your upload
To perform the upload from your Android app, you can use the FastPixUploadSdk
class. At the simplest, you need to build your FastPixUploadSdk
via its Builder, then add your listeners and start()
the upload.
val sdk = FastPixUploadSdk.Builder(this)
.setFile(file)
.setSignedUrl(signedUrl)
.setChunkSize(chunkSize * 1024 * 1024)
.build()
sdk.startUpload()
FastPixUploadSdk sdk = new FastPixUploadSdk.Builder(this)
.setFile(file)
.setSignedUrl(signedUrl)
.setChunkSize(chunkSize * 1024 * 1024)
.build();
sdk.startUpload();
Parameters to use:
This SDK supports the following parameters
Parameter | Required? | Description |
---|---|---|
setSignedUrl | Yes | The URL endpoint where the file will be uploaded. |
setFile | Yes | The file object that you want to upload (e.g., a video file). |
setChunkSize | No | Defines the chunk size in bytes. By default, the SDK splits files into 16 MB chunks. You can customize this (minimum of 5 MB). |
callback | No | Lets you handle the upload lifecycle events such as progress, completion, and errors. |
setMaxRetries | No | Sets the number of retry attempts for failed chunk uploads. Defaults to 5. |
setRetryDelay | No | Sets the wait time (in milliseconds) before retrying a failed chunk upload. Defaults to 2000ms. |
Monitor the upload progress through lifecycle events
Using the following lifecycle events lets you to build a robust and user-friendly upload experience. By tracking progress in real-time, handling errors proactively, managing chunk retries, and responding to network changes, you can ensure seamless and efficient uploads.
Integrating these event handlers into your application can enhance reliability, optimize performance, and provide users with clear, actionable feedback throughout the upload process.
class MyUploadCallback : FastPixUploadCallbacks {
override fun onProgressUpdate(progress: Double) {
// Called periodically to report upload progress (0.0 - 100.0)
// Example: update a progress bar
}
override fun onSuccess(timiMillis: Long) {
// Called when the upload completes successfully
// timiMillis indicates how long the upload took
}
override fun onError(error: String, timiMillis: Long) {
// Called when an error occurs during upload
// error provides the error message
// timiMillis indicates how long the upload lasted before failing
}
override fun onNetworkStateChange(isOnline: Boolean) {
// Called when the network connectivity changes
// isOnline indicates whether the device is currently online or offline
}
override fun onUploadInit() {
// Called when the upload process is initialized
// Use this to show an initial loading state or setup UI
}
override fun onAbort() {
// Called when the upload is manually aborted
// Use this to clean up UI or notify the user
}
override fun onChunkHandled(
totalChunks: Int,
filSizeInBytes: Long,
currentChunk: Int,
currentChunkSizeInBytes: Long
) {
// Called after a chunk is successfully uploaded
// totalChunks: total number of chunks to upload
// filSizeInBytes: total file size
// currentChunk: index of the currently uploaded chunk
// currentChunkSizeInBytes: size of the uploaded chunk
}
override fun onChunkUploadingFailed(
failedChunkRetries: Int,
chunkCount: Int,
chunkSize: Long
) {
// Called when a chunk fails to upload after retry attempts
// failedChunkRetries: number of retries attempted for the chunk
// chunkCount: index of the failed chunk
// chunkSize: size of the failed chunk
}
override fun onPauseUploading() {
// Called when the upload is paused
// Use this to reflect paused state in UI
}
override fun onResumeUploading() {
// Called when the upload resumes after being paused
// Use this to resume UI indicators or timers
}
}
public class MyUploadCallback implements FastPixUploadCallbacks {
@Override
public void onProgressUpdate(double progress) {
// Called periodically to report upload progress (0.0 - 100.0)
// Example: update a progress bar
}
@Override
public void onSuccess(long timiMillis) {
// Called when the upload completes successfully
// timiMillis indicates how long the upload took
}
@Override
public void onError(String error, long timiMillis) {
// Called when an error occurs during upload
// error provides the error message
// timiMillis indicates how long the upload lasted before failing
}
@Override
public void onNetworkStateChange(boolean isOnline) {
// Called when the network connectivity changes
// isOnline indicates whether the device is currently online or offline
}
@Override
public void onUploadInit() {
// Called when the upload process is initialized
// Use this to show an initial loading state or setup UI
}
@Override
public void onAbort() {
// Called when the upload is manually aborted
// Use this to clean up UI or notify the user
}
@Override
public void onChunkHandled(int totalChunks, long filSizeInBytes, int currentChunk, long currentChunkSizeInBytes) {
// Called after a chunk is successfully uploaded
// totalChunks: total number of chunks to upload
// filSizeInBytes: total file size
// currentChunk: index of the currently uploaded chunk
// currentChunkSizeInBytes: size of the uploaded chunk
}
@Override
public void onChunkUploadingFailed(int failedChunkRetries, int chunkCount, long chunkSize) {
// Called when a chunk fails to upload after retry attempts
// failedChunkRetries: number of retries attempted for the chunk
// chunkCount: index of the failed chunk
// chunkSize: size of the failed chunk
}
@Override
public void onPauseUploading() {
// Called when the upload is paused
// Use this to reflect paused state in UI
}
@Override
public void onResumeUploading() {
// Called when the upload resumes after being paused
// Use this to resume UI indicators or timers
}
}
Manage video uploads
You can control the upload lifecycle with the following methods:
Pause an upload:
sdk.pauseUploading()
Resume an upload:
sdk.resumeUploading()
Abort an upload:
sdk.abort()
Usage example of Android uploads SDK
The following examples give an overview of integrating the FastPix Android Uploads SDK into your project, enabling you to build a fully customized upload interface. By making use of the SDK's lifecycle events and configurable attributes, you can enhance functionality and optimize the upload experience.
class UploadActivity : AppCompatActivity(), FastPixUploadCallbacks {
private lateinit var sdk: FastPixUploadSdk
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val file = File(filesDir, "your-video.mp4")
val signedUrl = "https://your-signed-upload-url" // Replace with actual signed URL
val chunkSize = 5 // Chunk size in MB
sdk = FastPixUploadSdk.Builder(this)
.setFile(file)
.setSignedUrl(signedUrl)
.setChunkSize(chunkSize * 1024 * 1024) // Convert MB to bytes
.setMaxRetries(3) // Optional: Number of retries for failed chunks
.setRetryDelay(2000) // Optional: Delay between retries in milliseconds
.callback(this) // Set this activity as the callback handler
.build()
sdk.startUpload() // Start the upload
}
// === FastPixUploadCallbacks Implementation ===
override fun onProgressUpdate(progress: Double) {
// Called periodically to report upload progress (0.0 - 100.0)
Log.d("Upload", "Progress: $progress%")
}
override fun onSuccess(timiMillis: Long) {
// Called when the upload completes successfully
Log.d("Upload", "Upload completed in $timiMillis ms")
}
override fun onError(error: String, timiMillis: Long) {
// Called when an error occurs during upload
Log.e("Upload", "Error: $error after $timiMillis ms")
}
override fun onNetworkStateChange(isOnline: Boolean) {
// Called when the network connectivity changes
Log.d("Upload", if (isOnline) "Back online" else "Offline")
}
override fun onUploadInit() {
// Called when the upload process is initialized
Log.d("Upload", "Upload initialized")
}
override fun onAbort() {
// Called when the upload is manually aborted
Log.d("Upload", "Upload aborted by user")
}
override fun onChunkHandled(
totalChunks: Int,
filSizeInBytes: Long,
currentChunk: Int,
currentChunkSizeInBytes: Long
) {
// Called after a chunk is successfully uploaded
Log.d("Upload", "Uploaded chunk $currentChunk/$totalChunks")
}
override fun onChunkUploadingFailed(
failedChunkRetries: Int,
chunkCount: Int,
chunkSize: Long
) {
// Called when a chunk fails after all retry attempts
Log.e("Upload", "Chunk $chunkCount failed after $failedChunkRetries retries")
}
override fun onPauseUploading() {
// Called when the upload is paused
Log.d("Upload", "Upload paused")
}
override fun onResumeUploading() {
// Called when the upload resumes
Log.d("Upload", "Upload resumed")
}
}
class UploadActivity : AppCompatActivity(), FastPixUploadCallbacks {
private lateinit var sdk: FastPixUploadSdk
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val file = File(filesDir, "your-video.mp4")
val signedUrl = "https://your-signed-upload-url" // Replace with actual signed URL
val chunkSize = 5 // Chunk size in MB
sdk = FastPixUploadSdk.Builder(this)
.setFile(file)
.setSignedUrl(signedUrl)
.setChunkSize(chunkSize * 1024 * 1024) // Convert MB to bytes
.setMaxRetries(3) // Optional: Number of retries for failed chunks
.setRetryDelay(2000) // Optional: Delay between retries in milliseconds
.callback(this) // Set this activity as the callback handler
.build()
sdk.startUpload() // Start the upload
}
// === FastPixUploadCallbacks Implementation ===
override fun onProgressUpdate(progress: Double) {
// Called periodically to report upload progress (0.0 - 100.0)
Log.d("Upload", "Progress: $progress%")
}
override fun onSuccess(timiMillis: Long) {
// Called when the upload completes successfully
Log.d("Upload", "Upload completed in $timiMillis ms")
}
override fun onError(error: String, timiMillis: Long) {
// Called when an error occurs during upload
Log.e("Upload", "Error: $error after $timiMillis ms")
}
override fun onNetworkStateChange(isOnline: Boolean) {
// Called when the network connectivity changes
Log.d("Upload", if (isOnline) "Back online" else "Offline")
}
override fun onUploadInit() {
// Called when the upload process is initialized
Log.d("Upload", "Upload initialized")
}
override fun onAbort() {
// Called when the upload is manually aborted
Log.d("Upload", "Upload aborted by user")
}
override fun onChunkHandled(
totalChunks: Int,
filSizeInBytes: Long,
currentChunk: Int,
currentChunkSizeInBytes: Long
) {
// Called after a chunk is successfully uploaded
Log.d("Upload", "Uploaded chunk $currentChunk/$totalChunks")
}
override fun onChunkUploadingFailed(
failedChunkRetries: Int,
chunkCount: Int,
chunkSize: Long
) {
// Called when a chunk fails after all retry attempts
Log.e("Upload", "Chunk $chunkCount failed after $failedChunkRetries retries")
}
override fun onPauseUploading() {
// Called when the upload is paused
Log.d("Upload", "Upload paused")
}
override fun onResumeUploading() {
// Called when the upload resumes
Log.d("Upload", "Upload resumed")
}
}
Updated 2 days ago