Add configuration and intelligence to your widgets
영상 링크 → 링크
Meet WidgetKit 정리 → 링크
함께 보면 좋은 문서 → Making a Configurable Widget
Intro
이 영상에선 위젯을 Configurable하게 만드는 방법과 Configurable한 위젯이 어떻게 시스템을 더욱 영리한 방식으로 작동하는데 도움을 줄 수 있는지에 대해 알아볼 것이다.
다음은 영상에서 살펴볼 예제 앱이다.
카드별 결제 내역을 보여주는 앱으로 최근 결제 내역
, 납부일 및 납부해야 할 총 금액
을 나타내는 두 가지 위젯을 제공한다.
이번 영상에서 다룰 주제의 목차는 다음과 같다.
- The Basics
- Types of data entry
- Configuration experience
- System intelligence
제일 먼저 위젯에 설정을 추가하는 방법을 살펴볼 것이다. 그 다음으로 사용자에게 입력하도록 요청할 수 있는 정보의 유형에 대해 설명하고, 앱의 데이터로 인터페이스를 채울 수 있는 방법을 살펴볼 것 이다.
이후엔 어떻게 위젯의 제목, 설명을 지정하고 배경색을 설정할 수 있는지에 대해 살펴볼 것이다. 마지막으론 스마트 스택에서 시스템이 여러분이 개발한 위젯이 노출되어야 할 시간을 보다 더 정확하게 예측할 수 있도록 설정을 추가하는 방법에 대해 살펴볼 예정이다.
The Basics
위젯이 설정 가능하다면 위젯 뒷면에 사용자에게 입력을 요청할 수 있는 옵션들을 지정할 수 있고, 시스템은 이를 사용자에게 보여줄 것이다. 이런 옵션, 즉 사용자가 정보를 입력할 수 있는 요소들을 파라미터라고 한다.
예제 앱에선 Card
파리미터와 Category
파라미터를 지정하여 사용자가 원하는 카드의 원하는 카테고리의 최근 결제 내역을 위젯에 보여줄 수 있다.
이런 파라미터를 정의하기 위해 Siri
와 Shortcut
에서 사용하고 있는 Intent
를 사용한다. Intent
에 추가한 파라미터는 위젯에 하나의 행으로 사용자에게 보여진다.
Xcode에서 Intent Definition 파일을 통해 Intent
를 선언할 수 있다. 이 파일에는 Intent
와 더불어 그들의 파라미터 등도 포함된다. 이 파일을 통해 시스템은 Intent
의 정보를 읽을 수 있다.
Intent
를 정의하면 Xcode는 정의한 Intent
와 이에 포함되는 파라미터를 프로퍼티로 갖는 클래스를 생성한다.
이 클래스의 인스턴스는 런타임 중 위젯 익스텐션에 전달되며 이를 통해 위젯은 사용자가 무엇을 설정했고 사용자에게 무엇을 보여주어야 하는지를 알 수 있다.
Types of data entry
위젯 설정에선 다양한 데이터 타입을 지원한다.
String
타입의 파라미터를 지정하면 설정 화면은 텍스트 필드를 보여줄 것이고, Boolean
타입의 파라미터는 스위치를 보여줄 것이다.
그리고 숫자는 Int
타입의 파라미터는 스테퍼를, Decimal
타입의 파라미터는 슬라이더를 지원한다.
또한 설정 화면은 연락처 선택과 Location
타입의 파라미터를 위한 위치 선택 UI도 제공한다.
설정 화면은 열거형도 지원하는데, 정적 열거형과 동적 열거형을 통해 이를 활용할 수 있다. 여기서 동적 열거형이란 사용자마다 차이가 있을 수 있는 앱의 사용자 데이터를 의미한다. (사용자가 추가한 카드(Card
)는 앱을 사용하는 사용자마다 달라질 수 있다.) 동적 옵션은 아래에서 더 자세히 살펴보도록 하자.
설정 화면은 위에서 언급한 것들 말고도 다수의 타입을 각각의 고유한 UI로 지원한다.
- Date components
- Duration
- URL
- Measurement
- Currency amount
- Payment method
또한 파라미터는 다수의 값을 가질 수 있으며, iOS 14에서 Intent는 고정된 크기의 배열을 지원한다. 이를 통해 정의된 갯수만큼의 아이템만 배열에 들어갈 수 있게 지정할 수 있다.
그리고 위젯의 크기에 따라 이 갯수를 별도로 지정해줄 수 있다.
영상의 06:43 ~ 09:39 구간에선 기본적으로 Intent Definition 파일에 Intent와 그의 파라미터를 입력하는 방법을 보여주고 있다.
Dynamic Options and Search
Dynamic Options
많은 경우, 위에서 언급한 사용자가 등록한 카드와 같이 위젯 설정에서 보여주고 싶은 데이터는 사용자마다 달라질 수 있다. 그리고 이런 유형의 데이터는 Intent Definition 파일에서 지정해줄 수 없다.
대신 Intent Definition 파일에서 Dynamic Options
체크박스를 체크하면 동적 옵션을 활성화할 수 있다.
이렇게 동적 옵션을 활성화하면 위젯 설정 화면에서 원하는 값을 직접 입력할 수 있는 대신 사용자가 선택할 수 있는 값을 검색하기 위해 앱에 요청해야 한다는 사실을 시스템에 알리게 된다. 이렇게 동적 옵션을 활성화하면 두 가지가 발생한다.
첫째, 위젯의 뒷면(설정 화면)의 동적 옵션이 활성화된 파라미터의 UI가 옵션의 목록을 보여주는 모달을 여는 버튼 모영으로 변경된다.
둘째, 여러분의 앱에서 구현해야 할 두 가지 메서드가 생성되는데, 하나는 선택 가능한 옵션을 제공하는 메서드, 나머지 하나는 기본 값을 제공하는 메서드이다.
이 메서드들은 Xcode가 생성해주는 Intent Handler 프로토콜의 일부이다. 여러분은 앱이나 Intent
익스텐션에서 이 프로토콜을 채택하는 클래스를 생성해야 한다. 이 클래스는 사용자가 위젯을 설정할 때 선택 가능한 옵션을 제공하기 위해 시스템에 의해 사용된다.
예제 앱에선 아래와 같이 선택 가능한 카드의 목록과 기본 선택 카드를 위의 메서드 구현을 통해 제공하고 있다.
선택 가능한 옵션을 제공하는 메서드를 사용하면 단순 리스트 형태로 옵션을 제공하거나 그룹화된 리스트 형태로 옵션을 제공할 수 있다.
아래는 그룹화된 리스트 형태로 옵션을 제공한 모습이다.
Search
기본적으로 상단의 검색 바는 여러분이 제공한 옵션을 필터링하는 역할을 한다. 몇몇의 경우 옵션이 리스트에 한번에 보이지 않을 정도로 많을 때 검색을 활용할 수 있다.
이를 위해 Intent handler provides search results as the user types
체크박스를 활성화해야 한다. 또한 Prompt Label
(검색에 도움을 줄 수 있는?)을 제공할 수도 있다.
Intent handler provides search results as the user types
체크박스를 활성화하면 선택 가능한 옵션을 제공하는 메서드는 searchTerm
파라미터를 추가로 받게 된다.
처음 사용자가 리스트를 마주하면 이 메서드가 호출될 때 searchTerm
은 nil
로 전달된다. 그리고 이후에 사용자가 타이핑을 하기 시작하면 이 메서드는 입력된 문자열과 함께 다시 호출될 것이다.
Configuration experience
이번엔 위젯의 설정 화면의 외형을 커스터마이징 해보자.
먼저 설정 화면의 제목과 설명을 configurationDisplayName
변경자와 description
변경자를 이용해 각각 지정해줄 수 있다.
background와 accent 색상 역시 별도로 지정해줄 수 있다.
이를 위해선 먼저 위젯 익스텐션의 에셋 카탈로그에 색상의 이름과 함께 색상을 추가해야 한다.
그리고 이렇게 추가된 색상과 색상의 이름을 위젯 익스텐션의 build settings에서 각각 Global Accent Color Name
과 Widget Background Name
에 지정해주면 된다.
그리고 설정 화면에서 특정 파라미터의 값을 기반으로 다른 파라미터를 보여주거나 숨기고 싶을 수 있는 경우가 생길 수 있다.
위의 예제를 통해 두 파라미터의 관계를 살펴보면 Mirror Calendar App
을 끄면, Calendar
파라미터가 나타나 어떤 캘린더가 보여야 하는지 수동으로 선택할 수 있어야 한다.
이를 위해 Intent Definition 파일
에서 Calendar
파라미터를 선택 후 Mirror Calendar App
파라미터를 Parent Parameter
로 지정해주면 된다.
그리고 Mirror Calendar App
이 false
일 때만 Calendar
가 보여야 하기 때문에 Show If Parent
를 has exact value
로, Value
를 False
로 지정해야 한다.
System intelligence
위젯은 단순히 하나만 배치할 수도 있지만 스택안에서 여러 위젯을 관리할 수 있다. 그리고 이 스택을 통해 적절한 타이밍에 특정 위젯을 최상단으로 올려 사용자에게 매번 적절한 위젯을 보여줄 수 있다. 이렇게 시스템이 적절한 타이밍과 위젯을 고르는데 영향을 미치는 것이 바로 intelligence, 즉 지능이다.
이번 챕터에선 다음의 두 가지 물음에 대해 살펴볼 예정이다.
- How do stacks behave intelligently?
- How can i appear at just the right time?
첫 스택 지능을 구현하는 기본 설계 원리를 살펴보고 여러분이 개발한 앱을 이번에 새롭게 등장한 홈 스크린 경험(스택)의 일부에 포함시키기 위해선 어떻게 새 API들을 구현해야 하는지를 살펴볼 것이다.
How do stacks behave intelligently?
어떤 것이 좋은 스마트 스택을 만들수 있을까?
스택은 사용자에게 분명한 가치를 적절한 타이밍에 한눈에 볼 수 있는 정보를 제공해야 한다.
예를 들어 뇌우가 오고 있다는 사실을 앱이 안다면 사용자에게 단순히 온도를 주기적으로 갱신해주는 것보다 뇌우가 오고 있다는 사실을 알려주는 것이 더 직관적이다.
시스템은 위젯을 올릴 때 두 가지 요인에 기반한다.
첫 번째는 사용자 행동 기반(behavior-based)이다. 시스템은 사용자가 특정 시간에 주로 찾는 정보를 제공하는 위젯을 해당 시간에 위로 올린다. 날씨 앱을 자주 들여다보는 사용자에겐 날씨 앱을 위로 올려 사용자가 이를 통해 날씨 정보를 빠르게 찾을 수 있도록 한다.
두 번째는 여러분의 앱이 제공하는 관련성 정보(relevant information)이다. 예를 들어 날씨 앱의 경우 뇌우가 왔을 때 위젯이 이를 시스템에 매우 관련성이 높은 정보가 있음을 알릴 수 있으며, 스택은 이를 통해 위젯을 위로 올릴지를 결정한다.
How can i appear at just the right time?
시스템이 위젯을 올리는데 필요한 정보를 제공하는데 사용할 수 있는 API들에 대해 살펴보도록 하자.
Behavior-based
먼저 행동 기반 요인에 영향을 줄 수 있는 API에 대해 살펴보자.
iOS 12에서 등장한 Shortcuts와 사용자 정의 Intent donations를 통해 여러분의 앱에서 사용자가 무엇을 했는지 시스템에 알릴 수 있게 되었다. 그리고 시스템은 이 정보를 바탕으로 Spotlight에서 그 다음 행동을 예측 및 추천할 수 있다. iOS 14에서 시스템은 동일한 정보를 바탕으로 언제 여러분의 위젯을 위로 올릴 것인지를 결정한다.
예제 앱에서 사용자가 앱에서 특정 카드를 확인했을 때 이 사실을 시스템에 알릴 건데, 이를 Intent donation을 통해 시스템에 알릴 것이다. 내부적으로 이게 어떻게 동작하는지 알아보기 전에 먼저 이를 위한 세팅을 하는 법에 대해 살펴보자.
먼저 기존의 Intent Definition 파일에서 Intent is elligible for Siri Suggestions
항목을 활성화한다.
해당 항목이 활성화되면 아래 Suggestions
필드가 추가된다. 우린 사용자가 앱에서 특정 카드를 확인했을 때 해당 카드의 내역을 보여주도록 구성된 위젯을 상단으로 올려야 하기 때문에 Supported Combinations
에 card
파라미터를 추가해야 한다.
이렇게 설정을 마쳤고, 앱에서 사용자가 카드를 확인했을 때 이 사실을 시스템에 알릴 수 있도록(donate) 코드를 작성해주어야 한다.
예제 앱에서 사용되는 ViewRecentPurchasesIntent
를 생성하고 여기에 현재 사용자가 확인한 Card
인스턴스를 담아 이를 donate
하는 코드이다. 위에서 Supported Combinations
에 Card
파라미터만 추가했기 때문에 Category
파라미터를 추가해도 시스템은 Card
만 고려한다.
그럼 시스템이 이를 통해 어떻게 동작하는지를 살펴보도록 하자.
사용자가 식료품 가게에선 정오에 AcmeCard로 주로 결제하고 저녁은 주로 SoupPay로 결제한다고 했을 때 donate된 정보를 바탕으로 시스템은 각각 AcmeCard는 정오에, SoupPay는 저녁에 사용된다는 사실을 알 수 있기 때문에 카테고리에 상관없이 AcmeCard로 구성된 위젯을 정오에 위로 올릴 것이다.
만약에 Supported Combinations
에 Category
를 추가하고 Intent
에 Category
를 함께 donate한다면 시스템은 사용자가 명확하게 AcmeCard와 Groceries 카테고리로 설정한 위젯만 위로 올릴 것이다. 즉 Supported Combinations
은 시스템과 소통하는 방법이다.
위의 과정을 요약하자면 아래와 같다.
Relevant Information
이번에 살펴볼 API는 앱에서 중요하고 관련된 정보가 생겼을 때 시스템이 해당 위젯을 위로 올리는데 사용되는 API다.
먼저 Timeline을 간략하게 살펴보면, WidgetKit을 사용하여 다양한 시점에서 위젯의 모양을 결정하는 Timeline을 제공할 수 있다.
또한 최근 구매 내역과 같이 구매가 발생했을 때 각각에 해당하는 entry를 제공함으로써 위젯이 이를 사용해 실시간으로 새 정보에 반응할 수 있다.
예제 앱에서 사용자가 $50 이상의 구매가 발생하면 알람을 받기 원한다고 가정했을 때, 어떻게하면 시스템에게 예제 앱 위젯이 관련성 높은 정보($50 이상의 구매가 발생)를 갖게 되었다고 알릴 수 있을까?
TimelineEntryRelevance
객체를 TimelineEntry
와 함께 제공함으로써 이런 정보를 시스템에 전달할 수 있다.
TimelineEntry
는 세 가지 요소로 이루어져 있다. Date
는 이 entry가 언제 랜더링되어야 하는지를 나타내고, View
는 랜더링되어야 할 뷰를 의미한다. 그리고 이 entry의 연관성을 나타내는 Relevance
는 TimelineEntryRelevance
객체로 score
와 duration
프로퍼티를 갖는다.
score
를 먼저 살펴보자면, score
는 과거에 제공된 모든 entry들과 비교했을 때 이 entry가 얼마나 연관되어 있는지를 나타낸다. 시스템은 다른 entry들과 관련하여 score
만을 고려하기 때문에 범위와 스케일은 정의하기에 달려 있다. 예외적으로 0과 그 이하의 score
는 시스템에게 현재 위젯이 관련 정보를 갖고 있지 않고, 위로 올라오지 말아야 한다고 알리는데 사용된다.
예제 앱으로 돌아와서 우리가 의도한대로 동작하기 위해 $50 이상의 구매가 발생했을 때는 1, 최근 구매 내역이 없으면 0 그리고 이외의 구매 내역은 0.1로 score
로 지정해보자. 이렇게 score
를 지정하면 사소한 구매 내역에 대해선 위젯이 올라올 수 있는 기회가 적지만 대신 굵직한 구매 내역은 확실한 우선순위를 갖을 수 있다.
다른 위젯들이 제공하는 score
는 상관없음을 기억하자. score는 오로지 여러분이 제공한 score
랑만 비교된다.
이번엔 결제 금액을 score
로 사용해보자. 이를 통해 특정 금액을 넘는지 아닌지가 아닌 결제 금액에 따른 우선순위가 정해진다.
score
를 살펴보았고 이제 duration
을 살펴보자.
duration
은 잘 정의된 일정 시간동안 관련성 점수(score
)를 고정할 때 사용된다. 그렇지 않으면 duration
을 0으로 두면 된다. 이는 관련성 점수가 다음 TimelineEntryRelevance
가 수신될 때 까지만 지속된다는 것을 의미한다.
다은 duration
을 활용한 예제이다.
농구 게임의 진행 상태를 알려주는 위젯으로 게임 시작 전에는 score
를 0으로 지정하고 게임이 시작하면 score
를 1로 지정하고 이를 게임이 진행되는 동안 고정하기 위해 duration
을 3시간으로 지정하였다.
그리고 게임이 진행되는동안 관련성 점수에 영향을 미치지 않도록 TimelineEntryRelevance
를 nil
로 두고 TimelineEntry
를 갱신할 수 있다.
스택의 지능(intelligence)에 정리해보자.
우린 스마트 스택을 이용해 특정 위젯을 스택의 최상단으로 올릴 수 있는 기회를 갖는다. 이를 가능하게 하는 방법은 다음 두 가지다.
- Donate
INIntents
that match your configuration intent (User behavior-based) - Provide
TimelineEntryRelevance
for important information (Relevance information)