はじめてのAppleWatchアプリ開発

[qnote Advent Calendar](https://qiita.com/advent-calendar/2019/qnote) の2日目です。

WWDC2019の発表でWatchOS6からAppleWatch単体でもアプリが動作することができるようになりました。
とあるプロジェクトでAppleWatchの開発を行うことになったので、iOSアプリの開発との違いや困ったところなどを残しておこうと思います。
※SwiftUIではありません。
※ある程度iOSの開発経験がある方への説明となります。

# ViewControllerがない！？
初めてAppleWatchを開発することになりプロジェクトを作成したりターゲットに追加して最初に追加されたファイル一覧を見てきっと思います、ViewControllerがないじゃんと。

AppleWatchではUIViewControllerではなくWKInterfaceControllerを使用します。
AppleWatchではUIKitでなくWatchKitを使用して開発を行うため、UIViewControllerは使えません。
代わりにWKInterfaceControllerを使用して開発をします。

ライフサイクルメソッドとしては主に以下のメソッドがあります。

- awake
- willActivate
- didAppear
- willDisappear
- didDeactivate

その他のライフサイクルは[Working with the watchOS App Life Cycle | Apple Developer Documentation](https://developer.apple.com/documentation/watchkit/working_with_the_watchos_app_life_cycle)

##### アプリキル
元々AppleWatchを持っていなかったので基本的な使い方すらわからない状態で開発を始めて、アプリキルの方法すらわからなかったのでそんな方は[こちら](http://iphone.f-tools.net/Apple-Watch/App-Kyousei-Syuuryou.html)にもありますが
1. アプリを開いた状態でサイドボタン（長いボタン）長押し
2. 電源オフ画面でデジタルクラウン（くるくる）長押し
になります。

##### 各ターゲットについて
アプリを作成するとTargetが3つあるかと思います、それぞれの詳細はざっくりと以下の様になります。

|ターゲット|説明|
|:-----------------:|:------------------:|
|(プロジェクト名)|アプリ全体（以下二つ）をまとめたもの|
|(プロジェクト名) WatchKit App|UIに必要な情報や画像等が格納される|
|(プロジェクト名) WatchKit Extension|プログラム等が格納される|

[Setting Up a watchOS Project | Apple Developer Documentation](https://developer.apple.com/documentation/watchkit/creating_independent_watchos_apps/setting_up_a_watchos_project)

# Storyboardでのレイアウトの方法がわからない

AppleWatchではiPhoneのように好きな位置に好きなViewを配置してAutoLayoutで色々して・・・ということができません。
基本的にはTableViewの様に上から順番にViewを並べて表示することくらいしかできません。
（VerticalStackViewが大元にある様なイメージ）
AutoLayoutという概念は捨てましょう。
![image](https://docs-assets.developer.apple.com/published/255d93c849/62e0c963-6834-4162-aa37-7fab50cecebd.png)
![image](https://docs-assets.developer.apple.com/published/32df0d2b76/6d512862-fce7-4dd3-b23f-864bd82cc6c8.png)
※[Building watchOS app Interfaces Using the Storyboard | Apple Developer Documentation](https://developer.apple.com/documentation/watchkit/storyboard_elements/building_watchos_app_interfaces_using_the_storyboard)から引用
横に並べる場合はGroupで囲って対応します。
配置の仕方も大まかな位置やViewのサイズを指定したりして決めます。
Viewの設定もiOSに比べると多くありません。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/dd911bad-dac2-7202-da3a-69a8bca971a3.png)　![label](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/26410191-291d-5cf2-43af-10a444bb19fb.png)
フォントの設定も少なめです

# Tableどうやって使うの・・・？
storyboardにTableを追加するとTableRowControllerというものがあるのでこれがiOSでのCellになります。
Rowをカスタマイズをする場合はNSObjectを継承してクラスを作成して、CustomClassに指定すればRowのクラスになり、Outlet等が接続できるようになります。
WKInterfaceTable自体にはdelegate等はありませんのでiOSでよく使う
numberOfRowsInSectionやcellForRowAtやdidSelectRowAt等がないので、タップした際に遷移する処理等は自分でDelegateを作るかSegueで遷移させるなどの対応が必要になります。
Rowの作成は以下のようになるかと思います。

```swift
let array = ["row1", "row2", "row3"]
table.setNumberOfRows(array.count, withRowType: "CustomRow")
for (i, text) in array.enumerated() {
    let row = table.rowController(at: i) as! CustomRow
    row.label.setText(text)
}
```

# モジュラーアイコンで複数の色があるアイコンを設定する際の注意点
モジュラー（AppleWatchのホーム画面のようなもの）のフルカラー対応
※下図の下段と左上の場所のアイコン
![ss](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/9d2c38ac-b33f-fc7b-b7b7-8cc2c614707b.png)

基本的には背景は表示せずアイコン部分のみ表示するアプリが多いのではないかと思います。（メールや電話等）
ですがどうしても背景付きのアイコンを表示しなければならないことがあるかと思います。
今回開発したアプリも背景付きのアイコンを表示することになりましたので対応方法を残しておきます。

わかりやすい例としてPayPayがありましたので今回挙げさせて頂きます。
現在(2019/11)のPayPayのアイコンは以下の様になっていますがこちらをiOS版のアイコンのようにしてみたいと思います。（何か問題があれば変更しますのお知らせください。）

※参考 PayPayのiOS版アイコン
![image](https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/80/e3/6f/80e36fee-e005-0cd9-dd4c-0a40bcda9698/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/246x0w.png)


**まず基本のアイコンのみ表示する場合です。（単色対応）**

```ComplicationController.swift
    func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
        switch complication.family {
        case .modularSmall:
            let template = CLKComplicationTemplateModularSmallSimpleImage()
            template.imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "complication")!)
            /*
            template.tintColor = .red // 色を変更する場合は色を指定する
            */
            return handler(template)
        default:
            return handler(nil)
        }
    }
```
おそらくこちらでPの部分がalphaで透明になっている画像を指定していると思われます。
色指定の部分は何も行わないとデフォルトで白になります。
（この状態で背景付きのカラーアイコン画像をしてもただ白いアイコンが表示されてしまいますので注意が必要です）

**次に背景付きの場合です。**
少し調査して対応できたのが

1. 背景がカラーでアイコンが白の場合
2. 背景が白でアイコンがカラー

の場合です。
両方カラーは対応ができないかと思いますが、できる場合は教えて頂けると今後開発される方の参考になるかと思います。

```ComplicationController.swift
    func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
        switch complication.family {
        case .modularSmall:
            let template = CLKComplicationTemplateModularSmallSimpleImage()
            let foreground = UIImage(named: "complication_foreground")!
            let background = UIImage(named: "complication_background")!
            template.imageProvider = CLKImageProvider(onePieceImage: foreground,
                                                      twoPieceImageBackground: background,
                                                      twoPieceImageForeground: foreground)
            template.tintColor = .red // 色を変更する場合は色を指定する
            return handler(template)
        default:
            return handler(nil)
        }
    }
```

CLKImageProviderの初期化に画像1枚と画像2枚の2パターンあり、後者を使用してCLKImageProviderを初期化します。
イメージとしては表示領域に2つレイヤーがあるイメージとなります。
tintColorで色を変更できるのは下層のレイヤー（backgroundの方）となります。
（onePieceImageはカラーの選択で単色にした際に表示される画像だと思います）

※背景は丸を前提としています
・背景の色を変更してアイコン部分を白にする場合
backgroundを白丸画像にしてforegroundにアイコンを指定すれば問題なく表示されます。

・背景の色を白でアイコン部分の色を変更する場合
こちらは少し画像を加工しないといけないのですが、
foregroundの画像を白丸にしてアイコン部分をalphaにします。
backgroundはそのままアイコンの画像にします。
この様にすれば問題なく表示されます。

まとめると以下の様になります。

|画像名|背景赤|アイコン赤|
|:-----------------:|:-----------------:|:------------------:|
|complication_foreground|![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/09668325-240c-4e7f-dea5-1483936a2592.png)|![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/2c35e138-4a09-2691-6c89-ee1df8da7e27.png)|
|complication_background|![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/e99e80bb-4ff4-791e-63d5-47210f2d46dc.png)|![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/09668325-240c-4e7f-dea5-1483936a2592.png)|
|tintColor|.red|.red|
|表示|![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/6448a39f-02da-1cd2-9c5a-e7e840fe5b75.png)|![IMG_0276.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149731/9a9d7ce5-ead7-c977-0d00-eab527c008ff.png)|
※白画像のみだとわかりづらいのでalpha部分を黒くしてあります。
※大雑把に加工したので赤アイコンの境界線が黒くなっていますが、Pの部分を少し大きくすれば問題ありません。

# まとめ
iOSは記事やサイトがたくさんありますがAppleWatchについてはあまり多くなく色々とわからないことがありましたが、勉強になったのでやってよかったと思います。
間違い等がありましたらご指摘をお願いいたします。
そしてもっとAppleWatchに対応するアプリが増えるといいなぁ。