WatchKit を実際に

さわってみてわかったこと
堤 修一 @shu223

2015.2.14 iOS オールスターズ勉強会
自己紹介
• 堤 修一(つつみ しゅういち)
自己紹介
• 堤 修一(つつみ しゅういち)
• iOS専業フリーランス
自己紹介
• 堤 修一(つつみ しゅういち)
• iOS専業フリーランス
• ブログ『Over&Out その後』
自己紹介
• 堤 修一(つつみ しゅういち)
• iOS専業フリーランス
• ブログ『Over&Out その後』
• 著書『iOSアプリ開発 達人のレシピ100』
自己紹介
• 堤 修一(つつみ しゅういち)
• iOS専業フリーランス
• ブログ『Over&Out その後』
• 著書『iOSアプリ開発 達人のレシピ100』
• GitHub
- iOS7-Sampler
- iOS8-Sampler
自己紹介
• 堤 修一(つつみ しゅういち)
• iOS専業フリーランス
• ブログ『Over&Out その後』
• 著書『iOSアプリ開発 達人のレシピ100』
• GitHub
- iOS7-Sampler
- iOS8-Sampler
自己紹介
2014.11.19
WatchKit ベータ公開
WatchKit ベータ公開
• クラスはたったの15個!
WatchKit ベータ公開
• クラスはたったの15個!
• あれもない、これもない。
WatchKit ベータ公開
• クラスはたったの15個!
• あれもない、これもない。
ドキュメントをさらっと見て、
サンプル動かして、
WatchKit ベータ公開
• クラスはたったの15個!
• あれもない、これもない。
ドキュメントをさらっと見て、
サンプル動かして、
「あんまりできること
なさそうだねー」
WatchKit ベータ公開
• クラスはたったの15個!
• あれもない、これもない。
ドキュメントをさらっと見て、
サンプル動かして、
「あんまりできること
なさそうだねー」
で終了
2015.2
とある WatchKit 案件
とある WatchKit 案件
数日間実際に触ってみた
とある WatchKit 案件
数日間実際に触ってみた
• 意外とよくわかってなかったところがたくさん!
とある WatchKit 案件
数日間実際に触ってみた
• 意外とよくわかってなかったところがたくさん!
• 意外とできることは多い
アジェンダ
アジェンダ
「WatchKit を実際にさわってみてわかったこと」

 を雑多に紹介します
アジェンダ
「WatchKit を実際にさわってみてわかったこと」

 を雑多に紹介します
1. アニメーション編
アジェンダ
「WatchKit を実際にさわってみてわかったこと」

 を雑多に紹介します
1. アニメーション編
2. テキスト入力編
アジェンダ
「WatchKit を実際にさわってみてわかったこと」

 を雑多に紹介します
1. アニメーション編
2. テキスト入力編
3. UIのカスタマイズ編
アジェンダ
「WatchKit を実際にさわってみてわかったこと」

 を雑多に紹介します
