Реалізація фонової відправки даних на сервер
Користувач вибрав 20 фотографій для загрузки та свернув додаток. Наївна реалізація — загрузка переривається. Правильна — користувач отримує уведомлення "Загрузка завершена" через 10 хвилин після того, як закрив додаток.
iOS: URLSession з Background Configuration
Єдиний правильний спосіб фонової загрузки на iOS — URLSession з URLSessionConfiguration.background(withIdentifier:). Тільки така сессія продовжує роботу після того, як додаток ушов в фон або був завершений системою.
let config = URLSessionConfiguration.background(
withIdentifier: "com.myapp.upload.\(UUID().uuidString)"
)
config.isDiscretionary = false // завантажувати одразу, не відкладати
config.sessionSendsLaunchEvents = true // будити додаток по завершенні
let session = URLSession(
configuration: config,
delegate: self,
delegateQueue: nil
)
Задача завантаження — тільки uploadTask(with:fromFile:). Дані повинні бути записані у файл на диску перед запуском задачі. uploadTask(with:from:) з Data у фоні не працює — система не може відновити дані з пам'яті після перезапуску додатка.
Коли завантаження завершується (або додаток убитий та перезапущений системою), iOS викликає application(_:handleEventsForBackgroundURLSession:completionHandler:) в AppDelegate. Тут потрібно відновити сессію з тим же ідентифікатором та викликати completionHandler після обробки всіх подій.
Типова помилка: створювати нову сессію з новим identifier при кожному запуску. При відновленні з фону система з'єднується з сессією за збереженим ідентифікатором — якщо сесії з таким ID немає, подіï втрачаються.
Прогрес та уведомлення
Прогрес завантаження отримуємо через делегат urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:). У фоні оновляти UI не можемо, тому показуємо прогрес через UNMutableNotificationContent з progress — користувач бачить статус у Notification Center.
По завершенні відправляємо локальне уведомлення через UNUserNotificationCenter:
let content = UNMutableNotificationContent()
content.title = "Загрузка завершена"
content.body = "20 фото успішно завантажено"
let request = UNNotificationRequest(
identifier: UUID().uuidString,
content: content,
trigger: nil
)
UNUserNotificationCenter.current().add(request)
Android: WorkManager + чанкова загрузка
На Android WorkManager з CoroutineWorker підходить для завантаження файлів. Для великих файлів реалізуємо чанкування: файл розбивається на частини, кожна частина завантажується окремим запитом з заголовком Content-Range. Якщо завантаження перервалось — продовжуємо з останнього успішного чанка.
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() — автоматичні повторні спроби при сбої з backoff-стратегією.
Multipart загрузка та Foreground Service
Для завантаження великих файлів (відео, архіви) на Android обов'язковий ForegroundService — система не убье процес поки сервіс показує уведомлення. WorkManager умітаре делегувати задачу в Foreground через setForeground(). На Android 14+ для ForegroundService типу dataSync потрібне явне дозвіл у манифесті.
Терміни: базова фонова загрузка файлів — 1 тиждень. Надійна реалізація з чанкуванням, retry-логікою, прогрес-уведомленнями та тестуванням на iOS + Android — 2-3 тижні.







