2015年9月21日月曜日

tvOSの所感

秋に発売される New Apple TVで、サードパーティにもアプリが作れるようになりました。
tvOS とは、そのApple TVのSDKになります。

一体何ができるのか、どんな感じなのか?というのを見てみたので、一般公開されている内容を元に書いてみたいと思います。

Apple TVに向いてそうなアプリ

やっぱり、TVなので..... 画像がないと寂しいです。

画像をみせつつなにかするとしたら、やっぱり通販系がいいのかなと。
服、CD、本 などを売ってみたりとか。
TVショッピングを見ている人々をターゲットに。
Appleが代金支払部分のシステムを提供してくれたらいいのにー。

あとはゲーム。
レスポンスみながらどこまで作り込めるか...にもよりますが。
単純なものだったら、複数人でできるとよさそう。

が、あの小さなリモコン。基本の操作はあのdpad。
こまかな操作はかなり難しいと思います。
操作はシンプルに...

アプリの作成方法は2種類

1. TVJSとTVMLを使ってClient-Serverアプリ

tvOSにはUIWebViewが使えません。
その代わり(?)的に使える方法が、JSとTVMLを使う方法です。

TVJSは、JSの中で使えるものが限定されたセット。
→  TVJS Framework Reference

TVMLは、HTMLに変わるAppleTV専用マークアップと考えればOK。
テンプレートが幾つか用意されていてそれに合った形のUIを考えていく必要あり。
→ Apple TV Markup Language Reference - Templates

ネイティブアプリも必要ですが、最初の画面となるURLを設定するぐらい。
TVJSと、TVMLは自社サーバーに配置します。

iOSを知らない、ましてやObjectiveC/Swiftを知らない人でも簡単に作れそうです。
また、テンプレートが用意されているので、できることが限られている反面、UIデザインに自信がない人でも気軽にできる気がする。

そういう人を狙いましたよ! というのがビンビン伝わってきます(笑
わざとWebViewを提供せずに、UIを統一したいのだろうかと思ったりも....。

2. ネイティブアプリ

もちろん、今までどおり、ObjectiveC/Swiftでゴリゴリ書くことも可能。
ただ、Frameworkは制限されています。
Flaskでよく使っている、HealthKit, EventKitは無いので残念!
ゲームで使うSpriteKit,SceneKitも入っています。


容量は限られている

アプリは200MB以内でないといけない。
デバイスに保存された情報は、次回起動時に存在する保証はないから、iCloudを使ってねと。
→  iCloud Storage

NSUserDefaults.standardUserDefaults() をためしてみたら、データの保存はできている模様。
だけど、永続化されている保証はないということか?!

iCloudって試してみたのは随分昔なもので、あまりすんなり動かないイメージなんですが、今は安定して使えるのだろうか?


UIはフォーカスがキモ

TV用のインターフェースを考える際に重要なのがフォーカス。
フォーカスを移動してから、タップして選択というのが操作の基本なので。
このイメージはAppleTV だけでなく、PlayStationとか、dボタンおした時の表示とかでも経験あるかと。

性質上、UICollectionViewを使うことが多いと思うのですが、普通に使うと、どのセルにフォーカスがあるのかは分からない状態に。

そこで、使えるのが、UIImageView#adjustsImageWhenAncestorFocused
このプロパティをtrueにすると、フォーカスがあたったら自動的にちょっと大きくなり、影などの効果も追加されます。
(ImageViewサイズより大きくなるのでUIImage#clipsToBoundsをfalseにする必要あり)

Imageについてはこれで簡単!なのですが、Labelなどには無いことに注意。
CollectionViewのCellの中に文字を表示形式だと、画像が大きくなるのに文字は大きくならないというアンバランスになります。
文字は画像の下に置く。フォーカスがあるときのみ文字を表示する。
などの工夫が必要そうです。

フォーカスが当たったタイミングは、
UIFocusEnvironment#didUpdateFocusInContext で取得可能。
UIFocusEnvironmentはUIViewControllerやUIViewで実装されているので、UI系のクラスならどのクラスでも取得できるはず。

ちなみにUICollectionView#didHighlightItemAtIndexPath はCallされません!
didFocusItemAtIndexPath のようなものを提供してくれると嬉しかったのですが。

このフォーカス有無での表示関連は、TVMLを使っていたらある程度自動的にいい感じにしてくれてそうで楽な予感。


入力イベント

AppleTVではTouchとTapの種類がある。
ちょっとややこいが、詳細はおいておいて、取得できる方法を。

UITapGestureRecognizer
UISwipeGestureRecognizer
は使える

もう少し低レベルのAPIでPress系のものも用意されている

func pressesBegan(presses: Set, withEvent event: UIPressesEvent?) 
func pressesChanged(presses: Set, withEvent event: UIPressesEvent?)
func pressesEnded(presses: Set, withEvent event: UIPressesEvent?)

名前が示しているようにPresssの状態の時=Tapの時がとれる。
Touchの状態のものはとれない。

UIPress には、typeと phase というプロパティがあり、どのボタンが開始されたのか?を取得できる。
タッチパッドの右、左、上、下というのも取れる。

pressした状態で左右に動かした時というのをとってみたかったのだが、
pressesChanged がなぜかイベントが飛んでこなかった。
操作がわるいのか....SDKのバージョンアップによって変わる?

他の取得方法は、GCController を使えます。
GCControllerとは、外部のゲームコントローラーとの接続を管理するクラス。
Apple TV Remote(コントローラー)は、GCControllerとして検出できます。
GCControllerのdpadにvalueChangedHandlerを登録すれば、タッチパッド上の指の動き..Touch,Tap両方状態ともに...を検知できます。
(シミュレータでは動きません)
この実装はAppleのSampleの DemoBot が参考になります。

参考までに、XCodeのシミュレーターのApple TV Remoteでは、Remoteの画面をActiveにした状態でOptボタンを押しながらマウスポインタを画面上で動かすとTouchの動きになります。(マウスをPressする必要なし)


iPhoneの接続

CoreBluetoothを使ってiPhoneと接続ができる。
が、どうやら2台までらしい。
それ以上の時はBonjour使えとー。


UIScrollView

UIScrollViewの中に画像を置いて、ズーム可能な配置にしても、AppleTVではズーム出来なかった。そういうもんなのか?!
関連 : stackoverflow - UIScrollView on tvOS



• • •