개인프로젝트에 WidgetExtension을 도입하면서 처음 만들어보는 Widget에서 많은 멘붕을 겪었다.
이 글을 통해 아래 사항들을 정리해보았다.
1.Widget 만드는 방법
2.메인 앱 데이터를 Widget으로 전달하는 방법
3.Widget Provider를 활용하여 API 호출방법
4.변경사항을 Widget 동기화 방법
👉 애플 공식문서-Widget 만들기
이번 포스팅은 StaticConfiguration 기준으로 설명합니다.
File > New > Target에 따라 WidgetExtension을 추가해준다. | Live Activity, Configuration App Intent를 추가해서 사용할 수 있다.체크를 둘다 해제하면 Static Configuration 기본으로 사용하게 된다. |
---|
AppIntent Configuration 예시위젯 편집을 통해서 사용자에게 옵션을 설정하게 할 수 있도록 제공한다. | AppIntent Configuration 예시위젯편집 기능이 있다면 AppIntent Configuration 예시이다 | Static App Intent 예시정보만을 나타내며, 위젯편집이 없다 |
---|
Live Activity - 잠금화면, 다이나믹 아일랜드에 화면 및 기능을 사용한다.
이제 WidgetExtension을 추가하면 아래처럼 폴더가 생성되며
StaticConfiguration 기준 2개의 파일이 생성된 것을 볼 수 있습니다.
그리고 아래 Frameworks에는 WidgetKit이 생성된것도 볼 수 있네요.
먼저 Bundle 파일을 보면 Widgetextension() 하나만을 가지고 있는데요.
만약 여러가지 유형의 위젯을 추가하고 싶다면 Bundle에 넣어주면 됩니다.
(카카오톡에는 내프로필 위젯, 즐겨찾기 위젯, 캘린더 위젯처럼 다양한 유형의 위젯이 존재하며, 이를 Bundle에 넣어주면 되겠죠?)
다음은 위젯의 핵심인 Widgetextension 파일을 보면 크게 4가지로 분류가 됩니다
위젯의 모든 동작을 담당하며, 3가지 핵심 함수가 존재합니다.
위 코드 기준, placeholder 예시 | placeholder 예시, 데이터 받아오기 전까지 위젯의 간략한형태를 보여준다 placeholder 예시 | getSnapshot을 통해 데이터를 받아온 후 예시getSnapshot 예시 |
---|
getSnapshot - 데이터를 불러 온 후의 위젯의 이미지를 보여줍니다.
위 코드를 보면 @escaping completion이 존재하며, completion handler가 얼마나 빠르게 동작하냐에 따라서 placeholder -> snapshot으로 화면이 보여지게 됩니다.
예를 들어, 위젯 추가를 위해 위젯 갤러리에서 캘린더를 검색 후 들어가면, placeholder 화면이 먼저 보여지며, getSnapshot 함수 실행 및 completion 결과 호출로 Snapshot 이미지가 보여집니다.
getTimeline - 위젯에 업데이트해서 보여줄 정보 및 업데이트 시간을 설정할 수 있습니다.
위 코드를 보면 SimpleEntry 타입의 entries 배열을 생성하여, 반복문을 통해 1시간 간격으로 entries에 append 해준 후, 마지막에 timeline에 entries를 추가하여 completion handler로 호출 되는 것을 볼 수 있습니다. (SimpleEntry 설명은 Provider 이후에..)
만약 지금이 12시라면 12시부터 16시까지의 (0,1,2,3,4) 시간을 entries에 넣어준거겠죠?
코드를 기준으로 "😀" 넣어주고 있지만, 업데이트 시간에 맞춰서 필요한 정보를 화면에 제공할 수 있습니다.
또한, Timeline(entries: entries, policy: .atEnd) 코드에서 policy는 아래와 같이 3가지로 분류됩니다.
atEnd - 16시 이후에 다시 getTimeline 호출되도록 설정합니다.
after - after 뒤에 date가 보이죠? 어떤 특정한 Date를 설정해서 타임라인을 업데이트 할 수 있습니다. 만약 지금이 금요일 16시 주식시장이라면, after을 사용하여 Date를 월요일로 지정한다면 (토,일)의 불필요한 Reload를 줄일 수 있겠죠?
never - 16시 이후에 getTimeline이 실행되지 않으며, WidgetKit을 사용해서 새로운 타임라인을 요청해야합니다. 예를 들자면, WidgetCenter.shared.reloadAllTimelines() 있습니다.
추가적으로, getTimeline 실행으로 12~16시 시간을 가지고 있다고 해서 정확하게 정각에 작동되지는 않으며, 약간 뒤에 업데이트 될 수 있습니다. (Note that the widget’s view might not be updated precisely at a timeline entry’s date and time; the update might occur later.)
그렇다면 여기서 문제 🤔
왜 이렇게 getTimeline을 통해서 업데이트 해주는거지?
그냥 계속 보여주면 되자나? 의 답변은 링크로 들어가면 자세하게 나와있숩니다..
답에 대한 핵심 문구만 가져왔습니다.
Reloading widgets consumes system resources and
causes battery drain due to additional networking and processing.
To reduce this performance impact and maintain all-day battery life,
limit the frequency and number of updates you request to what’s necessary.
Provider를 통해 위젯 핵심기능 3가지를 다뤄봤는데요.
이제는 TimelineEntry 프로토콜을 따르는 SimpleEntry를 살펴보겠습니다.
TimelineEntry: A type that specifies the date to display a widget, and, optionally, indicates the current relevance of the widget’s content.
결국, SimpleEntry는 TimelineEntry 프로토콜을 따르며,
Date와 사용자가 원하는 content를 위젯의 화면으로 보여줄 수 있습니다.
위의 코드를 보면 emoji: String으로 Provider에서는 "😀" 담아주고 있지만,
여기에 원하는 타입으로 바꿔서 위젯에 보여주고자 하는 정보를 넣어줄 수 있습니다.
struct SimpleEntry: TimelineEntry {
let date: Date
let number: Int // 예를 들어 number를 통해 숫자를 넣어줄 수 있습니다.
}
실제로 위젯 화면에서 보여주고자 하는 화면을 만들 수 있는 전형적인 SwiftUI View 모습입니다.
widgetFamily 사용하여 위젯의 크기에 [small,medium,large] 따라서 보여주고 싶은 위젯화면을 설정해 줄 수 있습니다.
(기본 default View) entry(SimpleEntry)를 통해서 date와 emoji "😀"를 화면에 보여줍니다. | widgetFamily - Switch문 사용을 통해 원하는 위젯 View를 설정 할 수 있습니다. |
---|
Widget 프로토콜을 따르고 있으며, body 또한 WidgetConfiguration 타입으로 이루어져 있습니다.
WidgetConfiguration은 결국 맨 처음 말했던 StaticConfiguration / AppIntent Configuration이라 볼 수 있습니다
현재 코드에서는 Static으로 되어 있지만, 아래처럼 AppIntentConfiguration을 사용한다면 intent가 추가 되는 모습을 볼 수 있습니다. intent를 통해서 위젯 편집 기능처럼 사용자가 옵션을 설정 하도록 할 수 있습니다.
AppIntentConfiguration(kind: String,
intent: WidgetConfigurationIntent.Protocol,
provider: AppIntentTimelineProvider) { TimelineEntry in
}
이렇게 Widget을 만드는 방법을 알아보았습니다.
다음에는 2.메인 앱 데이터를 Widget으로 전달하는 방법 을 정리해서 포스팅하겠습니다.
참고자료
https://developer.apple.com/documentation/widgetkit/creating-a-widget-extension
https://matdongsane.tistory.com/149
https://ios-development.tistory.com/1131
https://velog.io/@stealmh/Swift-Widget%EC%9C%84%EC%A0%AF-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0
https://yoo-kie.tistory.com/27
https://gyuios.tistory.com/102
https://eunjin3786.tistory.com/212