티스토리 뷰
최근 회사에서 Watch App을 만들게 되어 열심히 만들고 있다.
Watch App을 간단히 살펴 보자면
- 이전에는 UIKit으로도 만들 수 있었는데, 이제는 SwiftUI로 안만들 이유가 없을 듯 하고,
- 폰에서 데이터 전송이 대부분 필요할텐데, shared UserDefaults 가 아닌 Watch Connectivity를 통한 전달이 필요하다.
UIKit만 바라보던 나는 미뤄두던 SwiftUI를 이참에 공부를 했고 (이건 신세계..)
Watch Connectivity에 대해 공부를 했었다.
본 포스트에서는 개념보다는 WatchApp을 만들어 가면서 만났던 이슈에 대해 정리를 해보려고 한다.
1. Watch OS 버전
개발을 위해 회사에서 지급받은 워치5는 무려 9.6.3 버전이다. (23년 9월 21일 출시 버전)
사용하고 있던 Xcode 14.2 에서는 빌드가 되지 않았다..!
(OS on the device is incompatible with the installed version of Xcode)
만약 아이폰이라면 DFU 모드에서 OS를 강제로 다운 시킬 것이다. 애플워치도 같은 방법이 있을까? 해서 찾아보았는데


당장은 불가능해 보인다
- watchOS 9.6.3 Device Support 는 존재하지 않음
- Xcode 14.3 이후 부터는 CoreDevice 방식으로 변경되었기 때문 !
Xcode 메이저 버전을 올리는 것은 굉장히 큰일이지만,
어차피 해야 할 일이기 때문에 브런치를 따로 파서 버전을 올렸고 오류는 사라졌다. (인줄 알았지만)
2. Watch Extension은 어디에?
잠시 헷갈렸던 부분인데 공식문서에 잘 설명이 되어있었다.

Xcode 14 이전에는 WatchKit App과 WatchKit Extension으로 두가지 타겟으로 나뉘어져 있었다고 한다.
어쩐지, 자료들을 찾아볼 때는 WatchExtension이 target에 추가되어 있었는데, 나는 없어서 잠시 혼돈이 왔었다.
공식 문서에 따르면 Xcode 14부터는 각 섹션이 하던 일이 WatchKit App 단일 타겟으로 통합이 되었다.
그리고 이전 버전의 개발자들을 위해 합치는 작업을 지원한다고 하다.
3. Cycle inside ... 오류
이 오류는 빌드가 아닌 아카이브때 났던 오류이다.
나의 경우는 실기기 빌드는 잘 되었는데, 아카이브 할 때만 오류가 났었다
https://developer.apple.com/forums/thread/731287
Xcode 15에서의 버그인 것 같기도 하다.

