A sequential file upload library for Android using WorkManager. Built by Extreme Solution.
- 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
EsUploadManageranywhere in your app - Network-aware — uploads only run when a network connection is available
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")
}Your Application class must be annotated with @HiltAndroidApp.
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()
}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>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
You can customize the notification title and filename:
UploadRequest(
// ... other fields
notificationTitle = "Uploading photo",
notificationFileName = "vacation.jpg" // null = use actual filename
)@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"
)
)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 -> {}
}
}
}esUploadManager.retry("photo_123")
esUploadManager.cancelAll()
esUploadManager.delete("photo_123")
esUploadManager.deleteAllFailed()| 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 |
MIT License — see LICENSE for details.