파파비의 블로그
[SwiftUI] Background Task (wwdc22) 사용방법 본문
[Background Task란?]
- Background: 앱이 백그라운드에 있으며, 화면에 보이지 않지만 코드가 실행될 수 있는 상태.
- Suspended: 앱이 백그라운드에 있으며, 코드 실행이 일시 중지된 상태.
앱이 위 2가지 상태중에 하나 일때, 시스템에 "원하는 코드/작업"을 "언제 실행"시키라고 지정하는 것임
실제로 iOS는 해당시간이 되면 앱을 깨워 실행하게 되나, 시스템 상황에 따라 시간적 오차가 있을 수 있음.
주로, 유저가 앱을 안보고 있을 때 어떠한 업데이트를 하여 유저 사용성을 높이는데 사용되고 있음.
[구현 방법]
1. Signing & Capabilities 에 "Background Modes" 추가하기
- Background Fetch 체크 (extension이 있어도 main target 한곳에만 기능추가하고 체크하면 됨)
- 그 외에도 Background 작업의 선택지로는
1) Background Processing : db작업, 다운로드 등 헤비한 작업할 때 사용 - 코드가 조금 다름)
2) Remote Notifications : 서버에서 Slient Push Noti를 보내서 백단에서 앱을 깨우고 원하는 작업 실행하게 하는 것
구조적으로 정기적(Fetch: 라이트한 작업/Processing: 헤비한 작업) 비정기적(Remote Notifications) 으로 나뉨
2. Info.plist에 식별자 추가하기
- 우리가 Background Task를 등록할 때, 이 Task를 언제 실행되도록 해주세요. 라고 시스템에 등록하는 과정이 있음.
- 이때 이 과정의 이름도 등록해야하는데, 그 이름들을 시스템에 모아서 알려주는 것임.
- 아래 예시는 "randomImage"라고 등록하였음. (이때 따옴표까지 같이 값을 넣는 실수를 종종하곤 하는데 유의할것)
3. Background Task 등록하기
- 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()
4. BackgroundTask 콜백 등록하기
- 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()
}
}
5. 테스트 해보기
- 이제 셋팅이 완료되었음. 문제는 테스팅인데, 테스트 하는 방법이 별도로 존재함
(참고로 실제 프로덕션에서는 최소 2-3시간에 한번씩만 background Task를 하도록 권장하고 있음. 너무 시간 간격이 좁으면 실행이 안되었던 사람도 있었음)
1) 스케쥴 등록 시점 직후 (이름/시점 셋팅한 직후)에 "중단점" 셋팅하기
2) 실행하기. 그리고 해당 부분에서 중단되도록 하기
- 위 예시는 버튼을 눌러야 실행 되기 때문에, 실행한 뒤에 버튼을 누르면 됨. 그러면 저기에서 중단 됨.
- 중단이 되면, lldb라고 해서, low-level debbuger를 실행할 수 있게 됨.
- 콘솔 부분이 아래와 같이 변함
3) lldb에 아래 코드 실행 후 다시 앱재개
- 맨 끝 부분에 "randomImage"로 되어 있는데, 당연히 본인이 실행하고 싶은 식별자로 바꿔줘야 함.
- 코드가 하나라도 틀리면 실행이 안되고 오류가 막 뜸. 아래 코드를 복사해서 쓰는게 좋음
expression -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"randomImage"]
- 앱을 다시 재개해야 함. 아래 이미지 좌측 상단, 2번째 버튼을 보면 재개하기 버튼이 있음. 눌러주면 됨.
4. 그럼 다시 실행이 되고, 백그라운드 작업이 진행됨.
- 백그라운드 작업이라, 코드가 잘 실행되었는지를 확인하기 위해 보통은 local notification을 활용 많이 함.
- 관련 코드를 넣어서 실행하도록 하는게 편함.
- 관련 코드까지 포함된 코드는 아래 [참고 링크]1 에 들어가서 확인하면 됨.
- 그런 사람들을 위해 아래 코드를 복사해서 쓰도록 공유함.
- 파일은 2개면 됨. 그리고 아래 블로그에서 올라온 코드를 수정한 코드임.
[참고 링크] 1
https://holyswift.app/new-backgroundtask-in-swiftui-and-how-to-test-it/
[참고 링크] 2
https://www.youtube.com/watch?v=FfRjTOl36UY