SensorKit 데이터를 수집할 때 background 환경에서도 데이터를 수집할 수 있도록 하기 위해 앱 내 백그라운드 작업이 가능하도록 하는 로직을 구현하였다.!
오늘은 백그라운드를 통해 작업을 수행할 수 있도록 하는 방식을 기록으로 남기려고 한다!
먼저 백그라운드 작업을 하기 위해 Signing & Capabilties에 백그라운드 Capability를 추가한 다음 사진에 보이는 두가지를 체크해야한다.
그 다음 infoPlist 내 백그라운드 작업이 진행 될 identifier를 넣어주어야 하는데
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.yourapp.sensordatafetch</string>
</array>
이와 같이 본인 앱의 번들아이디를 넣어준 뒤 코드 내 기재해 둔 identifier를 넣어주면 된다.
이렇게 하면 프로젝트 내 세팅은 마무리하고 코드를 넣어주도록 하자!
먼저 이 프로젝트는 모듈화하여 각각 센서들이 다른 곳에 사용될 수 있도록 해야하기 때문에 동일한 로직들도 같이 구현하지 않고 각각의 Manager를 구현 하는 방식으로 진행되었기 때문에 이를 하나로 통합해줄 수 있는 SensorKitManager를 만들어주었다.
import Foundation
import BackgroundTasks
import SensorKit
class SensorKitManager {
static let shared = SensorKitManager()
func resumeAllSensors() {
print("SensorKit 데이터 수집 재개")
AmbientManager.shared.startRecording()
KeyboardMetricsManager.shared.startRecording()
CallLogManager.shared.startRecording()
DeviceUsageManager.shared.startRecording()
SpeechMetricsManager.shared.startRecording()
}
func startBackgroundFetch() {
scheduleBackgroundTask()
}
func scheduleBackgroundTask() {
let request = BGAppRefreshTaskRequest(identifier: "com.turingbio.vitaltracker.sensordatafetch")
request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 15) // 15분 후 작업 예약
do {
try BGTaskScheduler.shared.submit(request)
print("백그라운드 작업 예약 성공: \\(request.identifier)")
} catch {
print("백그라운드 작업 예약 실패: \\(error.localizedDescription)")
}
}
func handleBackgroundTask(task: BGAppRefreshTask) {
print("백그라운드에서 SensorKit 데이터 수집 시작...")
task.expirationHandler = {
print("백그라운드 작업 만료")
}
AmbientManager.shared.fetchAmbientLightData()
KeyboardMetricsManager.shared.fetchKeyboardMetricsData()
CallLogManager.shared.fetchCallLogData()
SpeechMetricsManager.shared.fetchTelephonySpeechMetricsData()
DeviceUsageManager.shared.fetchDeviceUsageData()
// 백그라운드 작업이 끝나면 재등록
scheduleBackgroundTask()
print("백그라운드에서 SensorKit 데이터 수집 완료")
task.setTaskCompleted(success: true)
}
}
먼저 import를 통해 BackgroundTasks를 넣어준 뒤 백그라운드 작업을 예약할 수 있는 로직을 구현하였다.
func scheduleBackgroundTask() {
let request = BGAppRefreshTaskRequest(identifier: "com.xxx.xxx.sensordatafetch")
request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 15) // 15분 후 작업 예약
do {
try BGTaskScheduler.shared.submit(request)
print("백그라운드 작업 예약 성공: \\(request.identifier)")
} catch {
print("백그라운드 작업 예약 실패: \\(error.localizedDescription)")
}
}
BGAppRefreshTaskRequest 를 사용해 백그라운드 작업을 예약한다. 시스템에게 특정 시점 이후에 작업을 수행할 것을 요청할 수 있어 각 사용에 맞게 해당 값을 넣어주면 된다.
그 다음 earliestBeginDate를 설정해 언제 작업이 실행될 지 설정한다. 지금은 백그라운드로 이동 후 15분 뒤 작업이 실행되도록 구현하였다.
BGTaskScheduler.shared.submit(request) 이걸 활용해 작업 요청을 시스템에 제출하여 실제 백그라운드 작업이 예약되도록 구현하면 된다!
func handleBackgroundTask(task: BGAppRefreshTask) {
print("백그라운드에서 SensorKit 데이터 수집 시작...")
task.expirationHandler = {
print("백그라운드 작업 만료")
}
// 각 SensorKit 데이터 매니저에서 데이터를 수집
AmbientManager.shared.fetchAmbientLightData()
KeyboardMetricsManager.shared.fetchKeyboardMetricsData()
CallLogManager.shared.fetchCallLogData()
SpeechMetricsManager.shared.fetchTelephonySpeechMetricsData()
DeviceUsageManager.shared.fetchDeviceUsageData()
// 작업 완료 후 다음 백그라운드 작업 예약
scheduleBackgroundTask()
print("백그라운드에서 SensorKit 데이터 수집 완료")
task.setTaskCompleted(success: true)
}
그 다음 백그라운드에서 실행 될 작업을 넣어주는데 각 매니저 내 데이터를 페치하는 로직을 넣어주어 15분 단위로 해당 데이터가 페치될 수 있도록 구현하였다.
데이터가 페치된 뒤 scheduleBackgroundTask() 를 호출해 다시 15분 뒤에 데이터를 호출 할 수 있도록 예약 하여 주기적으로 데이터가 들어올 수 있도록 했다.
그리고 SensorKit의 특성 상 StartRecording 이후의 값을 수집할 수 있기 떄문에 데이터를 가져오는 로직만 구현해두면 가져올 데이터가 없어 정상적으로 실행된다고 하여도 아무런 데이터를 받을 수 없기 때문에 앱이 포그라운드에 처음 진입할 때 App 단에서 레코딩이 시작될 수 있도록 구현했다.
.onChange(of: scenePhase) { phase in
switch phase {
case .active:
print("앱 포그라운드 들어옴")
SensorKitManager.shared.resumeAllSensors()
이렇게 구현이 완료되면 백그라운드 이동 시 위에서 스케줄에 넣었던 로그가 원하는 시간이 지나면 이렇게 데이터 페치가 완료되게 된다!
백그라운드 작업에 대해서 조금 이해할 수 있는 과정이었던 것 같아 아주 뿌듯하다..
하지만 애플에서는 모든 작업에서 백그라운드 작업을 허용하는 것은 아니니 백그라운드 작업이 필요한 것들은 공식문서를 통해 그 내용을 잘 찾아보도록 하자!!
오늘은 여기까지 🙂
'◽️ Programming > iOS' 카테고리의 다른 글
앱 내 데이터 JSON으로 변환하기 (1) | 2024.10.14 |
---|---|
EventKit을 사용해 디바이스 내 캘린더 접근하기 (0) | 2024.10.11 |
SensorKit Data Fetch 하는 법 (0) | 2024.10.04 |
SensorKit을 구현하면서 만난 트러블 슈팅 ( 지속적으로 업데이트 예정 ) (1) | 2024.09.19 |
HealthKit에 대해서 알아보고 데이터 가져오기 :) (2) | 2024.09.04 |