Device 잠금 상태 추적해 백그라운드 데이터 업로드 하기

오늘은 이전에 백그라운드를 통해 데이터를 수집했던 로직을 사용했을 때 iOS 정책 상 디바이스가 잠겼을 때 데이터에 접근할 수 없는 다소 민감한 데이터들을 처리하기 위해 고민 했던 내용을 기록으로 남겨두려고 한다.

 

SensorKit, HealthKit 데이터와 같이 다소 민감한 데이터는 백그라운드에서 데이터 수집이 가능하지만, 디바이스가 잠겨있을 때 데이터 접근이 불가해진다.

 

목표는 최대한 많은 데이터를 수집해야하기 때문에 이 점을 바탕으로 가장 최선의 방식은 디바이스 잠김이 해제됐을때 데이터를 수집할 수 있도록 구현하는게 가장 좋다고 판단했다.

 

먼저 가장 중요한 개념은 UIApplication에서 protectedDataDidBecomeAvailableNotification 부분이라고 볼 수 있다.

 

https://developer.apple.com/documentation/uikit/uiapplication/1623039-protecteddatadidbecomeavailablen/

 

protectedDataDidBecomeAvailableNotification | Apple Developer Documentation

A notification that posts when the protected files become available for your code to access.

developer.apple.com

 

공식문서를 살펴보면 디바이스의 잠김 상태를 추적해서 그 시점에 어떠한 작업을 해줄 수 있다는 점이다. 이 기능을 활용해 앱이 켜지는 시점에 데이터를 호출해보도록 하자.

 

먼저 BackgroundDataManager를 하나 만들어준다. 하나만 적용할게 아니라 다수 데이터를 다룰거기 때문에 조금 더 수월하게 데이터를 수집하도록 구현할 예정이기 때문.

private init() {
    NotificationCenter.default.publisher(for: UIApplication.protectedDataDidBecomeAvailableNotification)
        .sink { [weak self] _ in
            self?.fetchDataIfNeeded()
        }
        .store(in: &cancellables)
    
    startFetchTimer()
}

매니저의 초기화 부분에 NotificationCenter를 활용해 기기의 잠금 상태를 체크할 수 있도록 구현해 준다.

 

그 다음

private func fetchDataIfNeeded() {
    guard UIApplication.shared.isProtectedDataAvailable else {
        print("기기 잠김")
        return
    }
    
    let now = Date()
    if let lastFetched = lastFetchedTime, now.timeIntervalSince(lastFetched) < 15 * 60 {
        print("15분 내 데이터 수집 됨, 수집 안함")
        return
    }
    
    collectDataFromManager()
    
    lastFetchedTime = now
}

private func collectDataFromManager() {
    DeviceUsageManager.shared.fetchDeviceUsageData()
    CallLogManager.shared.fetchCallLogData()
    AmbientManager.shared.fetchAmbientLightData()
    SpeechMetricsManager.shared.fetchTelephonySpeechMetricsData()
    KeyboardMetricsManager.shared.fetchKeyboardMetricsData()
    HealthKitManager.shared.fetchStepCountDifference()
    print("잠김 해제 후 데이터 수집 완료")
}

fetchDataIfNeeded 메소드를 만들어 기기가 잠겨있을때와 잠기지 않을때의 로직을 구현해 주었다. 먼저 마지막 데이터 수집 시점을 저장하고 해당 지점이 지금 현재 지점과 차이가 15분이 나지 않을때 데이터를 수집 하지 않도록 한다.

 

왜냐하면 데이터 수집이 디바이스 잠금이 해제될때마다 수집되는 것을 막기 위해서이다. 그래서 처음 디바이스를 해제 했을때 데이터를 수집하고 그 이후 잠궜다가 다시 열었는데 그 시점이 15분이 지나지 않으면 데이터를 수집하지 않는다.

그 이후 collectDataFromManager 내 각 데이터 수집 메서드를 호출해주면 이제 디바이스 잠금이 해제됐을때 정상적으로 데이터를 가져올 수 있게 된다.

struct VitalTrackerApp: App {
	init() {
		_ = BackgroundDataManager.shared
	}
}

그 다음 앱단에서 앱이 실행 됐을 때 해당 내용을 적용할 수 있도록 초기화 함수를 통해 넣어주면 앱이 실행 된 이후 디바이스를 잠그거나 열때 해당 로직이 제대로 작동하게 된다.

 

요즘 앱 구현 시 백그라운드 데이터를 다루고 있는데 백그라운드에서 iOS 가 직접 앱 사용 시기와 시점을 선택해 호출해준다는 점도 있었고 역시 아직 신기한 부분이 많았다.

 

이 내용은 현재 사이드로 개발 중인 런닝 기록을 하는데 있어 조금 유용하게 작용할 수 있을 것 같다 백그라운드 데이터 다루는데 익숙해지자!

 

오늘은 여기까지!