* Background: 앱이 백그라운드에 있으며, 화면에 보이지 않지만 코드가 실행될 수 있는 상태.
* Suspended: 앱이 백그라운드에 있으며, 코드 실행이 일시 중지된 상태.
앱이 위 2가지 상태중에 하나 일때, 시스템에 "원하는 코드/작업"을 "언제 실행"시키라고 지정하는 것임
실제로 iOS는 해당시간이 되면 앱을 깨워 실행하게 되나, 시스템 상황에 따라 시간적 오차가 있을 수 있음.
주로, 유저가 앱을 안보고 있을 때 어떠한 업데이트를 하여 유저 사용성을 높이는데 사용되고 있음.
우리가 Background Task를 등록할 때, 이 Task를 언제 실행되도록 해주세요. 라고 시스템에 등록하는 과정이 있음.
이때 이 과정의 이름도 등록해야하는데, 그 이름들을 시스템에 모아서 알려주는 것임.
아래 예시는 "randomImage"라고 등록하였음. (이때 따옴표까지 같이 값을 넣는 실수를 종종하곤 하는데 유의할것)
Background Task의 이름은 randomImage인데, 이 녀석을 언제 실행하도록 해주세요를 시스템에 등록하는 행위
이때, Task의 존재만 등록하는 것이고, "그때가 되면 Task가 어떤 코드를 실행해야하는지"에 대해선 여기서 따로 셋팅하지는 않음.
아래 코드를 보면,
1) BackgroundTasks를 import하였음
2) 실제로는 평범한 뷰 안에 있는 내용인데, 그 중에 관련된 코드만 뽑아서 따로 적은 것임
3) 버튼 뷰의 콜백메소드를 살펴보면, BGAppRefreshTaskRequest안에 identifier를 넣어줘야 하는데, 이게 Task의 이름임
- 위에서 randomImage로 등록해놨으니, 그걸 써야함.
- 실제로 이름은 안겹치게 하기 위해, bundleID + @의 조합으로 많이씀.
4) 이름 등록했으니, 언제 시작할지 셋팅해줘야하며, 그게 earlistBeginDate 파라미터임.
- Date 객체를 넣어서 시점을 주입해야함.
- 이름부터 알 수 있지만, 이게 "최소 이때 이후로 실행되어라~"의 개념으로, iOS가 바쁠땐 배터리 소모 등을 고려해서 뒤로 미뤄질 수 있음.
5) 이름/시점 셋팅 완료했으면 스케쥴러에 등록하는 과정을 거침
- BGTaskScheduler.shared.submit 메소드 안에 우리가 만든 TaskRequest를 넣어준다.
- 이때 do-catch로 처리해주는 게 좋음. 괜히 try? 로 했다가 무슨 에러인지 파악도 안되어서 시간낭비만 할 수 있음.
import BackgroundTasks
---
Button("Schedule Background Task") {
let request = BGAppRefreshTaskRequest(identifier: "randomImage") // Mark 1
request.earliestBeginDate = Calendar.current.date(byAdding: .second, value: 30, to: Date()) // Mark 2
do {
try BGTaskScheduler.shared.submit(request) // Mark 3
print("Background Task Scheduled!")
} catch(let error) {
print("Scheduling Error \(error.localizedDescription)")
}
}.buttonStyle(.bordered)
.tint(.red)
.padding()
3단계에서, Task의 이름 및 언제 발동되록 시스템에 등록해줌.
이제 그럼 실제로 실행되었을 때, 어떤 코드가 실행되어야하는지 설정해줘야함.
앱의 진입점에 해당하는, 최상단 view에 (보통은 WindowGroup) .backgroundTask Modifier에서 설정하면 됨.
이때 app.Refresh(테스크이름) 파라미터로 넣어주어, 어떤 이름을 가진 BackgroundTask인지에 대해 인지해야함.
그리고 식별이 되었을 때 우리가 원하는 코드를 클로저로 넣어주면 됨
알아두어야 할 점은 여기서는 await/async를 사용할 수 있음.
그리고 여기서 실행 전에, 다시 작업을 설정할 수 있음. 즉 위 3단계에서 했던 이름/시점 등록과정을 여기서 또 할 수 있음. 그러면 "정기적으로 백그라운드 실행환경"을 구현할 수 있게 됨. 위 예시에서는 버튼을 눌러서 작업 등록을 했지만. onAppear 등에서 셋팅할 수도 있음.
var body: some Scene {
WindowGroup {
ContentView(imageStore: imageStore)
}
.backgroundTask(.appRefresh("randomImage")) {
await refreshAppData()
}
}