일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- swift
- Autolayout
- Clean Architecture
- 파이썬 풀이
- 파이썬
- error
- 정렬
- Kotlin
- Level 1
- ios
- 앱개발
- dfs
- 프로그래머스
- 그리디 알고리즘
- 백준온라인저지
- 공부
- 알고리즘 공부
- iOS개발
- 오토레이아웃
- SwiftUI
- 안드로이드 공부
- UIKit
- Algorithm
- 백준 온라인 저지
- Android
- Swift공부
- 알고리즘
- greedy algorithm
- Python
- BFS
- Today
- Total
Tori의 개발 공부
[SwiftUI/WatchOS] WatchConnectivity - WCSession을 이용하여 WatchOS와 IOS 데이터 주고 받기 본문
[SwiftUI/WatchOS] WatchConnectivity - WCSession을 이용하여 WatchOS와 IOS 데이터 주고 받기
B_Tori 2024. 3. 20. 15:40워치앱을 개발하면서 워치와 iOS앱의 데이터를 연동해야 하는 상황이었다.
위젯의 경우 UserDefaults와 같은 데이터를 AppGroup을 통해 데이터를 공유하여 연동할 수 있었기에 워치도 이와 같은 방법으로 구현할 수 있으리라 생각하고 쉽게 생각하였다.
하지만 워치의 경우 iOS App의 Data Store 부분과 Watch App의 Data Store 부분이 완전히 분리되어 있어 위젯처럼 데이터 공유를 할 수 없다.
따라서 다른 방법을 이용해서 iOS와 워치 간의 데이터를 동기화시킬 수 있도록 해야헀다.
그 방법이 바로 Watch Connectivity이다.
Watch Connectivity
iOS 앱과 페어링 된 watchOS 앱 간의 양방향 통신을 구현합니다.
- 공식문서 Watch Connectivity
Watch Connectivity은 WCSession 객체를 통해 통신을 진행하며 WCSessionDelegate 대리자를 위임받아 기능을 작성할 수 있다.
❗️공식문서에서 실기기로 테스트하라는 말을 자주 볼 수 있다고 한다. 따라서 테스트는 실기기로 테스트하기를 권장한다. 이 사실을 모르고 시뮬레이터로 연습 코드를 실행하면서 데이터 연동이 안 됐다 됐다 이상해서 오류 인가 하고 시간을 많이 잡아먹었는데 시뮬레이터의 문제였다..
플러스 마이너스 버튼을 누르면 카운터가 증감되는 간단한 앱을 워치와 핸드폰을 연동시켜 보면서
WCSession으로 데이터를 주고받아볼 예정이다.
WCSession 사용 방법
- 먼저 WCSession.default를 (init) 통해 세션을 얻고
- delegate를 설정한 후
activate()
메서드를 호출하여 세션을 활성화 - 데이터 송수신을 위한 함수를 작성
- 세션의 상태는
activationState
프로퍼티를 통해 확인 가능 isReachable
프로퍼티를 통해 현재 다른 장치가 도달 가능한 상태인지 확인 가능- 데이터를 수신하려면, WCSessionDelegate 프로토콜의 메서드를 구현해야 함.
예를 들어,session(_:didReceiveMessage:)
메서드를 통해 메시지를 수신하고,session(_:didReceiveUserInfo:)
메서드를 통해 사용자 정보를 수신 가능
IPhone - ViewModel
IPhone의 ViewModel 클래스이다.
import Foundation
import WatchConnectivity
final class ViewModelIPhone: NSObject, WCSessionDelegate, ObservableObject {
@Published var count: Int = 0
var session: WCSession
init(session: WCSession = .default) {
self.session = session
super.init()
self.session.delegate = self
session.activate()
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}
func sessionDidBecomeInactive(_ session: WCSession) {
}
func sessionDidDeactivate(_ session: WCSession) {
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
DispatchQueue.main.async {
self.count = message["count"] as? Int ?? 0
}
}
}
init
- 클래스 안에 WCSession 객체를 선언해 주고 클래스 init 시 세션을 생성해 주었다.
- WCSessionDelegate의 델리게이트를 위임받아 통신한 데이터를 핸들링할 수 있도록 하였다.
session.activate()
를 통해 세션 활성화
WCSessionDelegate 메서드
WCSessionDelegate 프로토콜을 준수하면 ios의 경우 아래 세 가지 함수를 필수적으로 추가해야 한다.
하지만 실제로 사용되지 않을 가능성도 많기 때문에 모두 비어있을 수 있다.
나 또한 사용할 일이 없어 비어 두었다.
session(_:activationDidCompleteWith:error:)
: 세션 활성화가 완료되었음sessionDidBecomeInactive(_:)
: 세션이 현재 Apple Watch와의 통신을 중단할 것임 (ios 만 존재)sessionDidDeactivate(_:)
: 세션이 이전 세션의 모든 데이터를 전달했으며 Apple Watch와의 통신이 종료되었음 (ios 만 존재)
가장 중요한 것은 워치에서 보낸 데이터를 수신하는 함수이다.
session(WCSession, didReceiveMessage: [String : Any])
: 메시지가 도착했음을 대리인에게 알리는 함수이다.- 메시지를 보내는 Send함수에 따라 호출되는 Receive함수가 다르다.
IPhone/ Watch 공통 - 메시지 보내기 - Send
메시지를 보내는 함수는 간단하게 그냥 뷰에서 버튼 액션에 작성해 주었다.
// - 버튼
Button {
vm.count -= 1
vm.session.sendMessage(["count": vm.count], replyHandler: nil) { error in
text = error.localizedDescription
}
} label: {
Text("-")
}
func sendMessage(\_ message: \[String : Any\], replyHandler: ((\[String : Any\]) -> Void)?, errorHandler: ((Error) -> Void)? = nil )
를 통해 즉시 메시지를 전송할 수 있도록 하였다.- [String : Any] 타입의 메시지를 보냈기 때문에 받는 부분의 델리게이트에서도 didReceiveMessage: [String : Any]로 받아주면 된다.
Watch - ViewModel
watch의 뷰모델의 경우 거의 비슷한 형태지만 모습이 조금 다르다.
import Foundation
import WatchConnectivity
final class ViewModelWatch: NSObject, WCSessionDelegate, ObservableObject {
@Published var count: Int = 0
var session: WCSession
init(session: WCSession = .default) {
self.session = session
super.init()
self.session.delegate = self
session.activate()
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
DispatchQueue.main.async {
self.count = message["count"] as? Int ?? 0
}
}
}
필수로 구현해야 하는 델리게이트 메서드가 session(_:activationDidCompleteWith:error:)
뿐이기 때문에 아이폰보다는 짧은 코드이다.
나머지 내용은 아이폰에서 구현한 방식과 동일하다.
Send와 Receive 종류
위에서는 didReceiveMessage - sendMessage를 사용하여 데이터를 주고받았다.
이 외에도 다양한 전송 방식이 있고 이에 따라 받는 함수도 다르게 호출이 된다.
Send
- 메시지 전송
sendMessage(_:replyHandler:errorHandler:)
sendMessage
→ [String : Any] 타입 메시지 전송sendMessageData
→ Data 타입 메시지 전송
- 연결된 장치가 활성 상태일 때 즉시 데이터를 전송할 수 있음
- 백그라운드 전송 불가 (세션이 활성화된 동안에만 메서드 호출 가능
- 사용자 정보 전송
transferUserInfo(_:)
- 메서드를 사용하면, 앱이 백그라운드에 있을 때도 데이터를 전송 가능
- 이 메서드는 주로 작은 크기의 변경 가능한 데이터(Dictionary 타입의 데이터)를 전송하는 데 사용
- 전송된 딕셔너리는 다른 기기의 큐에 들어가 대기하게 되고, 순차적으로 전달됨
- 시뮬레이터에서는 안됨, 실기기 사용해야 함
- 파일 전송
transferFile(_:metadata:)
- 파일 또는 데이터를 전송해 주는 메서드
- 앱이 백그라운드에 있을 때도 파일을 전송 가능 (transferUserInfo(_:)와 거의 동일하지만 파일 전송도 된다는 차이를 가짐)
Receive
- 메시지 받기
session(_:didReceiveMessage:replyHandler:)
→sendMessage
session(_:didReceiveMessageData:)
→sendMessageData
- 사용자 정보 받기
session(_:didReceiveUserInfo:)
- 파일 받기
session(_:didReceive:)
: didReceive file: WCSessionFile
'IOS App Programming > IOS 연습' 카테고리의 다른 글
[iOS] UIKit 과 SwiftUI 의 차이점 - 명령형과 선언형의 차이 (0) | 2024.04.03 |
---|---|
[SwiftUI] 다크모드 대응 ColorScheme (0) | 2024.03.20 |
ActivitiKit 사용해보기(IOS 16.2 이후 업데이트 버전) (0) | 2024.03.13 |
[IOS] URLSessrion을 통해 CLOVA Sentiment API 사용기 (1) | 2024.02.27 |
FCM 푸시알림 사용기3 - 푸시 알림 클릭 핸들링 (0) | 2024.02.21 |