1. アニメーション編
2. テキスト入力編
3. UIのカスタマイズ編
持ち時間(20分?)で話せるところまで。。
※
Appleの公開資料(ログイン不要領域より閲覧およびダウンロード可能)の
範囲で発表します
• Apple Watch Human Interface Guidelines(UIガイドライン)
• WatchKit Programming Guide(プログラミングガイド)
• WatchKit Framework Reference(APIリファレンス)
• WatchKit Catalog(サンプルコード)
• Lister(サンプルコード)
• WatchKit特設サイト: https://www.apple.com/jp/watch/ (画像・動画等)
予備知識:
WatchKit のアーキテクチャ
• 親アプリは WatchKit Extension を持つ
• 親アプリは WatchKit Extension を持つ
• WatchKit Extension に書いたコードは基本的に
iPhone 側で実行される
• 親アプリは WatchKit Extension を持つ
• WatchKit Extension に書いたコードは基本的に
iPhone 側で実行される
• WatchKit App (ウォッチ側)は基本的に表示だけ
例)WKInterfaceImage
例)WKInterfaceImage
例)WKInterfaceImage
• UIImage オブジェクトの生成は iPhone 側で行われる
例)WKInterfaceImage
• UIImage オブジェクトの生成は iPhone 側で行われる
• setImage: を実行すると、引数に渡したUIImageオブ
ジェクトをウォッチ側に転送し、表示する
iPhone Watch画像
例)WKInterfaceImage
例)WKInterfaceImage
例)WKInterfaceImage
• 引数に渡した名前の画像リソースが WatchApp 側に
あれば、それを表示する
バンドル内にある
画像を表示
iPhone Watch文字列
例)WKInterfaceImage
• 引数に渡した名前の画像リソースが WatchApp 側に
あれば、それを表示する
• 転送するのは名前だけなので速い
バンドル内にある
画像を表示
iPhone Watch文字列
1. アニメーション編
Static なアニメーション
Static なアニメーション
WatchKit App の Asset Catalog 内の連番画像(=Static なリソース)
を使用
Static なアニメーション
WatchKit App の Asset Catalog 内の連番画像(=Static なリソース)
を使用
Static なアニメーション
WatchKit App の Asset Catalog 内の連番画像(=Static なリソース)
を使用
• setImageNamed: と
startAnimatingWithImagesInRange∼ がポイント
Static なアニメーション
WatchKit App の Asset Catalog 内の連番画像(=Static なリソース)
を使用
• setImageNamed: と
startAnimatingWithImagesInRange∼ がポイント
• WatchKit Extension の Asset Catalog にリソースがあってもダメ
メッチャ速い
これは10fps、もっといける。
Dynamic なアニメーション
Dynamic なアニメーション
WatchKit App の Asset Catalog にない画像(=
Dynamic なリソース)を使用
Dynamic なアニメーション
WatchKit App の Asset Catalog にない画像(=
Dynamic なリソース)を使用
• setImageNamed: や
startAnimatingWithImagesInRange∼ が使え
ない
Dynamic なアニメーション
WatchKit App の Asset Catalog にない画像(=
Dynamic なリソース)を使用
• setImageNamed: や
startAnimatingWithImagesInRange∼ が使え
ない
• setImage: や setImageData: を使うしかない
Dynamic なアニメーション
WatchKit App の Asset Catalog にない画像(=
Dynamic なリソース)を使用
• setImageNamed: や
startAnimatingWithImagesInRange∼ が使え
ない
• setImage: や setImageData: を使うしかない
- 画像が動的に転送されるので、パフォーマンスの懸念あり
Dynamic なリソースでのアニ
メーションをどう実現するか?
最初に試した方法:
タイマーを利用する(非推奨!)
最初に試した方法:
タイマーを利用する(非推奨!)
最初に試した方法:
タイマーを利用する(非推奨!)
• フレームごとの UIImage を生成して
WKInterfaceImage の setImage: で転送
最初に試した方法:
タイマーを利用する(非推奨!)
• フレームごとの UIImage を生成して
WKInterfaceImage の setImage: で転送
• というのを NSTimer で回す
明らかに遅い
NSTimer にセットしたインターバルは 0.1、つまり10 fps だ
が、明らかに転送か描画が間に合っていない
キャッシュを使う?
キャッシュを使う?
• NO!
キャッシュを使う?
• NO!
• アニメーションをキャッシュすること自体が問題と
いうわけではないが、フレームごとの画像をキャッ
シュするのはやめろとプログラミングガイドに書い
てある。
Dynamic アニメーション
実装方法の正解
Animated Imageを利用する
Animated Imageを利用する
Animated Imageを利用する
Animated Imageを利用する
• UIImage の
animatedImageWithImages:duration: を利用
Staticアニメーションとほぼ同等
(今回試したアニメーションでは感じなかったが、)Animated Imageのサイズ
が大きくなると転送オーバーヘッドが体感でわかるぐらいには出てくるかも。
2. テキスト入力編
アニメーションする3D絵文字
これどうやるのか?WatchKitにAPIはあるのか?
スマートリプライと音声入力
スマートリプライと音声入力
• 同じく、どうやるの?WatchKitにAPIはあるの?
スマートリプライと音声入力
• 同じく、どうやるの?WatchKitにAPIはあるの?
• スマートリプライのフレーズは動的に指定できるの?
3D絵文字や音声入力、ス
マートリプライの実現方法
presentTextInputControllerWith∼
を使うだけ
presentTextInputControllerWith∼
を使うだけ
テキスト入力のインターフェースを表示するメソッド
presentTextInputControllerWith∼
を使うだけ
テキスト入力のインターフェースを表示するメソッド
presentTextInputControllerWith∼
を使うだけ
テキスト入力のインターフェースを表示するメソッド
- 第1引数: suggested phrases を指定
presentTextInputControllerWith∼
を使うだけ
テキスト入力のインターフェースを表示するメソッド
- 第1引数: suggested phrases を指定
- 第2引数: 入力タイプを指定
presentTextInputControllerWith∼
を使うだけ
テキスト入力のインターフェースを表示するメソッド
- 第1引数: suggested phrases を指定
- 第2引数: 入力タイプを指定
- 第3引数: 入力完了後に呼ばれる block
Smart Replies + 音声入力
Smart Replies + 音声入力
Smart Replies + 音声入力
• 第1引数にフレーズの配列、第2引
数に .Plain を渡す
Smart Replies + 音声入力
• 第1引数にフレーズの配列、第2引
数に .Plain を渡す
Smart Replies + 音声入力
• 第1引数にフレーズの配列、第2引
数に .Plain を渡す
• 選択フレーズのリストはスクロール
する
Smart Replies + 音声入力
• 第1引数にフレーズの配列、第2引
数に .Plain を渡す
• 選択フレーズのリストはスクロール
する
• マイクボタンを押すと "Dictation is
not supported in the WatchKit
Simulator
絵文字入力
絵文字入力
絵文字入力
• 第2引数に .AllowEmoji を渡す
絵文字入力
• 第2引数に .AllowEmoji を渡す
絵文字入力
• 第2引数に .AllowEmoji を渡す
• 絵文字ボタンを押すと "Emoji is not
supported in the WatchKit Simulator"
絵文字入力
• 第2引数に .AllowEmoji を渡す
• 絵文字ボタンを押すと "Emoji is not
supported in the WatchKit Simulator"
• マイクボタンを押すと "Dictation is
not supported in the WatchKit
Simulator”
アニメーション絵文字
アニメーション絵文字
アニメーション絵文字
• 第2引数に .AllowAnimatedEmoji を
渡す
アニメーション絵文字
• 第2引数に .AllowAnimatedEmoji を
渡す
アニメーション絵文字
• 第2引数に .AllowAnimatedEmoji を
渡す
• 絵文字ボタンを押すと "Emoji is not
supported in the WatchKit Simulator"
アニメーション絵文字
• 第2引数に .AllowAnimatedEmoji を
渡す
• 絵文字ボタンを押すと "Emoji is not
supported in the WatchKit Simulator"
• マイクボタンを押すと "Dictation is not
supported in the WatchKit Simulator”
おまけ:音声入力だけ
おまけ:音声入力だけ
おまけ:音声入力だけ
• 第1引数は nil、入力モードは Plain
おまけ:音声入力だけ
• 第1引数は nil、入力モードは Plain
おまけ:音声入力だけ
• 第1引数は nil、入力モードは Plain
• 遷移してすぐに "Dictation is not supported
in the WatchKit Simulator" と出る



→この画面が既に Dictation インターフェー
スになっていると考えられるる
おまけ:音声入力だけ
• 第1引数は nil、入力モードは Plain
• 遷移してすぐに "Dictation is not supported
in the WatchKit Simulator" と出る



→この画面が既に Dictation インターフェー
スになっていると考えられるる
(=ユーザーの操作を1ステップ減らせる)
3. カスタムUI編
(ヒューマンインターフェースガイドラインより)
Core Graphics?
(ヒューマンインターフェースガイドラインより)
Core Graphics?
iOS であれば、Core Graphics とか UIBezierPath で円弧を描画
しつつグラデーションカラーで塗る
(ヒューマンインターフェースガイドラインより)
直接 WatchKit App 上で Core
Graphics 的な描画ができる?
直接 WatchKit App 上で Core
Graphics 的な描画ができる?
→ できません
Apple による正解
Apple公式サンプル『Lister』
Apple公式サンプル『Lister』
Apple公式サンプル『Lister』
1度ずつ、360個切りだされた連番png (!)

がWatch Appのバイナリにあらかじめ入っている!
実装もやはり普通に連番アニメーション
(Listerサンプル)
その他、試してみた

カスタムUI
カスタムフォント
カスタムフォント
• iOS と同様の手順でできるか?
カスタムフォント
• iOS と同様の手順でできるか?
- WatchKit App のバンドルに
フォントファイルを入れる
カスタムフォント
• iOS と同様の手順でできるか?
- WatchKit App のバンドルに
フォントファイルを入れる
- WatchKit App の Info.plist 編集
カスタムフォント
• iOS と同様の手順でできるか?
- WatchKit App のバンドルに
フォントファイルを入れる
- WatchKit App の Info.plist 編集
→ 普通にできた
カスタムフォント
• iOS と同様の手順でできるか?
- WatchKit App のバンドルに
フォントファイルを入れる
- WatchKit App の Info.plist 編集
→ 普通にできた
インターフェースのオーバーレイ
インターフェースのオーバーレイ
• WKInterfaceObject は、

