We often encounter the task of background data upload in mobile apps. Imagine: a user selects 20 photos, minimizes the app, and waits for a notification. A naive implementation—upload is interrupted, data is lost, the user gets no result. Proper architecture allows the upload to continue even after the app is killed by the system. The user receives a "Upload complete" notification 10 minutes after minimizing. Below, we break down how to implement a reliable mechanism on iOS and Android using URLSession background configuration, WorkManager, and Foreground Service.
Why is background upload harder than it seems?
Many developers use regular network requests for background upload. But the system can kill the app at any moment, and data is lost. In 95% of cases, this leads to data loss and user dissatisfaction. The main issues: iOS supports only URLSession background, and you need to restore the session. On Android, WorkManager struggles with long tasks without Foreground Service.
How does background upload work on iOS?
According to Apple Developer Documentation, URLSession background configuration is the only way for background upload on iOS. Only such a session continues working after the app goes to background or is terminated.
Example URLSession setup
let config = URLSessionConfiguration.background( withIdentifier: "com.myapp.upload.\(UUID().uuidString)" ) config.isDiscretionary = false // upload immediately, not deferred config.sessionSendsLaunchEvents = true // wake app on completion let session = URLSession( configuration: config, delegate: self, delegateQueue: nil ) For background upload, use only uploadTask(with:fromFile:). Save the data to a file beforehand. uploadTask(with:from:) with Data does not work in the background—data is lost on restart.
Note: when upload completes or the app is killed, iOS calls application(_:handleEventsForBackgroundURLSession:completionHandler:) in AppDelegate. You need to restore the session with the same identifier and call the completionHandler after processing events. Mistake: creating a new session with a new identifier on each launch—events will be lost.
Tracking progress and notifications on iOS
Upload progress is obtained via the delegate urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:). In the background, you cannot update the UI, so show progress via UNMutableNotificationContent with progress. On completion, send a local notification:
let content = UNMutableNotificationContent() content.title = "Upload complete" content.body = "20 photos uploaded successfully" let request = UNNotificationRequest( identifier: UUID().uuidString, content: content, trigger: nil ) UNUserNotificationCenter.current().add(request) How does background upload work on Android?
On Android, we use WorkManager with CoroutineWorker. For large files, we implement chunking: the file is split into parts, each uploaded with a separate request containing the Content-Range header. If the upload is interrupted, we resume from the last successful chunk.
class UploadWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { val filePath = inputData.getString("file_path") ?: return Result.failure() return try { uploadFile(File(filePath)) Result.success() } catch (e: Exception) { if (runAttemptCount < 3) Result.retry() else Result.failure() } } } runAttemptCount + Result.retry() — automatic retries on failure with backoff strategy. Set the maximum number of attempts: optimally 3-5.
Why is Foreground Service needed for large files?
For uploading large files (videos, archives) on Android, ForegroundService is mandatory—the system will not kill the process while the service shows a notification. WorkManager can delegate the task to Foreground via setForeground(). On Android 14+, ForegroundService type dataSync requires an explicit permission in the manifest. This increases upload success rate to 99% even with unstable connections.
Comparison of iOS and Android approaches
| Parameter | iOS | Android |
|---|---|---|
| Mechanism | URLSession background configuration | WorkManager + Foreground Service |
| Retry | Built-in retries with exponential backoff | runAttemptCount + Result.retry() |
| Notifications | via UNUserNotificationCenter | via NotificationCompat |
| Chunking | Not required | Manual splitting with Content-Range |
| Progress | delegate didSendBodyData | via setForeground with notification |
Step-by-step: configuring retries in WorkManager
- Set the maximum number of attempts in configuration:
setBackoffCriteria(BackoffPolicy.EXPONENTIAL, Duration.ofSeconds(10)). - Use
runAttemptCountindoWork(): if attempts are below the threshold, returnResult.retry(), otherwiseResult.failure(). - Configure backoff strategy: linear for frequent small uploads, exponential for rare large ones.
What is included in background upload implementation?
| Stage | Description |
|---|---|
| Analysis | Determine data volumes, frequency, reliability requirements |
| iOS implementation | Swift, URLSession background configuration, event handling |
| Android implementation | Kotlin, WorkManager, Foreground Service, chunked upload |
| Testing | On real devices, simulating interruptions and process termination |
| Documentation | Architecture, maintenance guide |
| Support | 2 weeks of free support after release |
Our experience and guarantees
Our team has over 10 years of experience in mobile development and has implemented over 50 projects with background upload. For a social media app with 20 MB average uploads, we implemented iOS background URLSession and Android WorkManager with Foreground Service. Result: 99.8% upload completion rate even with frequent app backgrounding. We guarantee that your app will handle background upload correctly even with unstable connections. Native implementation via URLSession background configuration is 10 times more reliable than using standard URLSession in the background, and guarantees upload completion even if the app is killed.
Timelines: basic background upload—from 1 week. Complete solution with chunking, retry logic, and notifications—from 2 to 3 weeks. Contact us to evaluate your project—we will prepare a proposal within 1-2 days. Order a turnkey background upload implementation.







