안녕하세요.... 네ㅋ 접니다
애플워치를 찬지 햇수로만 만 4년이 다되가네요 사실은 요새 잘 안찹니다. 참 사연이 많은 시계인데ㅋ
문뜩 이 시계를 집에만 썩혀두기 아깝단 생각이 들어서요 활용해서 무얼 만들어보면 좋겠단 생각이 문뜩 들더라구요
생각해보니 애플워치로도 간단하게 카톡 답장이 가능하지 않습니까?!
따로 워치앱에서 카카오톡 로그인을 해주지 않았는데도 말이쥬
그것은 바로 iOS와 WatchOS간 데이터 공유가 이루어졌기 때문입니다!
그 방법, 지금 공개합니다!

공식 문서
Watch Connectivity | Apple Developer Documentation
Implement two-way communication between an iOS app and its paired watchOS app.
developer.apple.com
(공식 문서를 먼저 읽어보는 것을 추천 드립니다.)
1. Watch Connectivity란?
Watch Connectivity(워치 커넥티비티)는 iOS 기기(아이폰, 아이패드)와 Apple Watch 간의 데이터 통신을 가능하게 하는 프레임워크입니다. 이를 통해 두 기기 간의 데이터 동기화, 메시지 전송, 파일 공유 등이 가능합니다.
2. WCSession
watchOS 앱과 companion iOS 앱 간의 통신을 시작하는 객체
iOS 앱과 watchOS 앱은 실행 도중 특정 시점에서 이 클래스의 인스턴스를 만들고 구성해야 합니다. 양쪽의 세션 객체가 모두 활성화되면, 두 프로세스는 메세지를 주고받으며 통신할 수 있게 됩니다.
/** -------------------------------- WCSession --------------------------------
* The default session is used to communicate between two counterpart apps
* (i.e. iOS app and its native WatchKit extension). The session provides
* methods for sending, receiving, and tracking state.
*
* On start up an app should set a delegate on the default session and call
* activate. This will allow the system to populate the state properties and
* deliver any outstanding background transfers.
*/
/** -------------------------------- WCSession --------------------------------
* 기본 세션은 두 개의 대응 앱
* (즉, iOS 앱과 해당 네이티브 WatchKit 확장) 간의 통신에 사용됩니다. 세션은
* 상태를 보내고, 받고, 추적하는 방법을 제공합니다.
*
* 시작 시 앱은 기본 세션에 대리자를 설정하고
* activate를 호출해야 합니다. 이렇게 하면 시스템이 상태 속성을 채우고
* 미처리된 백그라운드 전송을 전달할 수 있습니다.
*/
세션을 구성하고 활성화시키기
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
3. WCSessionDelegate
WCSession 객체가 보낸 메세지를 수신하기 위한 메서드를 정의하는 델리게이트 프로토콜
protocol WCSessionDelegate
그중 몇가지만 살펴보도록 하겠습니당
3-1. sendMessage(_: replyHandler: errorHandler:)
- 페어링되고 활성화된 기기에 즉시 메시지(데이터)를 전송하고, 설정에 따른 응답을 제어해주는 메서드
- 워치 APP과 아이패드 혹은 아이폰 앱이 둘다 켜져있어야 하는 상황(Foreground 상황에서만 데이터 공유 가능)
- 즉, 둘다 세션이 활성화 된 동안에만 데이터를 공유 받을 수 있음.
파라미터
- message
보내고자 하는 Dictionary 타입의 데이터. 수신하는 기기 쪽에서 받으려는 데이터 타입과 맞게 타입을 지정해주어야함. non-optional 타입의 파라미터
- replyHandler
상대 기기로부터 응답을 받기 위한 응답 핸들러. 답장을 받고 싶지 않다면 nil로 지정
- errorHandler
에러가 발생했을 때 실행되는 블록. 에러 정보를 신경 쓸 필요가 없다면 nil로 지정
3-2. transferUserInfo(_:)
- sendMessage와 마찬가지로 상대 기기에 데이터를 전송해주는 메서드
- 이 메서드를 사용하여 전송된 딕셔너리는 다른 기기의 큐에 들어가 대기하게 되고, 순차적으로 전달됩니다.
- 전송이 시작된 후 앱이 일시 중지 혹은 종료가 되더라도 전송 작업은 계속됩니다. (백그라운드에서도 전송 가능)
open func transferUserInfo(_ userInfo: [String : Any] = [:]) -> WCSessionUserInfoTransfer
파라미터
- userInfo
보내고자 하는 Dictionary 타입의 데이터, 수신하는 기기 쪽에서 받으려는 데이터의 타입과 맞게 타입을 지정해주어야함.
!!!!!!!!!!진짜 중요!!!!!!!!
공식문서를 보니 Simulator로는 해당 메서드를 지원하지 않는다고 되어있더라구여? 공식 문서를 흘깃 봐서 못보고 째끔 삽질했읍니다..

