샘플 다운로드 받기
watchOS 앱과 연결된 iOS 앱과 상태 동기화하기
일부 워치 앱은 복잡한 계산을 수행하거나 풍부한 콘텐츠를 표시하기 위해 페어링된 iOS 앱에 많은 의존성을 가지며, 인터넷 연결이 불가능한 상황에서도 iOS 동반 앱과 데이터를 교환해야 할 수 있습니다. Watch Connectivity 프레임워크는 페어링된 앱 간의 양방향 통신을 구현하기 위한 편리한 API를 제공합니다. 이 예제는 이러한 API 간의 미묘한 차이점을 보여주며 Watch Connectivity 백그라운드 작업을 처리하는 방법을 보여줍니다.
샘플 코드를 빌드하기 전에 XCode에서 다음과 같은 절차를 밟아야 합니다
1. SimpleWatchConnectivity 대상의 일반 패널에서 Bundle Identifier 필드를 새 식별자로 업데이트하십시오.
2. 서명 및 기능 패널에서 Team 드롭다운 메뉴에서 해당 팀을 선택하여 Xcode가 프로비저닝 프로필을 자동으로 관리하도록 합니다. 자세한 내용은 팀에 프로젝트 할당을 참조하십시오.
3. 마찬가지로, WatchKit 앱 및 WatchKit Extension 대상의 번들 식별자와 개발 팀을 업데이트하십시오. 각각의 번들 식별자는 <iOS 앱 번들 식별자>.watchkitapp 및 <iOS 앱 번들 식별자>.watchkitapp.watchkitextension이어야 합니다.
4. WatchKit 앱 대상의 Info.plist 파일을 열고 WKCompanionAppBundleIdentifier 키의 값을 새 iOS 앱 번들 식별자로 업데이트하십시오.
5. WatchKit Extension 대상의 Info.plist 파일을 열고 NSExtension > NSExtensionAttributes > WKAppBundleIdentifier 키의 값을 새 WatchKit 앱 번들 식별자로 업데이트하십시오.
워치 연결을 사용하여 데이터 전송
워치의 Connectivity 프레임워크는 다음과 같은 작업을 하도록 API들을 제공합니다.
* 애플리케이션의 context를 업데이트합니다.
* 메세지를 보냅니다.
* 사용자 정보를 전송하고 뛰어난 전송을 관리합니다.
* 파일을 전송하고, 전송 진행 상황을 보고, 뛰어난 전송을 관리합니다.
* iOS 앱에서 현재 컴플리케이션을 업데이트할 수 있습니다.
이러한 API는 모두 딕셔너리를 받아서 앱 간에 전달하지만, 중요한 차이점이 있습니다. updateApplicationContext(_:)는 딕셔너리를 보내며, 일반적으로 앱 context 데이터의 일부입니다. 이를 통해 반대편 앱에 데이터를 보내고, 이미 존재하는 데이터가 있는 경우 대체합니다. transferUserInfo(_:) 또한 딕셔너리를 전송하지만, 전송이 보장됩니다. 앱이 짧은 시간 내에 여러 딕셔너리를 전송하는 경우, 시스템이 이들을 큐에 넣어 동일한 순서대로 전달합니다. sendMessage(_:replyHandler:errorHandler:)는 즉시 딕셔너리를 보내고, 전송이 실패할 경우 오류를 반환할 수 있습니다.
메세지를 전송할 때 앱은 선택적으로 반대편 앱으로부터 받는 데이터를 handler를 통해서 대응할 수 있습니다. 대응하는 handler는 비동기적으로 백그라운드 스레드에서 실행되며 타임아웃을 피하기 위해 빠르게 반환되어야 합니다. watchOS 앱에서 메시지를 보내면 연결할 수 있는 페어링된 iOS 앱이 깨어납니다.
iOS 앱에서 활성화된 Complications 업데이트
현재 복잡성 사용자 정보 전송을 보여주기 위해, 이 샘플은 무작위 숫자를 표시하는 복잡성을 제공합니다. 이를 활성화하려면 다음 단계를 따라야 합니다.
1. 워치에서 모듈형 시계 페이스를 선택하십시오.
2. 워치 페이스를 눌러 사용자 정의 화면을 표시하고, 편집 버튼을 탭한 후 화면을 오른쪽으로 스와이프하여 구성 화면을 표시하십시오.
3. 긴 바디 영역을 탭하고, 디지털 크라운을 회전하여 SimpleWatchConnectivity 복잡성을 찾으십시오.
4. 디지털 크라운을 누르고 화면을 탭하여 뒤로 가기를 누르고 구성을 완료하십시오.
iOS 앱에서 복잡성을 업데이트하려면, 이 샘플은 iOS 측에서 복잡성이 활성화된 경우 transferCurrentComplicationUserInfo를 호출합니다. 시스템은 하루에 이러한 종류의 50회 전송을 허용하며, 앱은 remainingComplicationUserInfoTransfers를 사용하여 남은 전송 횟수를 검색할 수 있습니다.
if WCSession.default.isComplicationEnabled {
let userInfoTranser = WCSession.default.transferCurrentComplicationUserInfo(userInfo)
시계 측면에서, 이 샘플은 컴플리케이션을 업데이트하기 위해 reloadTimeline을 호출합니다.
let server = CLKComplicationServer.sharedInstance()
if let complications = server.activeComplications {
for complication in complications {
// Call this method sparingly.
// Use extendTimeline(for:) instead when the timeline is still valid.
server.reloadTimeline(for: complication)
}
}
Watch Connectivity 백그라운드 작업 처리
앱은 WKWatchConnectivityRefreshBackgroundTask를 완료해야 합니다. 그렇지 않으면 작업은 백그라운드 실행 시간을 계속 소비하다가 메모리가 바닥나고 앱이 충돌합니다. 이 샘플은 작업을 배열에 보관하고 다음 경우에 완료합니다:
* 앱이 작업을 처리하는 것을 마쳤을 때.
* 현재 WCSession이 .activated 이외의 상태로 변경될 때.
* hasContentPending이 false로 전환되어 (WCSession 활성화 전에 받은) 처리 대기 중인 데이터가 없음을 나타낼 때.
다음 코드는 확장 delegate의 handle(_:) 메서드 끝에서 작업을 완료합니다.
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
for task in backgroundTasks {
if let wcTask = task as? WKWatchConnectivityRefreshBackgroundTask {
wcBackgroundTasks.append(wcTask)
Logger.shared.append(line: "\(#function):\(wcTask.description) was appended!")
} else {
task.setTaskCompletedWithSnapshot(false)
Logger.shared.append(line: "\(#function):\(task.description) was completed!")
}
}
completeBackgroundTasks()
}
다음 코드는 다른 상황에서 작업을 완료합니다.
activationStateObservation = WCSession.default.observe(\.activationState) { _, _ in
DispatchQueue.main.async {
self.completeBackgroundTasks()
}
}
hasContentPendingObservation = WCSession.default.observe(\.hasContentPending) { _, _ in
DispatchQueue.main.async {
self.completeBackgroundTasks()
}
}
백그라운드 작업을 디버깅하는 것은 까다로울 수 있습니다. 왜냐하면 일반적으로 watchOS 앱은 오랫동안 실행되지 않기 때문입니다. 사용자가 앱을 사용을 멈추고 손목을 내리면 watchOS는 앱을 일시 중단시킵니다. watchOS가 앱에 대한 백그라운드 작업을 트리거할 때, 앱은 일시 중단된 상태일 수 있으므로 시스템은 이를 깨워야 합니다 (또는 시작해야 합니다). Xcode를 사용하여 앱을 실행하면 시스템이 일시 중단 프로세스를 진행하지 못하므로 디버깅 환경과 최종 사용자 환경 사이에 불일치가 발생할 수 있습니다. 이러한 불일치를 피하기 위해, 앱을 직접 홈 화면에서 실행하고 앱 로그를 분석하여 디버깅합니다. 이 샘플에서는 디버깅을 위해 Logger 클래스를 사용하여 로그를 파일에 작성하고 사용자가 파일 전송 버튼을 탭할 때 이를 iOS 앱으로 전송합니다.
'SwiftUI' 카테고리의 다른 글
사용자의 운동 경로 기록 가져오기 (0) | 2024.03.13 |
---|---|
사용자의 운동 경로 기록하기 (0) | 2024.03.13 |
HKQuantityType (0) | 2024.03.11 |
HKLiveWorkoutDataSource (0) | 2024.03.11 |
HKLiveWorkoutBuilder (0) | 2024.03.11 |