[iOS] WatchKit[5] - 예시를 통해 Complication 알아보기

ungchun·2022년 8월 8일
0

WatchKit

목록 보기
5/5
post-thumbnail

제가 진행했던 코드들을 보면서 Complication을 어떻게 핸들링하는지 한번 알아보도록 하겠습니다 ! 앞에 글을 안보고 오셨으면 이해를 하기 어려울 수 있으니 꼭 한번씩 읽어보시고 오시길 바랍니다 !

Watch와 Complication 데이터 공유

데이터를 보여주지않고 앱 아이콘이나 사진같은걸 Complication에 보여주면 넘어가셔도 됩니다.

// InterfaceController
//
class DayInfo {
    static let shared = DayInfo()
    
    var days: String?
    private init() { }   
}

class InterfaceController: WKInterfaceController, WCSessionDelegate {
	...
	override func willActivate() {
    	...
	    DayInfo.shared.days = data
    	...
    }
    ...
}

이 방법이 정확하지는 않을 수도 있지만, 저는 InterfaceController에서 싱글톤을 이용해 데이터를 세팅하고 ComplicationController에서 이 데이터를 이용해서 세팅하니 정상적으로 데이터가 나왔습니다. 더 좋은 방법이 있으시면 댓글 부탁드려요!


Complication Assets

WatchKit Extension -> Assets 에 들어가보면

요렇게 생긴 친구들이 있습니다. 저도 사용해보지는 않았습니다만 예상해보면 CLKComplicationFamily에 맞춘 이미지를 넣으면 해당 Complication에 이미지가 나오지 않을까 예상해봅니다. 예를 들면 앱 아이콘 이미지가 될 수 있겠네요. 이미지를 사용하실 분들은 여기다가 워치 사이즈에 맞게 이미지를 넣어주시면 될 거 같습니다.


ComplicationController

Watch를 추가하고 ComplicationController를 처음 딱 열어보면 많은 메서드들이 반겨줍니다. 하나씩 알아보도록 하겠습니다.

getComplicationDescriptors(handler:)

ClockKit은 이 메서드를 호출하여 앱이 지원하는 컴플리케이션을 결정합니다. 여기서 중요한게 바로 지원하는 CLKComplicationFamily 선택할 수 있습니다.

func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
	let descriptors = [
		CLKComplicationDescriptor(identifier: "complication", displayName: "너랑나랑", 
        	supportedFamilies: [
            	CLKComplicationFamily.modularSmall, CLKComplicationFamily.circularSmall, CLKComplicationFamily.graphicCircular])
		]
	handler(descriptors)
}

supportedFamilies 배열에 본인이 원하는 family 종류를 넣어주시면 됩니다. 만약 모든 케이스를 넣고 싶으시면 .allCases를 넣어주시면 됩니다.

getTimelineEndDate(for:withHandler:)

이 메서드는 업데이트할 날짜를 지정해야합니다. 이걸 구현하지 않으면 ClockKit은 현재 항목 이후를 업데이트하지 않는다고 합니다.

func getTimelineEndDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
	handler(Date().addingTimeInterval(60.0 * 30.0)) // 30분..
}

추가로 컴플리케이션을 백그라운드로 새로 고침을 막 계속 할 수는 없습니다. 애플이 막아놨거든요. WKApplicationRefreshBackgroundTask를 보시면 "컴플리케이션과 함께 각 앱에 대해 시간당 네 가지 작업을 수행합니다. 현재 시계 페이스의 모든 컴플리케이션은 이 예산을 공유합니다. 예산이 소진되면 더 많은 시간을 사용할 수 있을 때까지 시스템에서 요청을 연기합니다." 라고 적혀있네요. remainingComplicationUserInfoTransfers에는 "컴플리케이션이 활성 워치 페이스에 있는 경우 하루에 50번의 전송이 제공됩니다." 라고 적혀있습니다. 사실 컴플리케이션을 초나 분 단위로 업데이트하는 일은 거의 없을거라고 보지만 참고하시길 바랍니다 !

getPrivacyBehavior(for:withHandler:)

ClockKit은 이 메서드를 호출하여 사용자의 Apple Watch가 잠겨 있을 때 정보 표시 데이터를 표시하는 방법을 결정합니다. 손목을 올리고 내릴 때를 핸들링하는 메서드인 거 같습니다. 이 친구도 딱히 건드리지는 않았네요.