4. 예제코드
iOS Code
import SwiftUI
import WatchConnectivity
class iOSDataManager: NSObject, WCSessionDelegate, ObservableObject {
@Published var count: Int = 0
@Published var text: String = ""
var session: WCSession
override init() {
self.session = WCSession.default
super.init()
session.delegate = self
session.activate()
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: (any Error)?) {
}
func sessionDidBecomeInactive(_ session: WCSession) {
}
func sessionDidDeactivate(_ session: WCSession) {
}
func sendCount() {
let message = ["count": count]
session.sendMessage(message, replyHandler: nil) { error in
print("Error sending message: \(error.localizedDescription)")
}
}
func sendTransfer() {
session.transferUserInfo(["text": text])
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
DispatchQueue.main.async {
if let receivedCount = message["count"] as? Int {
self.count = receivedCount
}
}
}
}
struct ContentView: View {
@ObservedObject var manager: iOSDataManager = .init()
var body: some View {
VStack(spacing: 20) {
Text("Count: \(manager.count)")
Button("increase Count(sendMessage)") {
manager.count += 1
manager.sendCount()
}
Spacer()
.frame(height: 80)
TextField("Enter Name", text: $manager.text)
.textFieldStyle(.roundedBorder)
.frame(width: 300)
Button("transferUserInfo") {
manager.sendTransfer()
}
}
.padding()
}
}
#Preview {
ContentView()
}
WatchOS Code
import SwiftUI
import WatchConnectivity
class WatchDataManager: NSObject, WCSessionDelegate, ObservableObject {
@Published var count: Int = 0
@Published var text: String = ""
var session: WCSession
override init() {
self.session = WCSession.default
super.init()
session.delegate = self
session.activate()
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
func sendCount() {
let message = ["count": count]
session.sendMessage(message, replyHandler: nil) { error in
print("Error sending message: \(error.localizedDescription)")
}
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
DispatchQueue.main.async {
if let receivedCount = message["count"] as? Int {
self.count = receivedCount
}
}
}
// 다른 기기의 세션으로부터 transferUserInfo() 메서드로 데이터를 받았을 때 호출되는 메서드
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
DispatchQueue.main.async {
self.text = userInfo["text"] as? String ?? "nil"
}
}
}
struct ContentView: View {
@ObservedObject var manager: WatchDataManager = .init()
var body: some View {
VStack(spacing: 20) {
Text("Count: \(manager.count)")
Button("increase Count") {
manager.count += 1
manager.sendCount()
}
Text("\(manager.text)")
}
.padding()
}
}
#Preview {
ContentView()
}
시연 영상
결론
OS간 데이터 이동을 간단한 예제 코드로 알아보았다.
난이도도 괜찮게 쉬운편이고 나중에 WatchOS를 만들때 참고 해보면 좋을듯 함!
'iOS' 카테고리의 다른 글
[iOS] 아이폰 검색(Spotlight), 앱과 다른이름이 검색되게 하기 (1) | 2023.11.14 |
---|---|
[iOS] 비공개 앱 배포, Unlisted App Distribution (5) | 2023.09.27 |
[iOS] 네아로(네이버 아이디 로그인) 승인거부 (0) | 2023.02.28 |
[iOS] Apple Appstore 심사거절 - Guideline 2.3.10 - Accurate Metadata (2) | 2022.09.21 |
안녕하세요.... 네ㅋ 접니다
애플워치를 찬지 햇수로만 만 4년이 다되가네요 사실은 요새 잘 안찹니다. 참 사연이 많은 시계인데ㅋ
문뜩 이 시계를 집에만 썩혀두기 아깝단 생각이 들어서요 활용해서 무얼 만들어보면 좋겠단 생각이 문뜩 들더라구요
생각해보니 애플워치로도 간단하게 카톡 답장이 가능하지 않습니까?!
따로 워치앱에서 카카오톡 로그인을 해주지 않았는데도 말이쥬
그것은 바로 iOS와 WatchOS간 데이터 공유가 이루어졌기 때문입니다!
그 방법, 지금 공개합니다!

공식 문서
Watch Connectivity | Apple Developer Documentation
Implement two-way communication between an iOS app and its paired watchOS app.
developer.apple.com
(공식 문서를 먼저 읽어보는 것을 추천 드립니다.)
1. Watch Connectivity란?
Watch Connectivity(워치 커넥티비티)는 iOS 기기(아이폰, 아이패드)와 Apple Watch 간의 데이터 통신을 가능하게 하는 프레임워크입니다. 이를 통해 두 기기 간의 데이터 동기화, 메시지 전송, 파일 공유 등이 가능합니다.
2. WCSession
watchOS 앱과 companion iOS 앱 간의 통신을 시작하는 객체
iOS 앱과 watchOS 앱은 실행 도중 특정 시점에서 이 클래스의 인스턴스를 만들고 구성해야 합니다. 양쪽의 세션 객체가 모두 활성화되면, 두 프로세스는 메세지를 주고받으며 통신할 수 있게 됩니다.
/** -------------------------------- WCSession --------------------------------
* The default session is used to communicate between two counterpart apps
* (i.e. iOS app and its native WatchKit extension). The session provides
* methods for sending, receiving, and tracking state.
*
* On start up an app should set a delegate on the default session and call
* activate. This will allow the system to populate the state properties and
* deliver any outstanding background transfers.
*/
/** -------------------------------- WCSession --------------------------------
* 기본 세션은 두 개의 대응 앱
* (즉, iOS 앱과 해당 네이티브 WatchKit 확장) 간의 통신에 사용됩니다. 세션은
* 상태를 보내고, 받고, 추적하는 방법을 제공합니다.
*
* 시작 시 앱은 기본 세션에 대리자를 설정하고
* activate를 호출해야 합니다. 이렇게 하면 시스템이 상태 속성을 채우고
* 미처리된 백그라운드 전송을 전달할 수 있습니다.
*/
세션을 구성하고 활성화시키기
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
3. WCSessionDelegate
WCSession 객체가 보낸 메세지를 수신하기 위한 메서드를 정의하는 델리게이트 프로토콜
protocol WCSessionDelegate
그중 몇가지만 살펴보도록 하겠습니당
3-1. sendMessage(_: replyHandler: errorHandler:)
- 페어링되고 활성화된 기기에 즉시 메시지(데이터)를 전송하고, 설정에 따른 응답을 제어해주는 메서드
- 워치 APP과 아이패드 혹은 아이폰 앱이 둘다 켜져있어야 하는 상황(Foreground 상황에서만 데이터 공유 가능)
- 즉, 둘다 세션이 활성화 된 동안에만 데이터를 공유 받을 수 있음.
파라미터
- message
보내고자 하는 Dictionary 타입의 데이터. 수신하는 기기 쪽에서 받으려는 데이터 타입과 맞게 타입을 지정해주어야함. non-optional 타입의 파라미터
- replyHandler
상대 기기로부터 응답을 받기 위한 응답 핸들러. 답장을 받고 싶지 않다면 nil로 지정
- errorHandler
에러가 발생했을 때 실행되는 블록. 에러 정보를 신경 쓸 필요가 없다면 nil로 지정
3-2. transferUserInfo(_:)
- sendMessage와 마찬가지로 상대 기기에 데이터를 전송해주는 메서드
- 이 메서드를 사용하여 전송된 딕셔너리는 다른 기기의 큐에 들어가 대기하게 되고, 순차적으로 전달됩니다.
- 전송이 시작된 후 앱이 일시 중지 혹은 종료가 되더라도 전송 작업은 계속됩니다. (백그라운드에서도 전송 가능)
open func transferUserInfo(_ userInfo: [String : Any] = [:]) -> WCSessionUserInfoTransfer
파라미터
- userInfo
보내고자 하는 Dictionary 타입의 데이터, 수신하는 기기 쪽에서 받으려는 데이터의 타입과 맞게 타입을 지정해주어야함.
!!!!!!!!!!진짜 중요!!!!!!!!
공식문서를 보니 Simulator로는 해당 메서드를 지원하지 않는다고 되어있더라구여? 공식 문서를 흘깃 봐서 못보고 째끔 삽질했읍니다..

