iOS14のウィジェットのテンプレートをIntentConfigurationで作る。

iOS14で追加になったウィジェットのテンプレートをIntentConfigurationで作ります。
("ウィジェットを編集"メニューが表示される方)
できるだけXcodeの自動生成を使います。
テンプレートなので何の機能もありませんが、ウィジェットを量産するときの基礎になることを期待しています。

# Appの作成
まだUIKitで作っているアプリがほとんどだと思うので、`UIKit App Delegate` を選択しています。
名前はクレジットカードアプリを想定して`LeaderCard`にしました。:relaxed:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/4b2d8c7c-aef3-715d-7bbd-a02155b01c43.png)

# Widget Extensionの作成
ここの`+`を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/2a139a81-9fc1-839e-e8d2-550c9389e00b.png)

Widget Extensionを選択して`Next`を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/29aeb168-26eb-86b7-2e5c-37f1b50e0a09.png)

`Include Configuration Intent`にチェックを入れる。(←ここ大事！)
チェックを入れないと`StaticConfiguration`になります。
Widget名は`LeaderCardWidget`にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/dbcb89fc-6edd-b2bc-a7b6-cdb48f79f8dd.png)

# Intent Handlerの作成
ここの`+`を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/8c3469be-9df4-3545-9e30-64dc3facc7c7.png)

Intents Extensionを選択して`Next`を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/d77d859d-9a4e-d929-8ae6-8261cb174fac.png)

`Include UI Extension`をチェックしない。(←ここ大事！)
`Starting Point`は`None`を選択。(←ここ大事！)
Intent Handler名は`LeaderCardIntent`にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/1c790365-b4e2-d517-202e-062a6b892006.png)

# intentdefinitionの設定
`LeaderCardWidget`フォルダーの中に生成されている`LeaderCardWidget.intentdefinision`を開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/34decf94-d6bb-4dec-75a2-f4f0b72c7244.png)
下方にある`+`を押して`New Type`を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/c31db5cb-2339-e6e9-af93-065347149df1.png)
タイプ名に`Card`を設定する。`Card`の中身は触らなくても良いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/b55fe12a-d042-b669-8a0b-690e05b2724e.png)
## Parameters
下図のように設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/35e2b117-5a6b-92f8-b790-213ea8ef5c8d.png)

### Parameter
Parameterは小文字で`card`と設定する。(←ここ大事！)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/9a6c874b-1a57-18a8-59f9-6df6b4747d24.png)
自動生成されるクラス`ConfigurationIntent`のプロパティ名になっているからです。

### Display Name
ここで指定した文字列は下図の場所で表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/29d0054f-b89d-b780-0b23-da1216e6ee1e.png" width="320">

### Type
`Card`を選択する。

### Configurable
チェックする。

### Dynamic Options
チェックする。

### Prompt Label
ここで指定した文字列は下図の場所で表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/82f7a4fd-81df-efe1-76dd-9ba89ed63f99.png" width="320">

## Target Membership
`LeaderCardWidgetExtension`と`LeaderCardIntent`にチェックする。(←ここ大事！)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/589314ae-8490-3cd7-321c-20bfce11c50a.png)

# Intent Handlerを最低限コーディングする
初期状態

```swift:IntentHandler.swift
class IntentHandler: INExtension {
    
    override func handler(for intent: INIntent) -> Any {
        // This is the default implementation.  If you want different objects to handle different intents,
        // you can override this and return the handler you want for that particular intent.
        
        return self
    }
    
}
```

`ConfigurationIntentHandling`プロトコルを追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/485c61f2-5396-1a9a-a1d6-c0ef8f3f1e9b.png)
そうすると、`protocol stub`を追加するか聞かれるので`Fix`を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/d661e747-fddc-1007-5df3-2acf96d2b0c7.png)
`provideCardOptionsCollection`メソッドが追加される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/23dbd496-a6bf-4468-cfdb-811eb16ea38f.png)

`code`の部分に`completion(nil, nil)`を書く。
(テンプレートなので何も機能しないです。)

```swift:IntentHandler.swift
class IntentHandler: INExtension {
    func provideCardOptionsCollection(for intent: ConfigurationIntent, with completion: @escaping (INObjectCollection<Card>?, Error?) -> Void) {
        completion(nil, nil)
    }
    
    override func handler(for intent: INIntent) -> Any {
        // This is the default implementation.  If you want different objects to handle different intents,
        // you can override this and return the handler you want for that particular intent.
        
        return self
    }
    
}
```

# 完成
これでテンプレートが完成したはずです。
実行すると以下のような画面が表示されます。
これに肉付けして目的のウィジェットに近づけていくことになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/ac75183d-7e55-0b56-d0b2-68e115bfcd2c.png)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/85ec50c5-5bba-b9d5-bab8-f1ae284e9d9d.png" width="320">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/2fd661ab-7905-c431-70f1-f6df396353d4.png" width="320">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/83411eae-5010-89c6-a5fc-7e3d03b03fd3.png" width="320">


#GitHub
こちらに`Template repository`を作っておりますので、よろしければご利用ください。
[iOS14-Widget-IntentConfiguration-template](https://github.com/hackenbacker/iOS14-Widget-IntentConfiguration-template)

# 開発環境
* Xcode 12.1
* iOS 14.0 - 14.1