Skip to content

Jameson Quave

Using computer technology to educate, and improve lives.

Menu
  • Home
  • Contact
Menu
Apple TV Developer

Developing tvOS Apps for Apple TV [Part 1]

Posted on September 9, 2015September 28, 2015 by Jameson Quave

tvOS - Apple TV SDK Released

Here’s what you’ll have at the end of part 2 of this tutorial if you follow along:

Looking for some help building your Apple TV tvOS App? I’m available for consulting and development, contact me.

Apple TV Developer Tools

Before we get started you’ll need the Xcode 7.1 beta, which you can download here:
Download Xcode 7.1 Beta
Note that this does require an Apple Developer account, and is currently pre-release, so some things may change!

One thing to note when installing is that there is a known issue if you rename the Xcode 7.1 app, apparently people do this. So just a forewarning… don’t do that or you’ll get a crashy tvOS Simulator.

Also note that while Yosemite is supported, the capabilities are limited. It is recommend that for tvOS development you use OS X 10.11 El Capitan or newer. The El Capitan beta can be downloaded here.

Let’s start with some simple definitions…

Becoming an Apple TV Developer – Vocabulary

TVMLKit

TVMLKit is Apple’s new framework designed for working with Javascript and XML to provide a rich user-interface on tvOS, while allowing your apps logic to be written in Swift or Objective-C.

TVML

TVML is short for “TV Markup Language” and is basically just some XML that describes how items are laid out in a client-server based tvOS app. When laying out an interface, we want to use some TVML templates that Apple provides to create our UI, and then we can script the interactions in TVJS.

TVJS

As far as I can tell, TVJS is just JavaScript like you might already be familiar with.

Hello World

Let’s start out by making a basic hello world. In terms of Apple TV, we could just log “Hello World” to the console and that would be a decent start, but let’s start digging in to some of the Apple TV’s TVMLKit elements and put up a template on-screen.

First, open Xcode 7.1 and create a new project. You’ll see a list of templates appear. On the left-hand side we want to select **CHANGE tvOS, and then select Single View Application* template.

This will create a number of files from the tvOS template which are going to be useful in setting up our UI, and gives us a simple entry point to start coding Swift as well.

Setting up the main TVJS file

So basically the “server” in client-server tvOS apps is the TVML and JavaScript files, and whatever associated data they need to operate. The JavaScript file will be what loads in the TVML, and adds the page to the view stack. Another way to think of this is that the JavaScript file acts as a router or controller for the TVML files which are basically the views.

Kicking things off

First, we want to make some modifications to the AppDelegate.swift file that launches the app. For one, we need our application to adhere to the TVApplicationControllerDelegate protocol. This is defined in the TVMLKit framework, so we’ll need to import that as well. So you’ll want to update your AppDelegate.swift to include those two items:

import TVMLKit
 
class AppDelegate: UIResponder,
                   UIApplicationDelegate,
                   TVApplicationControllerDelegate {
 
....

This interface has four functions that tvOS calls upon the implementing AppDelegate to notify our app of the lifecycle of the tvOS application. We don’t need to worry about these just yet, but we’ll dig in to these in later tutorials. For now, just add the protocol as shown in the code snippet above, and that’s enough to get us started.

Next, we need to add some code to actually launch our JS file. This is a beta, and actually requires we do this work ourselves, I’m sure in future Xcode version’s this will simply be a template.

In the application didFinishLaunchingWithOptions function we need to perform a few steps. These steps are unlikely to change for each individual app so you can simply copy this snippet here:

// We'll hold a reference to the app controller in an optional property
var appController: TVApplicationController?
 
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  self.window = UIWindow(frame:UIScreen.mainScreen().bounds)
 
  let appControllerContext = TVApplicationControllerContext()
 
  let jsFilePath = NSURL(string: "http://localhost:8000/main.js")
  let javascriptURL = jsFilePath!
 
  appControllerContext.javaScriptApplicationURL = javascriptURL
  if let options = launchOptions
  {
    for (kind, value) in options
    {
      if let kindStr = kind as? String
      {
        appControllerContext.launchOptions[kindStr] = value
      }
    }
  }
 
  self.appController = TVApplicationController(context: appControllerContext, window: self.window, delegate: self)
 
  return true
}

In short, what this code does is it gets a reference to an TVApplicationControllerContext, a class that simply provides some launch data to our AppDelegate class, and gives us an interface to make adjustments to the launch process. Then it passes the URL of the main.js file we’re going to execute, and sets the path for the app controller to be that path.

We need to now add our javascript file, so click File > New, and then under the iOS tab you can select an Other > Empty file. Name this file main.js.

Do the same thing for a new file called hello.tvml.

In your main.js file we’ll add some relatively simple JavaScript to load in the hello.tvml file:

function getDocument(url) {
  var templateXHR = new XMLHttpRequest();
  templateXHR.responseType = "document";
  templateXHR.addEventListener("load", function() {pushDoc(templateXHR.responseXML);}, false);
  templateXHR.open("GET", url, true);
  templateXHR.send();
  return templateXHR;
}
 