위 애플 개발자 포럼의 내용처럼 Build Phase 순서를 바꿔서 해결이 되었다.
Embed Found Extensions 를 Copy Bundle Resource 다음으로 올렸다. (이후 Run Script)
(Embed Found Extensions - Run Script - Copy Bundle Resource ... )
Xcode 15에서 새로운 링커가 적용이 된다고 하는데, 그것과 관련이 있는 버그였을까?
Build Phase에 대해 따로 공부를 해봐야 겠다.
4. didReceiveApplicationContext 데이터 전송 안됨
이번에 개발하는 워치 앱에서는 지속적인 데이터 전송 형태는 아니고,
iOS에서 전송하는 여러 데이터들 중 가장 최신의 데이터만을 필요로 한다.
- 워치가 백그라운드, 포그라운드 상관없이 가장 최신의 데이터만을 수신처리하는 context를 사용하기로 했다.
그런데 context가 수신이 될 때도 있고, 안될때도 있는 것이다.
굉장히 많이 헤멧고 삽질도 많이 했다.
껏다가 켰다가 초기화했다가 Xcode 버전 올렸다가 .. 등등..
상당히 혼란스러웠는데 침착하려고 했다.
isPaired: true,
isReachable: true,
phone Watch Connectivity status: active
watch Watch Connectivity status: active
1. 위 조건이라면 Connectivity가 작동을 안할 상황은 아니다.
2. 휴대폰에서 데이터 전송은 아주 잘 수행하고 있다. (error == nil)
3. 그렇다면 데이터를 전송하는 중간에 없어진다?
(그래도 엄청 헤멧다)
삽질 끝에 찾은 원인은 OS의 개입이였다.
결론적으로 이전에 보낸 데이터와 동일한 데이터를 전송할 경우에는 (추정: 배터리 절약을 위해) OS에서 차단한다는 내용이다.
그래서 didReceiveApplicationContext에서 수신을 하지 못했던 것이다.
지속적인 데이터 전송을 위한다면 Date() 를 함께 보내거나, 보낼때마다 UUID를 생성해 보내면 된다. (애플이 싫어할듯)
공식문서를 많이 읽어보았지만... 개인적으로 이 내용에 대한 설명은 조금 더 필요하지 않을까 싶다.
차단되었을 때 디버그 메시지라도 보내주면 좋았을텐데 !!
Use the updateApplicationContext(_:) method to communicate recent state information to the counterpart. When the counterpart wakes, it can use this information to update its own state. For example, an iOS app that supports Background App Refresh can use part of its background execution time to update the corresponding Watch app. This method overwrites the previous data dictionary, so use this method when your app needs only the most recent data values.
updateApplicationContext(_:) 메소드를 사용하여 최근 상태 정보를 상대방에게 전달합니다. 상대방이 깨어났을 때 이 정보를 사용하여 자신의 상태를 업데이트할 수 있습니다. 예를 들어 백그라운드 앱 새로 고침을 지원하는 iOS 앱은 백그라운드 실행 시간의 일부를 해당 Watch 앱을 업데이트하는 데 사용할 수 있습니다. 이 메소드는 이전 데이터 사전을 덮어쓰므로 앱에 가장 최근 데이터 값만 필요할 때 이 메소드를 사용합니다.
내용을 알고 보니 관련된 글 몇몇개가 보였다.
그 중에는 공식문서에는 이런 내용이 없는데? 라는 내용도 보인다.
- 무려 6년전의 글이라 구글링을 엄청 했음에도 읽지 않았던 것 같다. 심지어 잘 설명되어 있었음.
- WC Session 문서
https://developer.apple.com/documentation/watchconnectivity/wcsession
- didReceiveApplicationContext 문서
https://developer.apple.com/documentation/watchconnectivity/wcsessiondelegate/1615619-session
- updateContext 문서
여러 글들이 이전부터 꾸준히 올라왔음을 보니, 내가 이 이슈를 너무 어렵게 생각했던 것 같다.
디버그의 문제라던가, 버전 이슈 등등으로 생각 했었고, 단순한 부분을 놓쳤었다.
--
이렇게 새로운 워치앱을 개발하는데 벌써 다양한 이슈들을 많이 만났고, 삽질을 많이 하게 되어 글로 정리를 해보았다.
(결론: SwiftUI를 얼른 공부해야겠다(?))
'iOS' 카테고리의 다른 글
| [iOS] 오픈소스 기여를 해보았다. (2) | 2024.01.04 |
|---|---|
| [iOS] DateFormatter 연도가 잘못 나올 때(주 기반 연도, YYYY) (2) | 2024.01.02 |
| [iOS] FLO 앱 만들기(5) - 자동으로 스크롤 되는 가사 TableView (1) | 2023.10.21 |
| [iOS] FLO 앱 만들기(4) - Seek 뷰와 기능 만들기 (0) | 2023.10.20 |
| [iOS] FLO 앱 만들기(3) - AVPlayer의 상태값 받아오기(KVO) (0) | 2023.10.16 |
- Total
- Today
- Yesterday
- watch connectivity
- Xcode15
- 맥북에어 m4
- flo
- Swift
- highprioritygesture
- swift날짜
- string catalog
- swiftui 제스처
- ios 다국어
- Github action
- open-api-generator
- easy cue
- demical
- ios채팅
- ios웹소켓
- swift audio
- audiokit
- AVFoundation
- onTapGesture
- openapi-generator
- self-hosted-runner
- IOS
- SwiftUI
- DateFormatter
- avplayer
- 애플워치 데이터 전송
- keyboardtype
- audio kit
- swiftui 탭
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 29 | 30 | 31 |