Can I mix UIKit and TVMLKit within one app?

Yes, you can. Displaying TVML templates requires you to use an object that controls the JavaScript Context: TVApplicationController.

var appController: TVApplicationController?

This object has a UINavigationController property associated with it. So whenever you see fit, you can call:

let myViewController = UIViewController()
self.appController?.navigationController.pushViewController(myViewController, animated: true)

This allows you to push a Custom UIKit viewcontroller onto the navigation stack. If you want to go back to TVML Templates, just pop the viewController off of the navigation stack.

If what you would like to know is how to communicate between JavaScript and Swift, here is a method that creates a javascript function called pushMyView()

func createPushMyView(){

    //allows us to access the javascript context
    appController?.evaluateInJavaScriptContext({(evaluation: JSContext) -> Void in

        //this is the block that will be called when javascript calls pushMyView()
        let pushMyViewBlock : @convention(block) () -> Void = {
            () -> Void in

            //pushes a UIKit view controller onto the navigation stack
            let myViewController = UIViewController()
            self.appController?.navigationController.pushViewController(myViewController, animated: true)
        }

        //this creates a function in the javascript context called "pushMyView". 
        //calling pushMyView() in javascript will call the block we created above.
        evaluation.setObject(unsafeBitCast(pushMyViewBlock, AnyObject.self), forKeyedSubscript: "pushMyView")
        }, completion: {(Bool) -> Void in
        //done running the script
    })
}

Once you call createPushMyView() in Swift, you are free to call pushMyView() in your javascript code and it will push a view controller onto the stack.

SWIFT 4.1 UPDATE

Just a few simple changes to method names and casting:

appController?.evaluate(inJavaScriptContext: {(evaluation: JSContext) -> Void in

and

evaluation.setObject(unsafeBitCast(pushMyViewBlock, to: AnyObject.self), forKeyedSubscript: "pushMyView" as NSString)

Leave a Comment