4. 예제코드
iOS Code
import SwiftUI
import WatchConnectivity
class iOSDataManager: NSObject, WCSessionDelegate, ObservableObject {
@Published var count: Int = 0
@Published var text: String = ""
var session: WCSession
override init() {
self.session = WCSession.default
super.init()
session.delegate = self
session.activate()
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: (any Error)?) {
}
func sessionDidBecomeInactive(_ session: WCSession) {
}
func sessionDidDeactivate(_ session: WCSession) {
}
func sendCount() {
let message = ["count": count]
session.sendMessage(message, replyHandler: nil) { error in
print("Error sending message: \(error.localizedDescription)")
}
}
func sendTransfer() {
session.transferUserInfo(["text": text])
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
DispatchQueue.main.async {
if let receivedCount = message["count"] as? Int {
self.count = receivedCount
}
}
}
}
struct ContentView: View {
@ObservedObject var manager: iOSDataManager = .init()
var body: some View {
VStack(spacing: 20) {
Text("Count: \(manager.count)")
Button("increase Count(sendMessage)") {
manager.count += 1
manager.sendCount()
}
Spacer()
.frame(height: 80)
TextField("Enter Name", text: $manager.text)
.textFieldStyle(.roundedBorder)
.frame(width: 300)
Button("transferUserInfo") {
manager.sendTransfer()
}
}
.padding()
}
}
#Preview {
ContentView()
}
WatchOS Code
import SwiftUI
import WatchConnectivity
class WatchDataManager: NSObject, WCSessionDelegate, ObservableObject {
@Published var count: Int = 0
@Published var text: String = ""
var session: WCSession
override init() {
self.session = WCSession.default
super.init()
session.delegate = self
session.activate()
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
func sendCount() {
let message = ["count": count]
session.sendMessage(message, replyHandler: nil) { error in
print("Error sending message: \(error.localizedDescription)")
}
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
DispatchQueue.main.async {
if let receivedCount = message["count"] as? Int {
self.count = receivedCount
}
}
}
// 다른 기기의 세션으로부터 transferUserInfo() 메서드로 데이터를 받았을 때 호출되는 메서드
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
DispatchQueue.main.async {
self.text = userInfo["text"] as? String ?? "nil"
}
}
}
struct ContentView: View {
@ObservedObject var manager: WatchDataManager = .init()
var body: some View {
VStack(spacing: 20) {
Text("Count: \(manager.count)")
Button("increase Count") {
manager.count += 1
manager.sendCount()
}
Text("\(manager.text)")
}
.padding()
}
}
#Preview {
ContentView()
}
시연 영상
결론
OS간 데이터 이동을 간단한 예제 코드로 알아보았다.
난이도도 괜찮게 쉬운편이고 나중에 WatchOS를 만들때 참고 해보면 좋을듯 함!
'iOS' 카테고리의 다른 글
[iOS] 아이폰 검색(Spotlight), 앱과 다른이름이 검색되게 하기 (1) | 2023.11.14 |
---|---|
[iOS] 비공개 앱 배포, Unlisted App Distribution (5) | 2023.09.27 |
[iOS] 네아로(네이버 아이디 로그인) 승인거부 (0) | 2023.02.28 |
[iOS] Apple Appstore 심사거절 - Guideline 2.3.10 - Accurate Metadata (2) | 2022.09.21 |