Widget Extensionを作る
Published by @SoNiceInfo at 7/5/2020
Widgetを作成するとアプリコンテンツをiOSのホーム画面やmacOSの通知センターに表示することができるようになります。
Widget作成に必要な知識
Widgetの大きさ
Widgetの大きさはsupportedFamiliesで定義され、.systemSmall
(2x2サイズ), .systemMedium
(4x2サイズ), .systemLarge
(4x4サイズ)の3種類があります。
StaticConfigurationとIntentConfiguration
Widgetには大まかに2種類あります。StaticConfiguration
とIntentConfiguration
です。
StaticConfiguration
: ユーザがWidget上で設定を必要としないものに利用。例えば新着ニュースを表示するWidget。IntentConfiguration
: ユーザがWidget上で設定を必要とするものに利用。例えば地域を選択して天気を表示するWidget。
TimelineEntryとTimeline
Widgetはリアルタイムのアップデートをサポートしません。 表示するコンテンツとともに適切な更新間隔を設定してWidgetに提供する必要があります。これを実現するのがTimelineEntryとTimelineの考え方です。TimelineEntry
オブジェクトは以下のようにコンテンツとDate型のdateを持ちます。(今回のコンテンツはInt型のなにかです。) dateにはコンテンツを表示したい日付を格納します。
struct SimpleEntry: TimelineEntry {
var date: Date
var int: Int
}
TimelineはTimelineEntry
オブジェクトの配列です。
Timelineの更新は最後のTimelineEntryを表示したとき(.atEnd
), 指定した時間が経過した後(.after
), アプリからWidgetCenterを利用して更新通知されたら更新する(.never
)の3種類があります。 TimelineはTimelineProvider
に準拠したProvider
によってwidgetsに渡されます。
Snapshot
SnapshotはWidgetのプレビュー機能やWidget Galleryで即座にWidgetを表示するために使われます。 SnapshotはひとつのTimelineEntry
を受け取ります。 Widgetのコンテンツがサーバーから提供されるまではモック的な値を入れておきます。
Provider
Providerは上記TimelineやSnapshotをWidgetに提供するためのオブジェクトです。
StaticConfigurationの場合、TimelineProvider
に準拠したProviderを用意します。
IntentConfigurationの場合、IntentTimelineProvider
に準拠したProviderを用意します。
struct Provider: TimelineProvider {
public typealias Entry = SimpleEntry
public func snapshot(with context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), int: Int.random(in: 1..<100))
completion(entry)
}
public func timeline(with context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let date = Date()
let refreshDate = Calendar.current.date(byAdding: .minute, value: 1, to: date)!
print(refreshDate)
let timeline = Timeline(entries: [SimpleEntry(date: date, int: Int.random(in: 1..<100)), SimpleEntry(date: refreshDate, int: Int.random(in: 1..<100))], policy: .after(refreshDate))
completion(timeline)
}
}
Placeholder
PlaceholderはWidgetの大体の見た目を表示します。.redacted(reason: .placeholder)
とすることで簡単に実装できます。
iOS 14 beta 3 introduces .redacted(reason: .placeholder) to generate a placeholder view of any SwiftUI view
— Jordan Singer (@jsngr) July 23, 2020
Here's a few real examples: https://t.co/m0iOlbMRCa pic.twitter.com/JUIrLdDP2F
kind
kindはそのWidgetを一意に識別するための文字列です。com.example.widget
のようにBundle indentifierのような文字列がいいでしょう。
Widget Extensionを追加する
Widgetは技術的にはアプリに付属するWidget Extensionのことを指します。
File → New → Target...と進みダイアログが表示されたらWidget Extension
を選択します。
IntentConfigurationを使う場合にはInclude Configuration Intentにチェックを入れましょう。
適切なProduct Nameを入力してFinishします。
Activate "PRODUCT_NAME" schemeと聞かれるのでActivateを選択します。
新しいフォルダが作成されPRODUCT_NAME.swift
が作成されています。 これでWidget Extensionを作成する準備は完了です。
Buildする
左上の「Set the active scheme」で作成したWidgetを選択してBuildします。
Xcode 12 betaとiOS SimulatorではIntentConfigurationのWidgetは動きません。修正されるのを待ちましょう。
参考
Creating a Widget Extension | Apple Developer DocumentationWidgets - System Capabilities - iOS - Human Interface Guidelines - Apple Developer