この記事はCyberAgent Developers Advent Calendar 2016の23日目の記事です。
こんにちは。AbemaTVでiOS、tvOSを開発している波戸(@dekatotoro)と申します。最近は黙々とtvOSアプリの開発をしていましたので、今回はiOSアプリ開発者向けにtvOSアプリ開発のポイントについて紹介したいと思います。
AbemaTV on Apple TV
AbemaTVはオリジナルの生放送コンテンツや、音楽、スポーツなど様々な番組を見ることができるインターネットテレビ局です。動画配信サービスなのでTVデバイスと非常に相性が良いものになります。tvOS向けのアプリは先月の11月25日から提供を開始していますので、Apple TVを持っている方は是非使ってみてください。
Apple TV 4th generation
まずApple TVについてです。Apple TVは、第1世代〜第4世代まであるのですが、開発者にtvOS SDKが提供され、Apple TV用アプリの開発・配信ができるようになったのは第4世代からとなります。まずは、Apple TV第4世代の概要について見ていきたいと思います。
第4世代Apple TVは2015年9月に発表されて、2015年10月30日に発売されたので、発売から1年ちょっと経過しています。
スペックは以下のようになっています。CPUはA8 Dual-Coreでメモリが2GBなのでiPhone 6のCPUとiPhone 6sのメモリと同等で、単純に比較はできませんが、iPhone 6とiPhone 6sの中間のスペックくらいでしょうか。
- 64-bit A8 processor
- 32GB or 64GB of storage
- 2GB of RAM
- 10/100Mbps Ethernet
- WiFi 802.11a/b/g/n/ac
- 1080p resolution
- HDMI 1.4
- New Siri Remote / Apple TV Remote
Apple TVに付属するリモコンですが、上部のマットな部分はTouch Surfaceと呼ばれている部分で、Swipe/Touch/Selectができます。物理ボタンとして、Menu、Home、Siri、Play/PauseとVolumeボタンがあります。
開発手法
開発手法は大きく分けて2つあります
-
Traditional Apps
-
Client-Server Apps
Traditional AppsはiOSと同様にUIKitで開発するもので、Client-Server AppsはTVMLやTVJSといったWeb technologyを使って開発する手法になります。今回はTraditional Appsについての内容です。
制限
大きな制限事項としてアプリケーションバンドルのサイズ制限とStorageの制限があります。
tvOSアプリのバイナリサイズは200MBまでとなります。アプリによって大きなリソースが必要な場合はオンデマンドリソースを使う必要があります。
またStorageに関しても以下のような制限があります。
TemporaryDirectoryとCacheDirectoryはOSによって消される可能性があります(アプリケーションの実行中は削除されません)。tvOSではLibraryDirectoryやDocumentsDirectoryが使えないので、RealmやSqliteのようなdatabase fileもCacheDirectoryに保存することになります。purgeされる可能性を考えると、DBはdisk保存じゃなくてonMemoryを検討してもいいかもしれません。
レイアウト
tvOSアプリの画面レイアウトは1920 x 1080の16:9の画面解像度に設計します。画像もiOSみたく@1x, @2x @3xと複数用意する必要はなくtvOS用に@1xの一つだけになります。
全体的なデザインですが、古いTVだと端が見切れて隠れてしまうことがあるので、画面の端は余白を空けておくことが推奨されています。
古いTVなどで端が見切れて隠れてしまう現象は、オーバースキャンとアンダースキャンがあり、テレビやプロジェクター側の設定で調整すると直る場合があります。ただ、ユーザーがなかなか設定できることに気づかないことが多いと思うので、見切れても問題ないように余白を設けたデザインにしたほうが良さそうです。
フォーカスして拡大しても問題ないようにパディングを設けること、大きな要素でもコンテンツを1画面に伸ばさず複数あるというヒントを残すことが推奨されています。
レイアウトに関してはtvOS Human Interface Guidelinesに豊富な例を示してくれているので一読することをおすすめします。
ジェスチャー
リモコンのTouch SurfaceのSwipe/Touch/Selectの操作は、GestureRecognizerやEventで検知できます。
UITapGestureRecognizer
UITapGestureRecognizerはallowedPressTypesにUIPressTypeを指定できます。
-
upArrow
-
downArrow
-
leftArrow
-
rightArrow
-
select
-
menu
-
playPause
upArrow/downArrow/leftArrow/rightArrowはTouch Surfaceを左右上下の位置で軽く触る、selectはTouch Surfaceを押し込む、menu/playPauseは物理ボタンの押下で発生するイベントです。
UISwipeGestureRecognizer
UISwipeGestureRecognizerはUISwipeGestureRecognizerDirectionを指定できます。
- right
- left
- up
- down
Touch Surfaceの左右上下のSwipeの入力イベントになります。
その他にもUIPanGestureRecognizerやUIResponderのPress EventやMotion Event等も使えます。Motion EventはViewフォーカス時のparallax効果を表現できます。使用例は以下のブログがわかりやすいと思います。
フォーカス
tvOSではフォーカスという概念があり、基本的にView間の移動はフォーカスによって行います。ここがiOSと大きく違うところでもあります。
フォーカスはフォーカスエンジンがデフォルトでViewを決定します。 通常は、このViewは画面の左上に最も近いフォーカス可能なViewになります。
デフォルトでフォーカスされるUIKitクラス
- UIButton
- UITextField
- UITableView
- UICollectionView
- UITextView
- UISegmentedControl
- UISearchBar
UILabelなどデフォルトでフォーカスされないViewをフォーカスさせるには、UIViewのcanBecomeFocusedをoverrideする必要があります。また、UITableView、UICollectionViewに関してもフォーカスするCellをtableView:canFocusRowAtIndexPath:とcollectionView:canFocusItemAtIndexPath:で決定することができます。
基本的にはフォーカスエンジンに任せておけば良いのですが、フォーカスエンジンの検索エリアのサイズは、現在フォーカスされているViewのサイズで決定するため、意図したフォーカスにならない場合もあります。その場合は、自前で制御する必要があります。
フォーカスエンジンは、View階層のフォーカス動作を定義するUIFocusEnvironmentプロトコルに従ってフォーカスを制御しています。
このプロトコルがフォーカス制御のキモになります。以下のUIKitクラスがこのプロトコルに準拠しています。
- UIView
- UIViewController
- UIWindow
- UIPresentationController
ViewやViewControllerでUIFocusEnvironmentプロトコルの以下の実装をoverrideすることでフォーカス動作を制御できます。
- preferredFocusEnvironment
- shouldUpdateFocus(in:)
フォーカスされた場合のVIewの拡大/縮小などデフォルトの動作を変更したい場合はdidUpdateFocus(in:with:)をoverrideすることで実現できます。UITableViewのCellはデフォルトのフォーカスアニメーションがありますが、UICollectionViewはありません。cellの中にadjustsImageWhenAncestorFocused がtrueのImageViewがあればImageが拡大しますが、cell自体のフォーカスアニメーションをつけたい場合はoverrideして実装する必要があります。
また、Swipe/Touch/Selectなどのジェスチャーや何らかの条件でフォーカスをupdateしたい場合はsetNeedsFocusUpdateでフォーカスエンジンに更新をリクエスト、即座に更新したい場合はupdateFocusIfNeededを呼び出します。ここら辺はAutoLayoutを彷彿とさせますね。
上でふれましたが、UIImageViewにはadjustsImageWhenAncestorFocusedというpropertyがあるのでこれをtrueにしておけばUIImageのフォーカスアニメーションとインタラクションがつきます。
その他、UITableViewとUICollectionVIewについてはremembersLastFocusedIndexPathというpropertyがあり、trueにすると最後のフォーカスを覚えておいてくれます。
ライブラリ
最後にライブラリについてですが、多くのライブラリがtvOSにも対応しています。iOSに特化したUI系のライブラリはもちろんtvOSで使えませんが、逆にtvOSに特化したライブラリもいくつあります。
参考までにAbemaTVのtvOSアプリで使っているライブラリは以下になります。大きいところで言うとRxSwift、SQLite.swift、ProtocolBuffersなどでしょうか。UI周りのライブラリはあまり使っておらず、基本的には
- RxSwift
- RxCocoa
- SQLite.swift
- ProtocolBuffers-Swift
- SwiftyUserDefaults
- SDWebImage
- Cartography
- AttributedLabel
- SwiftDate
- Cheetah
- SpringIndicator
- CryptoSwift
- KeychainAccess
- ReachabilitySwift
- Fabric
- Crashlytics
まとめ
今回はtvOSアプリの開発についてポイントを絞っていくつか紹介しました。iOSと大きく違うポイントは今回紹介したUI/UXや入力イベントの扱い、フォーカスの制御ではないかと思います。
tvOSはリモコンを使って操作するので、iOSほど自由度もなく、他のアプリも標準のUIを採用しているところが多いので、基本的には標準のUI/UXに準拠した方が良いでしょう。
操作感は入力イベントの扱いとフォーカスの制御がキモですが、フォーカスのデバッグ機能も用意されているので、iOSアプリを開発している方ならすぐに理解できるのではないでしょうか。
発売から1年以上経過したApple TV第4世代ですが、ストアを見ると外資系のアプリばかりが並んでるように見受けられます。個人的には、ゲームや動画サービスだけでなく音楽や旅行、不動産といったサービスもtvOSに向いているのではないかと思っています。これから色々なサービスがtvOSに対応してくれるのを楽しみにしております。
それでは、お読み頂き有難うございました。
明日クリスマスイブ、24日目の CyberAgent Developers Advent Calendar 2016 は LE VAN NGHIA さんの記事になります。お楽しみに!
参考文献