function pushDoc(document) {
  navigationDocument.pushDocument(document);
}
 
App.onLaunch = function(options) {
  var templateURL = 'http://localhost:8000/hello.tvml';
  getDocument(templateURL);
}
 
App.onExit = function() {
  console.log('App finished');
}

Now in the hello.tvml file:

<document>
  <alertTemplate>
      <title>Hello tvOS!</title>
  </alertTemplate>
</document>

This TVML file is the meat of the UI. Documents must use templates or you’ll get crashes at runtime with the code we’re using. It just contains a simple template and a single title element.

One issue I found with setting things up is that I was unable to locally refer to these files, and instead they have to be on a web server. So, what is easiest to do is navigate to the location of your tvml and js files we just created and type the following command in the command line:

Setting up the server to host the files

python -m SimpleHTTPServer 8000

This just uses Mac OS’s built-in python interpreter to start a web server on port 8000 serving up the local directory. If you copied my code shown above you should now be able to boot in to your tvOS simulator by pressing the play button in Xcode! There is one more issue you should be aware of, which is that this is an http unsecured request. In iOS 9 this is blocked by default by App Transport Security. In order to allow localhost to be used in this way, we need to add a key to the Info.plist file.

Allowing Arbitrary Loads

Select your Info.plist file and add a new record by pressing one of the (+) buttons. In the list find “App Transport Security Settings” and press return. This will create a new Dictionary row, expand this and press the (+) button on this row to add a child row. For this one find, “Allows Arbitrary Loads” and set it to true. With this in place we can run the app and preview using the simulator.

Adding Buttons

What you’re seeing in this example is actually a template from Apple called the alertTemplate. You can also embed a few basic controls, such as text and buttons within the template. Try adding a few buttons to select from:

<document>
    <alertTemplate>
        <title>Hello tvOS!</title>
        <button>
            <text>A Button</text>
        </button>
        <button>
            <text>A Second Button</text>
        </button>
    </alertTemplate>
</document>

Here we just are adding child button elements, each with it’s own child text element. This in turn displays the fullscreen alert and the two buttons on the tvOS simulator. The official Apple documentation has a list of each template, and control you can use if you want to hit the ground running. Otherwise stay tight, subscribe, and I’ll be bringing you a full tutorial of a fully developed app very soon.

Next Steps

Proceed to PART 2 » of this tutorial to learn how to add interactivity to the app.

If you want me to email you letting you know when new posts are up, be sure to subscribe to my newsletter.

These are still early days, so expect issues. If you get stuck don’t hesitate to contact me on twitter @jquave

GO TO PART 2 »

Looking for an Apple TV Developer for your tvOS App? I’m available for consulting and development, contact me for more info.

4 thoughts on “Developing tvOS Apps for Apple TV [Part 1]”

  1. Pete Barber says:
    September 10, 2015 at 3:09 pm

    Thanks for the tutorial. Helped with the missing declaration and nice technique for loading in the JS & TVML. I tried to load these form the app. Had success with the JS but not the TVML. Wrote a very short blog post based on yours about it. http://petebarber.blogspot.co.uk/2015/09/a-slight-enhancement-on-developing-tvos.html

    Reply
    1. Jameson Quave says:
      September 10, 2015 at 8:13 pm

      Please see part 2, might help you some. What you’re looking for is not “Document”, you want navigatonDocument.documents[0] or something similar.

      Reply
  2. tom says:
    September 10, 2015 at 5:00 pm

    Objective c translation

    – (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // let appControllerContext = TVApplicationControllerContext()
    self.appControllerContext = [[TVApplicationControllerContext alloc] init];
    // let javascriptURL = NSURL(string: String(“Enter path to your JavaScript file here”))
    NSURL *javascriptURL = [NSURL URLWithString:@”http://localhost:8000/main.js”];

    //appControllerContext.javaScriptApplicationURL = javascriptURL!
    self.appControllerContext.javaScriptApplicationURL= javascriptURL;

    for (id key in launchOptions)
    {
    id val=[launchOptions objectForKey:key];
    NSLog(@”key=%@ value=%@”, key, val);
    if([val isKindOfClass:[NSString class]]) [self.appControllerContext.launchOptions objectForKey:val];
    }

    self.appController = [[TVApplicationController alloc] initWithContext:self.appControllerContext window:self.window delegate:self];

    //self.appController = TVApplicationController(context:appControllerContext, window:self.window, delegate: self)

    return true;
    }

    Reply
    1. Jameson Quave says:
      September 10, 2015 at 8:13 pm

      Thanks for this!

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Connect

  • Facebook
  • Google+
  • My Programming Book Picks
  • Twitter

Jameson Quave


I write about new technologies and how we interact with them.
© 2025 Jameson Quave | Powered by Minimalist Blog WordPress Theme