Mixing TVML and UIKit without a server

Mixing TVML and UIKit without a server

When building for tvOS Apple gave us two approaches. A fully native app could be built using UIKit, storyboards and everything developers have been familiar with when building apps for iOS.

However, Apple also opened up their TVML and TVJS platform that has been used on Apple TV 2 and 3 by the likes of Netflix, Hulu and Now TV. This approach allows for apps to be created using a simple XML markup and JavaScript. That sounds great but when using TVML you're required to use a separate server to handle the logic of populating data and navigating between views.

That sounds like a massive pain, so why use TVML at all? Well Apple have provided a load of beautiful ready made templates that aren't available when using UIKit.



TVML without a server

In researching for a new project as well as planning for Fetch 2.0 I started investigating whether TVML/TVJS can be used without a server. Turns out it can fairly easily. You just need to set the base URL to be a local one (file://).

Justin Walsh did a really good write up over on his blog.

Mixing TVKit + UIKit

But what if you want to mix some UIKit views with TVML views? That's actually super easy.

When working with TVKit you'll setup a TVApplicationController. This controller is a global controller for the entire app and is what and JavaScript logic will interface with. The great thing is, TVApplicationController has a navigationController property which is just a standard UINavigationController. You can push native views onto this as and when you please.

applicationController?.navigationController.pushViewController(viewController, animated:true)

Combining it all with TVMLKitchen

I started putting together a little framework to mix all of this together and then I found TVMLKitchen. This is an amazing little library that allows you to easily serve XML or JS templates in a UIKit app.

Setting it up is super simple, just add the following into your AppDelegate:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    Kitchen.prepare(launchOptions)
    return true
}

Once that's done, you'll be able to serve up templates ridiculously easily.

// "Push" a view onto the navigation stack
Kitchen.serve(xmlFile: "template.xml")

// Present a view as an overlay
Kitchen.serve(xmlFile: "template.xml", type: .Modal))

Even better is the concept of "recipes" that TVMLKitchen opens to you. These are pre-built customisable templates that you can just drop into a project.

let buttons = [
    AlertButton(title: "Accept", actionID: "alertAction"),
    AlertButton(title: "Decline", actionID: "alertAction2"),
]

let recipe = DescriptiveAlertRecipe(title: "Terms of Service", description: "A long description would go here", buttons: buttons)

Kitchen.serve(recipe: recipe)

This will display the following alert when triggered.

The actionID property passed to the AlertButton can be caught and handled by TVMLKitchen. For more info see the documentation on GitHub.

You can of course make your own recipes as long as they adhere to the RecipeType protocol. This alone makes the prospect of a truly hybrid TVML/UIKit app very exciting.

I'll be using it on the new version of Fetch that will be out in a couple of months. Fetching and handling the data in Swift and then populating TVML templates using Kitchen.

✌️

Come Say Hello! Drop me an email, follow me on Twitter, or check out Cocoon (you totally should, we're doing some cool stuff over there).