UIView の subview 的にイン
ターフェース同士を重ねられ
ない
インターフェースのオーバーレイ
• WKInterfaceObject は、

UIView の subview 的にイン
ターフェース同士を重ねられ
ない
→ WKInterfaceGroup の

 setBackgroundImage: 

 を活用
インターフェースのオーバーレイ
• WKInterfaceObject は、

UIView の subview 的にイン
ターフェース同士を重ねられ
ない
→ WKInterfaceGroup の

 setBackgroundImage: 

 を活用
origin 調整
origin 調整
• WKInterfaceObject には、
(UIView における) frame.origin
的なプロパティがない
origin 調整
• WKInterfaceObject には、
(UIView における) frame.origin
的なプロパティがない
• UIEdgeInsets 的なものもない
origin 調整
• WKInterfaceObject には、
(UIView における) frame.origin
的なプロパティがない
• UIEdgeInsets 的なものもない
→ WKInterfaceGroup を活用
origin 調整
• WKInterfaceObject には、
(UIView における) frame.origin
的なプロパティがない
• UIEdgeInsets 的なものもない
→ WKInterfaceGroup を活用
• 角丸・・・WKInterfaceGroup にそういうプロパティがある
• 角丸・・・WKInterfaceGroup にそういうプロパティがある
• テーブルセルの高さ変更・・・普通にコンテンツの高さで決まる
• 角丸・・・WKInterfaceGroup にそういうプロパティがある
• テーブルセルの高さ変更・・・普通にコンテンツの高さで決まる
• 38mm と 42mm でレイアウト設定を分ける・・・IBの+ボタンか
ら設定可能
• 角丸・・・WKInterfaceGroup にそういうプロパティがある
• テーブルセルの高さ変更・・・普通にコンテンツの高さで決まる
• 38mm と 42mm でレイアウト設定を分ける・・・IBの+ボタンか
ら設定可能
• 画面に対してn等分になるようInterfaceオブジェクトを設置す
る・・・”Relative to Container”の比率をセットできる(デフォル
トが 1)
• 角丸・・・WKInterfaceGroup にそういうプロパティがある
• テーブルセルの高さ変更・・・普通にコンテンツの高さで決まる
• 38mm と 42mm でレイアウト設定を分ける・・・IBの+ボタンか
ら設定可能
• 画面に対してn等分になるようInterfaceオブジェクトを設置す
る・・・”Relative to Container”の比率をセットできる(デフォル
トが 1)
• WKInterfaceButton のカスタマイズ・・・IB の Content を“Group”
に切り替える(デフォルトは“Text”)
まとめ
• 「WatchKit を実際にさわってみてわかったこと」を
雑多に紹介しました
• 検証サンプルのまとめOSS
- https://github.com/shu223/WatchKitTrials
- 近日公開予定!
告知
iOS ✕ BLE プログラミング

∼ Core Bluetooth 徹底解説 ∼(仮)
という著書が来月(2015年3月)に出る予定ですので、
ぜひよろしくお願いします!
ご清聴ありがとうございました!
• Twitter:@shu223
• Facebook:shuichi.tsutsumi
• GitHub:shu223

WatchKitを実際にさわってみてわかったこと