So far tvOS supports two ways to make tv apps, TVML and UIKit, and there is no official mentions about how to mix up things to make a TVML (that is basically XML) User Interface with the native counter part for the app logic and I/O (like playback, streaming, iCloud persistence, etc).

So, which is the best solution to mix TVML and UIKit in a new tvOS app?

In the following I have tried a solution following code snippets adapted from Apple Forums and related questions about JavaScriptCore to ObjC/Swift binding.
This is a simple wrapper class in your Swift project.

import UIKit
import TVMLKit
@objc protocol MyJSClass: JSExport {
 func getItem(key: String) -> String ?
  func setItem(key: String, data: String)
}
class MyClass: NSObject, MyJSClass {
 func getItem(key: String) -> String ? {
  return "String value"
 }

 func setItem(key: String, data: String) {
  print("Set key:\(key) value:\(data)")
 }
}

where the delegate must conform a TVApplicationControllerDelegate:

typealias TVApplicationDelegate = AppDelegate
extension TVApplicationDelegate: TVApplicationControllerDelegate {

 func appController(appController: TVApplicationController, evaluateAppJavaScriptInContext jsContext: JSContext) {
  let myClass: MyClass = MyClass();
  jsContext.setObject(myClass, forKeyedSubscript: "objectwrapper");
 }

 func appController(appController: TVApplicationController, didFailWithError error: NSError) {
  let title = "Error Launching Application"
  let message = error.localizedDescription
  let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert) self.appController ? .navigationController.presentViewController(alertController, animated: true, completion: {
   () - & gt;Void in
  })
 }

 func appController(appController: TVApplicationController, didStopWithOptions options: [String: AnyObject] ? ) {}

 func appController(appController: TVApplicationController, didFinishLaunchingWithOptions options: [String: AnyObject] ? ) {}
}

At this point the javascript is very simple like. Take a look at the methods with named parameters, you will need to change the javascript counter part method name:

App.onLaunch = function(options) {
 var text = objectwrapper.getItem()
  // keep an eye here, the method name it changes when you have named parameters, you need camel case for parameters:
 objectwrapper.setItemData("test", "value")
}

App.onExit = function() {
 console.log('App finished');
}

Now, supposed that you have a very complex javascript interface to export like

@protocol MXMJSProtocol
- (void)boot:(JSValue *)status network:(JSValue*)network user:(JSValue*)c3;
- (NSString*)getVersion;
@end
@interface MXMJSObject : NSObject
@end
@implementation MXMJSObject
- (NSString*)getVersion {
return @"0.0.1";
}

you can do like

JSExportAs(boot,
- (void)boot:(JSValue *)status network:(JSValue*)network user:(JSValue*)c3 );

At this point in the JS Counter part you will not do the camel case:

objectwrapper.bootNetworkUser(statusChanged,networkChanged,userChanged)

but you are going to do:

objectwrapper.boot(statusChanged,networkChanged,userChanged)

Finally, look at this interface again:

- (void)boot:(JSValue *)status network:(JSValue*)network user:(JSValue*)c3;

The value JSValue* passed in. is a way to pass completion handlers between ObjC/Swift and JavaScriptCore. At this point in the native code you do all call with arguments:

dispatch_async(dispatch_get_main_queue(), ^{
NSNumber *state = [NSNumber numberWithInteger:status];
[networkChanged.context[@"setTimeout"]
callWithArguments:@[networkChanged, @0, state]];
});

In my findings, I have seen that the MainThread will hang if you do not dispatch on the main thread and async. So I will call the javascript “setTimeout” call that calls the completion handler callback.

So the approach I have used here is:

– Use JSExportAs to take car of methods with named parameters and avoid to camel case javascript counterparts like callMyParam1Param2Param3
– Use JSValue as parameter to get rid of completion handlers. Use callWithArguments on the native side. Use javascript functions on the JS side;
dispatch_async for completion handlers, possibly calling a setTimeout 0-delayed in the JavaScript side, to avoid the UI to freeze.

See here for discussion.

References
Apple TV Markup Language Reference
JavaScriptCore Framework Reference
Apple tvOS