Background Task — механизам iOS-а који омогућава апликацији да заврши започету операцију након преласка у позадински режим. Систем додељује ограничено време (до 30 секунди) за извршавање задатка, након чега се апликација принудно зауставља. Према Apple, 2026, употреба expiration handler-а је обавезан услов за правилно завршавање позадинског задатка.
Главне тачке
Background Task је програмски механизам iOS-а који омогућава апликацији да продужи време извршавања након преласка у позадински режим. Када корисник минимизује апликацију, систем позива UIApplicationDelegate.applicationDidEnterBackground. Ако се у том тренутку извршава критична операција (чување података, слање захтева), апликација може затражити додатно време путем beginBackgroundTask.
Без коришћења Background Task-а, апликација се принудно зауставља након 3–5 секунди од одласка у позадину. Све незавршене операције се прекидају: подаци се не чувају, мрежни захтеви се прекидају, стања се губе. Background Task даје апликацији до 30 секунди за правилно завршавање ових операција.
beginBackgroundTask се појавио у iOS 4.0 — првом издању које подржава вишезадачност. Пре iOS-а 4, апликација се потпуно затварала притиском на дугме Home. Од iOS-а 7 појавили су се Background Fetch и URLSession background configuration. Почевши од iOS-а 13, Apple препоручује BGTaskScheduler за нове пројекте, али beginBackgroundTask остаје актуелан за краткорочне операције.
beginBackgroundTask — метод UIApplication-а који региструје задатак и враћа јединствени идентификатор UIBackgroundTaskIdentifier. Систем повећава тајмер позадинског извршавања. По истеку времена позива се expiration handler, након чега апликација мора да позове endBackgroundTask(identifier:) ради правилног завршетка.
Корак 1 — апликација прима обавештење didEnterBackground. Корак 2 — позива се beginBackgroundTask(expirationHandler:). Корак 3 — извршава се критична операција (чување, мрежни захтев). Корак 4 — по завршетку се позива endBackgroundTask(identifier:). Ако се операција не заврши за 30 секунди — систем позива expiration handler, и апликација мора одмах да заврши задатак.
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Expiration handler
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
func finishBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
Својство backgroundTimeRemaining враћа број секунди преосталих до принудног завршавања позадинског задатка. Вредност се смањује у реалном времену. Ако апликација није у позадини — враћа DBL_MAX. Користите ово својство за прилагођавање понашања: када остане мање од 5 секунди, прекините дуготрајне операције и сачувајте напредак.
Апликација може регистровати неколико Background Task-ова истовремено. Сваки задатак добија сопствени идентификатор. Укупно време извршавања се сабира — ако су регистрована 3 задатка, апликација може добити до 90 секунди. Међутим, систем може раније завршити апликацију ако су ресурси исцрпљени или је прекорачена граница батерије.
Expiration handler је блок кода који систем позива када истекне додељено време за позадински задатак. Постојање expiration handler-а је обавезан услов компаније Apple. Без њега, апликација може бити принудно завршена од стране система, а подаци могу бити изгубљени.
Expiration handler треба да изврши минималне радње за чување стања апликације: сачува тренутне податке у трајном складишту, позове endBackgroundTask са одговарајућим идентификатором и постави идентификатор на .invalid. Унутар expiration handler-а забрањено је покретање нових дуготрајних операција — време извршавања је ограничено на 1–2 секунде.
func handleExpiration() {
// Чувамо напредак извршавања
saveProgressToUserDefaults()
// Отказујемо активне мрежне захтеве
currentTask?.cancel()
// Завршавамо Background Task
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// Регистрација са expiration handler-ом
backgroundTaskID = UIApplication.shared.beginBackgroundTask(
withName: "SaveDocument",
expirationHandler: handleExpiration
)
Најчешћа грешка је не позивати endBackgroundTask унутар expiration handler-а. У овом случају систем наставља да сматра задатак активним, апликација не прелази у стање Suspended, а батерија се празни. Друга грешка је покретање дуготрајних операција унутар expiration handler-а. Систем може завршити апликацију пре њиховог завршетка, и подаци ће бити изгубљени.
У expiration handler-у време извршавања је критично кратко — обично мање од 1 секунде. Стога се унутар handler-а не могу извршавати: сложена израчунавања, мрежни захтеви, упис великих количина података у CoreData. Само атомске операције: упис једног кључа у UserDefaults, постављање статусне заставице, позив endBackgroundTask.
Размотримо потпуну имплементацију Background Task-а за чување документа при одласку апликације у позадину. Пример укључује регистрацију задатка, извршавање операције са провером преосталог времена и правилан завршетак путем endBackgroundTask.
При одласку у позадину, апликација покреће чување великог документа. Background Task даје до 30 секунди за операцију. Ако време истекне — expiration handler чува међурезултате. Након завршетка чувања позива се endBackgroundTask за ослобађање ресурса.
class DocumentManager {
private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func saveDocumentInBackground(document: Document) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
self.saveProgress(document)
self.endBackgroundTask()
}
DispatchQueue.global().async {
document.save()
self.endBackgroundTask()
}
}
private func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
Мрежни захтеви у позадини захтевају посебну пажњу — expiration handler може прекинути захтев пре добијања одговора. Користите URLSession са dataTask и проверавајте backgroundTimeRemaining пре слања. Ако је остало мање од 5 секунди — одложите слање до следећег буђења апликације.
func sendCriticalData(data: Data) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Чувамо податке за поновно слање
saveForRetry(data)
self.endBackgroundTask()
}
let task = URLSession.shared.dataTask(with: request) { _, _, error in
if error != nil {
saveForRetry(data)
}
self.endBackgroundTask()
}
task.resume()
}
За дуготрајне операције пратите UIApplication.shared.backgroundTimeRemaining. Ако вредност падне испод прага (10 секунди), прекините тренутну операцију и покрените чување међурезултата. Ово омогућава правилан завршетак рада пре принудног позива expiration handler-а.
Background Task је моћан механизам, али његово неправилно коришћење доводи до проблема са батеријом и перформансама. Поштовање препорука Apple-а и проверених пракси заједнице помаже у избегавању типичних грешака и обезбеђивању стабилног рада апликације.
Завршите Background Task што је пре могуће. Свака секунда позадинског извршавања троши енергију батерије. Оптимално време — мање од 5 секунди. Ако операција траје дуже — размотрите коришћење BGTaskScheduler-а или Background Modes-а. Не продужавајте задатак вештачки путем beginBackgroundTask позива без стварне потребе.
Чувајте UIBackgroundTaskIdentifier као својство класе или структуре. Никада га не прослеђујте као глобалну променљиву — то доводи до конфликата код вишеструких задатака. Поставите идентификатор на .invalid након позива endBackgroundTask да бисте спречили двоструко завршавање.
У Xcode Simulator-у пребаците апликацију у позадину путем дугмета Home (Command + Shift + H). Користите Debug — Simulate Background Fetch за тестирање позадинског буђења. За симулацију истека времена поставите променљиву окружења BACKGROUND_TASK_SIMULATE_EXPIRATION = YES — expiration handler ће бити позван након 5 секунди.
// Провера преосталог времена пре почетка операције
let remaining = UIApplication.shared.backgroundTimeRemaining
guard remaining > 10.0 else {
// Недовољно времена — одложи задатак
scheduleForNextLaunch()
return
}
// Извршавање операције са контролом времена
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
saveProgress()
self.endBackgroundTask()
}
Expiration handler хвата self — то може створити retain cycle ако се backgroundTaskID чува као својство истог објекта. Користите [weak self] у затварању или чувајте идентификатор одвојено. Retain cycle доводи до цурења меморије — објекат неће бити ослобођен до завршетка апликације.
Са изласком iOS-а 13, Apple је представио BGTaskScheduler — модерну замену за стари Background Task API. Оба механизма решавају сличне задатке, али BGTaskScheduler пружа више контроле и флексибилности. Разумевање разлика помаже у одабиру правог алата за конкретан сценариј.
| Карактеристика | Background Task | BGTaskScheduler |
|---|---|---|
| Верзија iOS | 4.0+ | 13.0+ |
| Макс. време | 30 секунди | 30 с / 10 мин (processing) |
| Иницијација | didEnterBackground | Планирање + систем |
| Гаранција извршења | Само при преласку у позадину | У било које време погодно за систем |
| Expiration handler | Да, обавезан | Да, путем task.expirationHandler |
| Интернет | Потребан при покретању | Доступан путем requiresNetworkConnectivity |
| Пуњење | Није потребно | Опционо за processing |
beginBackgroundTask је погодан за краткорочне операције које треба извршити одмах при одласку у позадину: чување стања, завршавање мрежног захтева, кеширање података. API је једноставан и не захтева конфигурацију Info.plist-а или регистрацију идентификатора. Идеалан за операције које трају мање од 10 секунди.
BGTaskScheduler је погодан за задатке који се могу извршити у било које погодно време: периодична синхронизација, чишћење кеша, ажурирање виџета. Систем сам бира оптимално време узимајући у обзир понашање корисника и стање батерије. За дуготрајне операције (до 10 минута) користите BGProcessingTask.
Оба API-ја се могу користити у једној апликацији. Background Task — за хитне операције при одласку у позадину (чување нацрта). BGTaskScheduler — за планирана ажурирања (синхронизација сваких 6 сати). Подела одговорности омогућава гарантовање правилног чувања података и енергетски ефикасног позадинског сервиса.
Често постављана питања
Да, beginBackgroundTask се може позвати у било ком тренутку рада апликације. Међутим, системско додељивање времена почиње тек након преласка у позадину. Ако је апликација у предњем плану, позив beginBackgroundTask нема ефекта — backgroundTimeRemaining враћа DBL_MAX, а задатак ће бити активиран при одласку у позадину.
Ако се не позове endBackgroundTask, систем наставља да сматра апликацију активном у позадини. Након 30 секунди биће позван expiration handler, али ако ни у њему нема endBackgroundTask — апликација остаје у меморији, трошећи батерију. У iOS 13+ систем принудно завршава такву апликацију након 3 минута.
Стандардно време је 30 секунди. Повећати га се може само кроз Background Modes: Audio (репродукција), Location (геолокација), Bluetooth (BLE). Или путем BGProcessingTask (iOS 13+) — до 10 минута уз услов пуњења и Wi-Fi-ја. beginBackgroundTask сам по себи не пружа начин за повећање лимита.
Да, iPadOS у потпуности подржава beginBackgroundTask са истим ограничењима као iOS. На iPad-у са Stage Manager-ом, апликација може остати у меморији дуже — систем ређе зауставља апликације због веће количине RAM-а. Али лимит од 30 секунди за позадински задатак остаје.
Повежите уређај са Xcode-ом, покрените апликацију, минимизујте је — у конзоли ће се појавити системски дневници. Користите sysdiagnose за прикупљање детаљних дневника: принудно покрените sysdiagnose са уређаја (Volume Up + Down + Power). У Xcode Debug Navigator-у пратите активност позадинских задатака.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође