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

## WidgetKit 実装について

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

### 主な参考サイト

* [Creating a Widget Extension | Apple Developer Documentation](https://developer.apple.com/documentation/widgetkit/creating-a-widget-extension)
* [【iOS14】Widget(WidgetKit) まとめ - Qiita](https://qiita.com/shiz/items/309349d9cdb75084e74e)

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

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

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

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

![preview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13070/9d46d3ec-55fd-a8e2-7127-2570bcb9be9c.png)


参考 : [ios - Why do some views appear as a red no entry sign in widgets? - Stack Overflow](https://stackoverflow.com/questions/63135404/why-do-some-views-appear-as-a-red-no-entry-sign-in-widgets) 
 

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

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

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

参考 :  [Today Extensions Deprecated? | Apple Developer Forums](https://developer.apple.com/forums/thread/650350)

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

### 対応サイズ(Small, Medium, Large)を固定するには？ (Smallだけのみとか)
 
* Widget の body のところで、supportedFamilies を設定します

``` 
// Smallだけに対応する場合
.supportedFamilies([.systemSmall])

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


参考リンク : [WidgetFamily | Apple Developer Documentation](https://developer.apple.com/documentation/widgetkit/widgetfamily) 
 
 
### 表示サイズ(Small, Medium, Large)に応じて、描画を切り替えるのはどうやって行う？

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

* [swift - iOS 14 Widgets: How to create different layouts for each sizes of widgets? - Stack Overflow](https://stackoverflow.com/questions/63246450/ios-14-widgets-how-to-create-different-layouts-for-each-sizes-of-widgets)


### タップ操作は可能？（Widget上にボタンなどを配置可能？）

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

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

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

参考:

* [swift - How to add Buttons to a iOS 14 Widget - Stack Overflow](https://stackoverflow.com/questions/62665936/how-to-add-buttons-to-a-ios-14-widget)
* [widgetURL(_:) | Apple Developer Documentation](https://developer.apple.com/documentation/swiftui/view/widgeturl(_:))

### 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")
}
```

参考: 

* [【iOS14】iOSアプリにウィジェットを導入する【WidgetKit】 - Qiita](https://qiita.com/bu-ka/items/6e5672181a418db03490#%E8%A4%87%E6%95%B0%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF)


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

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

参考リンク : [Sharing data with a Widget](https://useyourloaf.com/blog/sharing-data-with-a-widget/)

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

WidgetCenter を使用します。

``` Swift

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

import WidgetKit

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

```

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

参考: [WidgetCenter | Apple Developer Documentation](https://developer.apple.com/documentation/widgetkit/widgetcenter)


### Placeholder, SnapShot, Timelineとは何か？

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


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

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

* [【iOS14】Widget(WidgetKit) まとめ #viewを提供するコード - Qiita](https://qiita.com/shiz/items/309349d9cdb75084e74e#view%E3%82%92%E6%8F%90%E4%BE%9B%E3%81%99%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89)