LoginSignup
5
3

More than 3 years have passed since last update.

[iOS14] Home Widget を作りたくて WidgetKit を調査したことまとめ

Last updated at Posted at 2020-12-16

WidgetKit 実装について

iOS 14 から利用可能になった WidgetKit ですが、これまでの Today Widget とは異なる点が多く、戸惑う箇所が多々ありました...。ここでは、調査したことをまとめて、書いておきたいと思います。

主な参考サイト

WidgetKitのUIを作る上で、UIKit (UIView) は使用できる?

WidgetKitでは、UIKitは使用不可です。そのため、画面要素はすべて SwiftUI で作成する必要があります。

既存のTodayWidgetから、UIViewを使い回せたら楽だなと思ったんですが...簡単に事は運べないのでした...。

ちなみに、UIViewRepresentable(UIKitのViewをSwiftUIで利用するためのプロトコル)を実装したViewを、Widget上に置くと、「進入禁止標識」が表示されてしまい、使用できない感じになってます。

preview.png

参考 : ios - Why do some views appear as a red no entry sign in widgets? - Stack Overflow

旧来のTodayWidgetと、WidgetKitの共存は可能?

プロジェクトに両方を含めるのは可能です。アプリでTodayWidgetとWidgetKitの両方を実装していた場合は、以下のようになるようです。

  • iOS13以下の端末 → TodayWidgetが使用できる (WidgetKitは使用できない)
  • iOS14の端末 → TodayWidget, WidgetKit が使用できる

参考 : Today Extensions Deprecated? | Apple Developer Forums

注: 参考サイトには「iOS14の端末では、TodayWidgetは使えない」のようなことも書いてありますが、自分で試したらiOS 14 でも TodayWidget 動作しました。

対応サイズ(Small, Medium, Large)を固定するには? (Smallだけのみとか)

  • Widget の body のところで、supportedFamilies を設定します
// Smallだけに対応する場合
.supportedFamilies([.systemSmall])

// SmallとLargeに対応する場合
.supportedFamilies([.systemSmall, .systemLarge])

参考リンク : WidgetFamily | Apple Developer Documentation

表示サイズ(Small, Medium, Large)に応じて、描画を切り替えるのはどうやって行う?

View の body の中で、Switch文を使って切り替えます。詳しくは↓のリンクを参照ください。

タップ操作は可能?(Widget上にボタンなどを配置可能?)

ボタンなどのコントロールは、機能しません。Viewに配置することは可能ですが、タップしてもイベントが来ないみたいでした。

Widgetタップ時は、カスタムURLを使用して、アプリ本体を起動する動作のみ可能です。

  • WidgetSizeがSmallのときは、Widgetをタップすると、アプリ本体が起動します(これはWidgetのdefaultの動作)。
  • WidgetSizeがMediumかLargeの時は、クリックするViewによって起動URLを変えることが可能です(Viewに対してLinkを設定する)

参考:

ViewにLinkを設定する方法は?

// リンクを設定できます
Link(destination: URL(string: "sample-app-url")!) {
    Text("click to launch app")
}

// 画像にもリンクを設定できます
Link(destination: URL(string: "sample-app-url")!) {
    Image(systemName: "hand.thumbsup.fill")
}

参考:

アプリ本体からのデータ参照はどうやって行う?

  • AppGroup を使って行うのが、定番のようです。このあたりは、Today Widgetの頃から変わらずですね。

参考リンク : Sharing data with a Widget

アプリ本体でデータを更新したとき、Widgetに反映するには?

WidgetCenter を使用します。


//*** アプリ本体側のソースコード ***//

import WidgetKit

// Widgetにデータ更新を通知する
if #available(iOS 14.0, *) {
  WidgetCenter.shared.reloadAllTimelines()
} 

アプリに複数のWidgetがあり、そのうち1つを更新したい時は reloadTimelines(ofKind: "widget-identifier") を使用します。

参考: WidgetCenter | Apple Developer Documentation

Placeholder, SnapShot, Timelineとは何か?

  • Placeholder : 端末の設定の変更時に利用される画面
  • SnapShot : Widget選択画面や、Widgetの初期表示などに使用される画面
  • Timeline : Widgetの画面更新時間を、配列的に指定できる([9:00, 10:00, 11:00]のように)。時間になると、Widgetが再描画される。

IntentTimelineProvider に getSnapshot(), getTimeline() というのがあるので、そこでSnapShot / TimeLineに必要なデータを設定する。

説明が難しい...これに関しては、参考リンクを参照していただくほうが良いと思います。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3