top of page

Developing for Apple TV

We recently debuted our newest app, Houzz for Apple TV®, bringing home design to the living room. In these blog posts I will share some of the lessons we learned during the development process.

The Big Picture Developing an app for Apple TV is quite different from developing an app for iPhone or iPad, in several ways. To start, an iPhone / iPad user is typically a single user, interacting with the screen from a close distance. The TV experience, on the other hand, is often more communal, with several people sitting together watching the screen, and watching it from a 10-foot distance. This should greatly dictate how you design your app; you want to have a bigger screen presence, and short texts. In general, we found the screen “smaller” than that of an iPhone in terms of the number of items we could show at one time. With the TV screen, we had to show larger items, and have a focused item on screen at all times, yet leave room for the focus engine to do its zoom magic (more on the focus engine later).

The user interaction model is also quite different in that you don’t touch the screen as you do on iOS, you manage the focus with the remote, moving from one UI element to another. An element always needs to be in focus on screen to receive the touch events from the remote.

You interact on tvOS with the same gestures you’re familiar with from iOS. Single finger gestures are supported, and the remote supports both a touch and a click. The remote also has an accelerometer and gyro just like an iPhone. The remote has two buttons, which are used to navigate content: the menu button, typically used to navigate back through the view hierarchy; and the play/pause button, used for playing content.

Another difference is that there is no persistent storage on the device. You can write to the caches directory or the NSTemporaryDirectory and expect it to be available while your app is in the foreground, but once moved to the background, the system may purge it and there is no guarantee it will be there on your next app session. Instead, if you need persistent storage, you will need to use iCloud storage. You can also use NSUserDefaults for persistence of key/values, but note NSUserDefaults storage is limited to 500 KB max. iCloud key/value storage is limited to 1 MB max, otherwise you would need to use CloudKit or you can always store things on your own server.

This brings me to another mindset change: the Apple TV is an always-connected device. Wifi is likely to be available, and at a good connection speed, the user will want to stream movies.

Another consideration, which didn’t impact us at Houzz since our bundle size is small, is that the app bundle on Apple TV is limited to 200 MB and you have to use iOS 9 on demand resources if you need more.

tvOS doesn’t support UIWebView or its friends, SFSafariWebViewController and WKWebView. No workaround is available – you just don’t do web content in a native app. You have the option of doing a TVML app, but we didn’t take that route. And at this point, it’s important to mention that the Javascript/ObjC bridge, Core Javascript, is also not available on tvOS.

We also had to strip everything related to social from our TV app. The social frameworks are not available on the Apple TV, including Twitter, MessageUI and the Accounts frameworks, as well as Facebook.

Architecture One of the issues we faced was how to setup our code and project architecture to share code between our iOS app and tvOS app. It was clear most of the UI would have to be re-written for  Apple TV, but we could reuse a lot of our model and communication infrastructure. What helped us to get things rolling quickly was that our code was already structured into a Core Houzz framework that included all of the communication with our server and our data model since we support app extensions on iOS 8. It was a simple matter of recompiling that framework for tvOS. The first thing we encountered is that Xcode doesn’t let you link a framework compiled with iOS to a tvOS app, and that there is no way to have one configuration compiled with the iOS SDK, and one with the tvOS SDK. We ended up duplicating our CoreHouzz framework target to a CoreHouzzTV target that was compiled using the tvOS SDK.

If your project is built similarly, it should be easy to create a framework for the tvOS. Again we encountered some iOS/tvOS differences we had to reconcile. In the code, we used a lot of the pre-compile predicate:

   #if TARGET_OS_TV
   #endif

libsqlite is not available on tvOS, so we had to #if it out. It was used for some persistent storage, which we were able to do without, with some minimal iCloud usage. The UIInterfaceOrientation enum is not defined for tvOS (obviously since no one turns their TV on its side!), though I wish Apple would have left that and given it a value of landscape. All of the rest of the status bar orientation related methods are also unavailable on tvOS.

Once we had our core framework compiled for tvOS, the rest of the work entailed creating the view controllers and views for our TV app. We did share some very basic views between our iOS and tvOS – views like showing a gradient, loading an image from a URL, displaying a rating, etc.

Get Focused As I’ve mentioned, a big part of the development pertains to managing the focus, as there is always one focused element on screen. You can find out the focused view by:

    UIScreen.mainScreen().focusedView

You can choose the initial focus and the focus engine will move the focus from item to item on the screen based on the user touch input on the remote. You can be notified of these changes. The key is a new protocol, UIFocusEnvironment, that is conformed by UIView and UIViewController. This protocol lets these objects manage the focus in the view hierarchy they control.

Only UIViews and subclasses of UIView can become focused.

    override func canBecomeFocused() -> Bool {
      return true
    }

To indicate a view can get the focus, override the method canBecomeFocused: