Skip to content

A sequential file upload library for Android using WorkManager. Built by Extreme Solution.

License

Notifications You must be signed in to change notification settings

ReemMousaES/esUpload

Repository files navigation

esUpload

A sequential file upload library for Android using WorkManager. Built by Extreme Solution.

Features

  • Sequential uploads — files are uploaded one at a time via a Mutex, ensuring order and preventing server overload
  • Automatic retries — configurable retry count with exponential backoff
  • Progress tracking — real-time upload progress reported at 10% intervals via WorkManager's setProgress()
  • Foreground notification — persistent notification with progress bar (required for Android 12+)
  • Persistent queue — uploads survive process death using Room + WorkManager
  • Hilt integration — inject EsUploadManager anywhere in your app
  • Network-aware — uploads only run when a network connection is available

Installation

JitPack

Add JitPack to your project-level settings.gradle.kts:

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
    }
}

Add the dependency to your app-level build.gradle.kts:

dependencies {
    implementation("com.github.ReemMousaES:esUpload:1.2.2")
}

Setup

1. Hilt

Your Application class must be annotated with @HiltAndroidApp.

2. WorkManager

Your Application must implement Configuration.Provider and provide HiltWorkerFactory:

@HiltAndroidApp
class MyApp : Application(), Configuration.Provider {

    @Inject
    lateinit var workerFactory: HiltWorkerFactory

    override val workManagerConfiguration: Configuration
        get() = Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
}

3. Disable default WorkManager initializer

In your AndroidManifest.xml:

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data
        android:name="androidx.work.WorkManagerInitializer"
        android:value="androidx.startup"
        tools:node="remove" />
</provider>

4. Notification permission (Android 13+)

On Android 13 (API 33) and above, you must request the POST_NOTIFICATIONS permission at runtime before uploads will show a notification:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), REQUEST_CODE)
}

The library automatically:

  • Creates a notification channel (esupload_channel) with low importance (no sound)
  • Shows a foreground notification with a progress bar during uploads (when app is foregrounded)
  • Uses expedited work to avoid crashes on Android 12+ when the app is backgrounded
  • Removes the notification when the upload completes or fails

Custom notification text

You can customize the notification title and filename:

UploadRequest(
    // ... other fields
    notificationTitle = "Uploading photo",
    notificationFileName = "vacation.jpg" // null = use actual filename
)

Usage

Enqueue an upload

@Inject
lateinit var esUploadManager: EsUploadManager

esUploadManager.enqueue(
    UploadRequest(
        uploadId = "photo_123",
        filePath = "/storage/.../photo.jpg",
        url = "https://api.example.com/upload",
        headers = mapOf("Authorization" to "Bearer token"),
        params = mapOf("eventId" to "evt_1"),
        fileParamName = "photo",
        notificationTitle = "Uploading photo",
        notificationFileName = "vacation.jpg"
    )
)

Observe progress

esUploadManager.observeWorkInfo().observe(this) { workInfos ->
    workInfos.forEach { workInfo ->
        when (workInfo.state) {
            WorkInfo.State.RUNNING -> {
                val uploadId = workInfo.progress.getString(FileUploadWorker.KEY_UPLOAD_ID)
                val progress = workInfo.progress.getInt(FileUploadWorker.KEY_PROGRESS, 0)
            }
            WorkInfo.State.SUCCEEDED -> {
                val uploadId = workInfo.outputData.getString(FileUploadWorker.KEY_UPLOAD_ID)
                val body = workInfo.outputData.getString(FileUploadWorker.KEY_RESPONSE_BODY)
            }
            WorkInfo.State.FAILED -> {
                val error = workInfo.outputData.getString(FileUploadWorker.KEY_ERROR_MESSAGE)
            }
            else -> {}
        }
    }
}

Retry / Cancel / Delete

esUploadManager.retry("photo_123")
esUploadManager.cancelAll()
esUploadManager.delete("photo_123")
esUploadManager.deleteAllFailed()

API Reference

Method Description
enqueue(request) Enqueue a single upload
enqueueAll(requests) Enqueue multiple uploads
retry(uploadId) Retry a failed upload
cancelAll() Cancel all pending/running uploads
delete(uploadId) Delete a specific upload
deleteAllFailed() Delete all failed uploads
resetStaleUploads() Reset stuck UPLOADING → FAILED
observeAll() Observe all uploads (LiveData)
observeByStatus(status) Observe uploads by status
observePending() Observe non-completed uploads
observeCountByStatus(status) Observe count by status
observeWorkInfo() Observe WorkManager work info

License

MIT License — see LICENSE for details.

About

A sequential file upload library for Android using WorkManager. Built by Extreme Solution.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages