TVML and UIKit as happy roommates
There is a classical beginning for every tvOS tutorial and it is a question: Are you creating a TVKit application or a native UIKit application?
Depending on the answer to that question, you will end up with one of two completely different ways of working to create your application.
The point is that the answer to that question is usually not so easy, because in fact, both alternatives, TVKit or UIKit, have their advantages and disadvantages.
📺 TVKit: Is a great solution for fast prototyping. Apple provides a super beautiful set of TVML templates, so that with just a few lines of code you can get a visually attractive application, completely integrated with the system. On the other hand, TVML templates are basically like they are, and they do provide a quite low level of customization.
💄 UIKit: On the other hand, offers a wider level of customisation. But it lacks of those fancy templates, so everything that you need will need to be created manually.
Would it not be great if we could just mix them up? So we could have, at the same time, a very customisable App with the option of fast prototyping specific sections making use of TVML?
One of the required steps to start working with TVML is to setup an instance of TVApplicationController. This instance of TVApplicationController is the one that will allow us to send the control of the app to JS.
In general, TVML Apps create their instance of TVApplicationController directly in their AppDelegate, and that is basically all the swift code that they have:
As you can see, one of the parameters received by the constructor of TVApplicationController is the application window.
The point is that when setting that window parameter to our TVApplicationController, it will actually set the rootViewController of the application to the one defined by our TVKit code.
But, what if we do not bind the instance of TVApplicationController to the window at that point, using
nil instead for the window parameter?
Then we will get a detached instance of TVApplicationController that is not bound to the window. And thanks to the property
navigationController exposed by
TVApplicationController, which is just a standard UINavigationController, we can manually host it as we want.
This is a very simple example of a UIKit ViewController presenting a TVKit screen when the IBAction
sendMeToTVMLButtonWasPressed is triggered:
And that is all, with this simple method we can use UIKit and TVKit in the same App, making use of one or the other whenever they fit better.
TVML as UIViewController:
Attending to the fact that having our views implemented with UIKit or TVKit is just an implementation detail, would it not be great if we could get rid of those particularities, having for them a similar interface?
This is actually what we can get embedding our TVKit code in a UIKit container view, so it is exposed with the interface of a UIViewController.
Show me the code:
If you are interested in more details about this, I have prepared this simple project combining UIKit and TVKit, embedding the TVML screen in a UIKit ViewController so it can be presented like any other ViewController.
let tvmlViewController = TVMLViewController()
present(tvmlViewController, animated: true, completion: nil)
And just for fun… I have also added some JS to the TVKit screen, binding it with some asynchronous code in Swift to emulate some network communication.
UIKit is great, it has been there since forever giving us a lot of powerful and flexibility, but whether you like it or not Apple is investing a lot in TVKit and this new way of working.
The best part is that TVKit and UIKit are definitely not exclusive, and we can mix them up taking advantage of the benefits of each whenever we need them.