func getPrivacyBehavior(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void) {
	handler(.showOnLockScreen)
}

getTimelineEntries(for:after:limit:withHandler:), getTimelineEntries(for:before:limit:withHandler:)

앱의 미래 데이터, 과거 데이터로 타임라인 항목의 배열을 빌드합니다. 라고 적혀있습니다만.. 잘 모르겠네요.. 심지어 애플 공식 예제 파일에도 handler(nil)로 되어있습니다. 이 친구들에 대해 잘 아시는분은 댓글 부탁드릴게요 !

func getTimelineEntries(for complication: CLKComplication, before date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) { 
	handler(nil)
}
    
func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
	handler(nil)
}    

getLocalizableSampleTemplate(for:withHandler:)

컴플리케이션의 샘플 데이터를 표시해줍니다.

저렇게 미리보기 화면에서 어떻게 컴플리케이션이 나타날지 보여주는 메서드입니다. placeholder랑 비슷한 느낌이라고 하면 이해가 편하실 겁니다.

func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
	switch complication.family {
	case .modularSmall:
		let tallBody = CLKComplicationTemplateModularSmallStackImage(line1ImageProvider: CLKImageProvider(onePieceImage: (UIImage(systemName: "heart")?.withTintColor(appMainColorAlaph40))!), line2TextProvider: CLKTextProvider(format: "days"))
		handler(tallBody)
		break
	case .circularSmall:
		let tallBody = CLKComplicationTemplateCircularSmallStackImage(line1ImageProvider: CLKImageProvider(onePieceImage: (UIImage(systemName: "heart")?.withTintColor(appMainColorAlaph40))!), line2TextProvider: CLKTextProvider(format: "days"))
		handler(tallBody)
		break
	case .graphicCircular:
		let tallBody = CLKComplicationTemplateGraphicCircularStackImage(line1ImageProvider: CLKFullColorImageProvider(fullColorImage: (UIImage(systemName: "heart")?.withTintColor(appMainColorAlaph40))!), line2TextProvider: CLKTextProvider(format: "days"))
		handler(tallBody)
		break
	default:
		handler(nil)
		break
	}
}

위에서 설정한 CLKComplicationFamily 종류대로 전부 다 세팅을 해주셔야합니다.

getCurrentTimelineEntry(for:withHandler:)

이 메서드가 메인입니다. 지금 표시하는 데이터를 가지고 컴플리케이션에 보여주는 메서드입니다.

func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
        
	var value = ""
        
	switch complication.family {
	case .modularSmall:
		let tallBody = CLKComplicationTemplateModularSmallStackImage(line1ImageProvider: CLKImageProvider(onePieceImage: (UIImage(systemName: "heart")?.withTintColor(appMainColorAlaph40))!), line2TextProvider: CLKTextProvider(format: DayInfo.shared.days == nil ? "days" : "\(value)"))
		let entry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: tallBody)
		handler(entry)
		break
	case .circularSmall:
		let tallBody = CLKComplicationTemplateCircularSmallStackImage(line1ImageProvider: CLKImageProvider(onePieceImage: (UIImage(systemName: "heart")?.withTintColor(appMainColorAlaph40))!), line2TextProvider: CLKTextProvider(format: DayInfo.shared.days == nil ? "days" : "\(value)"))
		let entry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: tallBody)
		handler(entry)
		break
	case .graphicCircular:
		let tallBody = CLKComplicationTemplateGraphicCircularStackImage(line1ImageProvider: CLKFullColorImageProvider(fullColorImage: (UIImage(systemName: "heart")?.withTintColor(appMainColorAlaph40))!), line2TextProvider: CLKTextProvider(format: DayInfo.shared.days == nil ? "days" : "\(value)"))
		let entry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: tallBody)
		handler(entry)
		break
	default:
		handler(nil)
		break
	}
}

결과

글 정리한다고 공식 문서에 들어가보니 거의 다 Deprecated가 떠있네요.. watchOS 9 기준으로 대대적인 변화가 있을 거 같습니다. 그래도 버전 적용해서 작업하려면 시간이 꽤 걸릴거 같긴 하네요. 이렇게 제가 작업한 내용들을 가지고 watch와 complication에 대해 정리를 한번 해봤습니다. 전부 다 정답이 아닐 수 있습니다.. 제가 몰랐던 부분이나 틀린 부분은 댓글로 달아주시면 수정하겠습니다!

0개의 댓글