📜 ⬆️ ⬇️

TvOS application development

The other day, Russian users who ordered the Apple TV console on the official website, finally began to receive long-awaited devices.

As you know, in the new generation of consoles debuts the App Store with third-party applications. The first Russian reviews with sadness noted that there are not so many applications in the domestic market yet (and this must somehow be corrected!) . However, among them is the Rutube app. In this article we will share a little experience that igor-petrov and Juraldinio managed to acquire during its development.

About tvOS platform


The new Apple TV (tvOS) platform is a derivative of iOS and has some unique features. In particular, it is possible for tvOS to port an existing iOS application written in Objective-C / Swift (according to the recommendations for interface implementation ), and to create an application on a new technology stack - TVML and TVJS, connected using the TVMLKit framework. This new stack is positioned as a good choice for simple and fast development of client-server applications (ideally for video!) , Which is confirmed in practice. It is about TVML and TVJS that will be discussed below.

TVMLKit


TVMLKit is a framework for Objective-C / Swift. Using it, control of the application is transferred to the JavaScript file and the TVML + TVJS environment. Details are available on the TVMLKit documentation page .
')

TVML


TVML (Television Markup Language) is a subset of XML that implements tvOS markup and standard interface elements. This interface is used not only for applications - it implements all tvOS pages: home screen, settings screen, and the App Store itself.

For example, the TVML button looks like this:

<button> <text>Hello world!</text> </button> 

And so the button looks on the screen:



And this is the device’s home screen, which consists of TVML elements:


tvOS provides a set of ready-made elements, a full list of which is available in the TVML documentation .

These elements are divided into:


In addition, elements can be given attributes and styles, such as width and src .

At the same time there are limitations - certain types of constituent elements can contain only certain types of simple elements, the same applies to templates. In general, the structure of the elements seemed rather confusing - each time I had to look in the directory to understand where which element could be used.

From the general list of templates, divTemplate is worth highlighting, which allows you to construct your own layout, if you are not satisfied with any other proposed one.

There is no opportunity to create your own elements, you can only combine existing ones.

Moreover, you need to make sure that when parsing the lines in the XML, an invalid TVML does not come across. For example, the response of our API could contain HTML tags, which caused an error.

TVML markup can be dynamically added to a page using JavaScript and TVJS.

Tvjs


TVJS is a JavaScript framework that provides an API for working with TVML. Conventionally, it can be divided into two parts:


Each of its own methods is described in the TVJS documentation . The rest is the usual JavaScript. ECMAScript 2015 is partially supported, for example, classes and template strings.

Arrow functions, constants are not supported. In this case, some third-party libraries may be inoperable. For example, I had to search several npm packages to find a working library for AJAX requests (due to calls to window.XMLHttpRequest, which in tvOS is not implemented as a window property) . Of course, it would be easier to write a few lines of code on your own, but at some point it became a matter of principle - to find a plug-in working from the box, and it exists!

Debugging


You can use Safari to debug JavaScript code. Activate the menu "Develop" ( Preferences -> Advanced -> Show Develop menu ), connect the Apple TV via USB. Go to the browser and, running the application on the console, select the “Apple TV” device in the drop-down menu “Develop”, and then select our application.

Hello world and the launch of the video


Further a small example of how the application for tvOS can look.

First you need to implement the loading of a JavaScript file. The task is to create an object of the TVApplicationController class, providing an interface for using TVML:

