본문 바로가기

IT/iOs

UIBackgroundTaskIdentifier vs BGTaskScheduler

UIBackgroundTaskIdentifier vs BGTaskScheduler

(UIBackgroundTaskIdentifier/BGTaskScheduler ios13 issue)

 

UIBackgroundTaskIdentifier란

앱의 상태가 백그라운드로 들어가도 특정 작업을 가능하게 해 줍니다.

UIBackgroundTaskIdentifier가 생성될 때 백그라운드에서 작업이 시작되는 것이 아닙니다.

UIBackgroundTaskIdentifier를 생성하여 os에게 이다음 작업은 백그라운드에서도 진행되길 원한다는 것을 알리는 것입니다.

 

ios4부터 지원됩니다.

여기서 이슈는 ios13에서 최대 작업 시간이 3분으로 변경되었고 이 3분도 보장을 하지 않는다는 것입니다.

회사 프로젝트를 개발 중에 백그라운드 task를 하는 기능이 동작이 안 되는 것 같아 디버깅을 열심히 해본 결과

30초 정도 작업을 하닥 멈추는 패턴을 발견했습니다.

하지만 앱을 다시 포그라운드로 올리면 하던 작업이 이어져서 진행이 되긴 합니다.

아래 코드는 UIBackgroundTaskIdentifier를 사용하여 타이머를 돌리는 예제입니다.

작업이 끝나면 꼭 UIBackgroundTaskIdentifier를 invalid를 시키고 endBackgroundTask를 호출해야 합니다.

 

 

 

 


import UIKit

class ViewController: UIViewController {
    
    var taskID: UIBackgroundTaskIdentifier?
    var mTimer: Timer?
    var number: Int = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewDidAppear(_ animated: Bool) {

        taskID = UIApplication.shared.beginBackgroundTask(expirationHandler: ({
            UIApplication.shared.endBackgroundTask(self.taskID!)
            self.taskID = .invalid
        }))

        mTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerCallback), userInfo: nil, repeats: true)

    }
    

    @objc func timerCallback() {
        number = number + 1
        print("number \(number)")
        if number == 101 {
            taskID = .invalid
            UIApplication.shared.endBackgroundTask(taskID!)
        }
    }

}

 

 

 

 

BGTaskScheduler란

UIBackgroundTaskIdentifier이 이상하기 때문에 

구글링 결과 wwdc2019에서 UIBackgroundTaskIdentifier 기능을 하는 새로운 API로 BGTaskScheduler를 발표했다고 하더군요

BGTaskScheduler은 UIBackgroundTaskIdentifier보다 작업 시간이 더 길다고 하길래

애플 예제며 구글 예제 소스들이며 열심히 테스트해봤으나 동작을 하지 않습니다!!!!

ios13 이상은 BGTaskScheduler을 사용하도록 분기 처리를 하려고 했으나 아무리 해도 동작을 하지 않고 애플에서 올려준 샘플 소스조차 동작을 하지 않아서 ios13 버그로 분류하고 일단은 좀 더 지켜보기로 했습니다.

만약 제가 잘못 알고 있는 것이라면 코멘트 부탁드리겠습니다 ㅠㅠㅠ

현재는 동작은 하지 않지만 아래부터는 BGTaskScheduler을 다루는 방법을 알아보겠습니다.

 

 

1. Target > Signing & Capabillities > +Capabillity > Background Modes 추가합니다.

 

 

2. Background Modes에서 아래 두항 목을 체크합니다.

 - Background fetch

 - Background processing

 

3. info.plist에 Permitted background task scheduler identifiers를 추가하고 background task가 필요한 만큼 item을 추가하여 식별자를 지정합니다.

4. 그럼 프로젝트 설정은 완료됐습니다. 아래는 BGTaskScheduler를 사용하여 타이머를 돌리는 샘플 소스입니다.

info.plist에 등록해준 식별 값으로 작업을 나누고 등록합니다.

register작업은 꼭 didFinishLaunchingWithOptions에서 해줘야 합니다.

작업을 진행하기 전 현재 실행 중인 작업들을 취소시키는 코드가 꼭 들어가야 에러가 안 난다고 합니다만 지금은 그냥 안됩니다.

 

BGProcessingTaskRequest : 네트워크 통신이나 DB작업이 필요한 시간이 오래 걸릴 수도 있는 작업을 다룹니다.

BGAppRefreshTaskRequest : 앱의 상태를 변경해주는 등의 BGProcessingTaskRequest보다 작업 시간이 짧게 걸리는 작업을 다룹니다.


import UIKit
import BackgroundTasks

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    var mTimer: Timer?
    var number: Int = 0
    var tempTask: BGProcessingTask? = nil

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.task.temp", using: nil) { task in
            self.handleTimerTask(task: task as! BGProcessingTask)
        }
        
        let rootViewController = UIViewController()
        rootViewController.view.backgroundColor = .systemGray
        
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = rootViewController
        window?.makeKeyAndVisible()
        
        return true
    }
    
    func handleTimerTask(task: BGProcessingTask) {
        tempTask = task

        task.expirationHandler = {
            //This Block call by System
            //Canle your all tak's & queues
        }
        
        mTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerCallback), userInfo: nil, repeats: true)

        task.setTaskCompleted(success: true)
    }
    
    @objc func timerCallback() {
        number = number + 1
        print("number \(number)")
        if number == 101 {
            tempTask?.setTaskCompleted(success: true)
        }
    }
    
    func scheduleTask() {
//        let request = BGAppRefreshTaskRequest(identifier: "com.task.temp")

        let request = BGProcessingTaskRequest(identifier: "com.task.temp")
        request.requiresNetworkConnectivity = false // Need to true if your task need to network process. Defaults to false.
        request.requiresExternalPower = false
        
        request.earliestBeginDate = Date(timeIntervalSinceNow: 1) // Featch Image Count after 1 minute.
        //Note :: EarliestBeginDate should not be set to too far into the future.
        do {
            try BGTaskScheduler.shared.submit(request)
        } catch {
            print("Could not schedule image featch: \(error)")
        }
    }
    
    func applicationDidEnterBackground(_ application: UIApplication) {
        print("applicationDidEnterBackground")
        cancelAllPandingBGTask()
        scheduleTask()
    }

    func cancelAllPandingBGTask() {
        BGTaskScheduler.shared.cancelAllTaskRequests()
    }

}

 

 

 

 

 

 

애플 샘플 소스입니다.

RefreshingAndMaintainingYourAppUsingBackgroundTasks.zip
0.06MB

 

 

#ios background task

#wwdc2019 새로운 기능

#wwdc2019 new

'IT > iOs' 카테고리의 다른 글

duplicate symbol for architecture arm64 error  (0) 2019.11.09
section header height must not be negative error  (0) 2019.11.08
Can't end BackgroundTask error  (7) 2019.10.31
SceneDelegate란  (4) 2019.10.30
iOS13 touchid issue  (0) 2019.10.22