tvOS Tutorial: Using TVML Templates

In this tvOS tutorial, you’ll learn how to use TVML templates and templating engines to make great-looking user interfaces. By Chris Belanger.

Leave a rating/review
Save for later
Share

In this tutorial, you’ll learn how to use the plethora of TVML templates that Apple has provided to make some stunning interfaces. You’ll use these templates to build a comprehensive screen for RWDevCon 2015 videos, which will include a wide range of information about the video and display it in an appealing and recognizable manner.

Getting Started

You can download the starter project for this tutorial here.

The sample app for this tutorial is wenderTV; it lets you browse and watch raywenderlich.com video content on your Apple TV, so you can enjoy a vast quantity of knowledge – and bad jokes – from the comfort of your sofa. Right now, wenderTV is quite empty.

wenderTV includes a lot of resources you’ll use during this tutorial; we’ve also reorganized some of the code to make it easier to understand.

Build and run the wenderTV starter project from Xcode; you’ll notice the screen is completely blank. This is because there aren’t any TVML documents in wenderTV yet. Before you can turn your attention to creating some TVML documents, you have a little housekeeping to do.

Note: Although you can use Xcode to write all the code you need for a TVML-based app, it can be quite a painful experience. Xcode is good for editing Swift or Objective-C, but has only rudimentary support for XML and JavaScript. It’s definitely worth using Xcode when you need to, and then switching to a more capable editor such as Sublime Text, Atom, Visual Studio Code or MacVim to work with TVML documents and JavaScript files.

Loading Scripts

The project for wenderTV already has ResourceLoaderJS split out into its own file, so you need to discover how to import it into main.js.

TVJS provides the evaluateScripts() function which takes an array of URLs of JavaScript files and a callback. The function reads each URL in turn, attempts to parse it and adds any contained functions and object definitions to the context’s global object. Finally, it invokes the supplied callback with a Boolean denoting success or failure.

The AppDelegate contains code that provides the JavaScript application with a list of URLs to the required JavaScript files as part of the launch options object. Open main.js and add the following code to the App.onLaunch() function:

// 1:
evaluateScripts(options.initialJSDependencies,
  function(success){
    if (success) {
      // 2:
      resourceLoader =
        new ResourceLoaderJS(NativeResourceLoader.create());
      var initialDoc = loadInitialDocument(resourceLoader);
      navigationDocument.pushDocument(initialDoc);
    } else {
      // 3:
      var alert = _createAlert("Evaluate Scripts Error",
        "Error attempting to evaluate the external JS files.");
      navigationDocument.presentModal(alert);

      throw ("Playback Example: unable to evaluate scripts.");
    }
  });

Taking this new function body step-by-step:

  1. The options object is prepared in Swift and then passed to the JavaScript app in the app delegate, while the initialJSDependencies property is an array of URLs for the different JavaScript files that need to be loaded as the app starts. evaluateScript() performs this action and then invokes the callback indicating whether it was successful.
  2. If the JavaScript sources evaluated successfully, create a ResourceLoaderJS object before using it to load the initial document and then pushing this TVML document onto the navigation stack. loadInitialDocument() is currently a stub method you’ll populate in a bit.
  3. If the JavaScript files failed to load, there is nothing more that the app can do. Therefore it uses _createAlert(), defined at the bottom of main.js to build and present an alert document and then throw an error.

Add the following to loadInitialDocument():

return resourceLoader.getDocument("video.tvml");

This uses the resource loader to get the TVML file from the app’s resource bundle and return it as a DOM object.

Next up, you’ll need to create the file your app is trying to load: video.tvml.

Head into Xcode, and right-click on the layouts group in the project navigator. Select New File…:

Navigate to tvOS\Other\Empty and hit Next. Name the file video.tvml and ensure that the wenderTV target is checked:

Open the new file in either your favorite XML editor (or Xcode, if you insist) and add the following lines:

<?xml version="1.0" encoding="UTF-8" ?>
<document>
  <productTemplate>
  </productTemplate>
</document>

This defines a simple TVML document using a new type of template: productTemplate.

Build and run the app to see how things look so far:

Hmm. The screen is still blank. Although you’ve created the file and provided the template, you haven’t provided any content. You’ll fix that shortly, but first you need to cover a bit of background on TVML templates.

TVML Templates

A TVML document is just an XML (eXtentible Markup Language) document with a specific schema defined by Apple. If you’ve used HTML in the past, XML will look familiar. HTML isn’t actually XML (despite some failed efforts with XHTML), but the syntax and structure is fairly similar.

Since TVML documents are XML they should start with the following line:

<?xml version="1.0" encoding="UTF-8" ?>

This is known as the XML prologue; it notes this file is an XML document and which character encoding it uses.

The TVML document has a root element, which is a single element at the top level of the document and the parent (or ancestor) of all other elements. The element has a single direct descendant, which can be one of 18 possible template tags.

A template tag specifies the top-level layout tvOS should use to render the document on screen. In addition to specifying the appearance onscreen, template tags also convey some semantic information about the content they contain. Templates might look similar, but have entirely different purposes.

TVML templates can be divided into the following categories:

  • Informational: Shows a small amount of information to the user, and optionally requests input from the user. It’s not designed for browsable content. Includes alertTemplate and loadingTemplate.
  • Data Entry: The user experience of entering data on TVs is pretty horrendous, and Apple TV is no different. However, there are a few templates for requesting data from the user, including searchTemplate and ratingTemplate.
  • Single Item: Displays information or content about a single product or item, such as a film or episode in a TV series. Includes productTemplate, oneupTemplate, compilationTemplate and showcaseTemplate.
  • Collections: Displays a collection of products, such as a TV series, a genre of films or tracks on an album. Includes stackTemplate, listTemplate and productBundle.
  • Other: Includes menuBarTemplate, which hosts a set of other templates, and divTemplate, which is a completely clean slate upon which you draw.
Note: Rather than go into detail here about each and every template, the Apple reference is a great resource for getting the low-down on the different templates, their capabilities and layouts: apple.co/1PJuOAV.
Chris Belanger

Contributors

Chris Belanger

Author

Over 300 content creators. Join our team.