Show code
 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { //  window window = UIWindow(frame: UIScreen.mainScreen().bounds) // ,      TVApplicationController let appContollerContext = TVApplicationControllerContext() #if DEBUG //       let tvBaseUrl = "http://192.168.xx.xx/" let tvBootUrl = "\(tvBaseUrl)js/main.js" guard let javaScriptUrl = NSURL(string: tvBootUrl) else { fatalError("Unable create js application url") } //   js-,     appContollerContext.javaScriptApplicationURL = javaScriptUrl //  ,   BASE    appContollerContext.launchOptions["BASEURL"] = tvBaseUrl; #else //    js-   bundle  appContollerContext.javaScriptApplicationURL = NSBundle.mainBundle().URLForResource("application", withExtension:"js")! #endif //      js- appController = TVApplicationController(context:appContollerContext, window: window, delegate: self) return true } 


After management passed to a JavaScript file, it is possible to start implementation of logic. Content main.js:

 App.onLaunch = function (options) { console.log('Hello World!'); } 

This demonstrates the TVJS App method. onLauch is the entry point of the application.

Let's try to do something more complicated:

 App.onLaunch = function () { var alertString, alertXML, parser; //   TVML- alertString = [ '<document>', '<alertTemplate>', '<title>Hello World!</title>', '<button>', '<text>OK</text>', '</button>', '</alertTemplate>', '</document>' ].join(''); //   DOMParser parser = new DOMParser(); //  XML-   alertXML = parser.parseFromString(alertString, 'application/xml'); //  XML-   navigationDocument.pushDocument(alertXML); } 

This example demonstrates the DOMParser constructor, with which the string is converted to an XML document.

Using the TVJS method of navigationDocument.pushDocument () , you can display the resulting document on the page. At the same time, the new page will be written into the navigationDocument.documents array, which can be used to navigate the history. In this case, when you start the application, the page will contain the inscription “Hello world” and the “OK” button.

Before inserting an XML document, you can add a custom event handler to the page:

 ... //     (  ) alertXML.addEventListener('select', function () { var player, mediaItem; //   MediaItem mediaItem = new MediaItem('video', 'http://example.org/path/to.m3u8'); //    player = new Player(); //   Playlist player.playlist = new Playlist(); //  mediaItem  playlist player.playlist.push(mediaItem); //    player.present(); //   player.play(); }); ... 

In the resulting example, the user-select event is hung on the element of the XML document — a button — and a video player is created and launched in the callback using the TVJS methods. Now when you click on the "OK" button, the video playback will start.

Sample code entirely
 App.onLaunch = function () { var alertString, alertXML, parser; //   TVML- alertString = [ '<document>', '<alertTemplate>', '<title>Hello World!</title>', '<button>', '<text>OK</text>', '</button>', '</alertTemplate>', '</document>' ].join(''); //   DOMParser parser = new DOMParser(); //  XML-   alertXML = parser.parseFromString(alertString, 'application/xml'); //     (  ) alertXML.addEventListener('select', function () { var player, mediaItem; //   MediaItem mediaItem = new MediaItem('video', 'http://example.org/path/to.m3u8'); //    player = new Player(); //   Playlist player.playlist = new Playlist(); //  mediaItem   playlist  player.playlist.push(mediaItem); //    player.present(); //   player.play(); }); //  XML-   navigationDocument.pushDocument(alertXML); }; 


Of course, this is a very simple example, but it fully reflects the general principle of working with TVML and TVJS and shows that this solution is not some Wonderful Beast , but a technology close to the classic frontend.

Finally


In conclusion, a few words about how the Rutube application is currently implemented.

The code is written in CoffeeScript, Browserify is used as a modular loader. XMLHttpRequest and the open-source Rutube API are used to retrieve data. For video delivery, the HLS protocol is used.

Admire the main screen of the application


In general, development on TVML and TVJS was pleasant - quickly and efficiently. Although the application is created in a standardized interface, this interface looks very impressive. At the same time, time is saved on layout and creation of visual effects, and there is no need to think about their performance.

Of the minuses I would like to note the limitations in design. Well, the implementation of the search (text input) seemed ambiguous. We do not even know whether to add it to the app without Siri?

The application has been written in a few days, but if you are inspired and start developing your own, put some time into the evaluation of unfamiliar APIs.

In the future, a plug-in for React is expected to be released, which so far (November 2015) is in the status “very alpha”

In the meantime, it should be noted that over the past week since the release, without straining, “over a cup of tea”, we added to our application a certain amount of nice-looking gadgets and are preparing an update.

useful links


TVMLKit Documentation
TVJS Documentation
TVML documentation
Beginning tvOS Development with TVML Tutorial

Source: https://habr.com/ru/post/270381/


All Articles