Top Banner
© 2016 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple. Part 2 App Frameworks #WWDC16 Session 229 App Development Using TVMLKit Jeremy Foo tvOS Engineer
106

App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Apr 04, 2018

Download

Documents

hoàng_Điệp
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

© 2016 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.

Part 2

App Frameworks #WWDC16

Session 229

App Development Using TVMLKit

Jeremy Foo tvOS Engineer

Page 2: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Agenda

Extending TemplatesExtending JavaScript

Page 3: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Extending Templates

Page 4: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

1408 x 792

Page 5: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

1408 x 792

Page 6: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

TVMLKitApp

Extending Templates

Page 7: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

TVMLKitApp

Extending Templates

TVElementFactory1

TVInterfaceFactory TVMLKit UI

2

3

<TVML>

Page 8: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

TVMLKitApp

Extending Templates

TVMLKit UI

<TVML>

Extended Interface Creator

Page 9: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

TVMLKitApp

Extending Templates

TVElementFactory1

TVInterfaceFactory

TVMLKit UI2

<TVML>

<App Markup>

Extended Interface Creator

4 App UI3

Page 10: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// XML custom banner with nested TVML button

<document>

<stackTemplate>

<myBanner animated="true">

<button>...</button>

</myBanner>

<collectionList>

...

</collectionList>

</stackTemplate>

</document>

Page 11: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// XML custom banner with nested TVML button

<document>

<stackTemplate>

<myBanner animated="true">

<button>...</button>

</myBanner>

<collectionList>

...

</collectionList>

</stackTemplate>

</document>

Page 12: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// XML custom banner with nested TVML button

<document>

<stackTemplate>

<myBanner animated="true">

<button>...</button>

</myBanner>

<collectionList>

...

</collectionList>

</stackTemplate>

</document>

Page 13: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// XML custom banner with nested TVML button

<document>

<stackTemplate>

<myBanner animated="true">

<button>...</button>

</myBanner>

<collectionList>

...

</collectionList>

</stackTemplate>

</document>

Page 14: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Register element nameExtending Templates

Page 15: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Register element nameExtending Templates

Once before app controller startup

Page 16: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Register element nameExtending Templates

Once before app controller startup

TVElementFactory.registerViewElementClass(TVViewElement.self, elementName: "myBanner")

Page 17: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Register element nameExtending Templates

Once before app controller startup

TVElementFactory.registerViewElementClass(TVViewElement.self, elementName: "myBanner")

TVViewElement

TVImageElement TVTextElement

Page 18: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Interface creatorExtending Templates

Page 19: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Interface creatorExtending Templates

Setup TVInterfaceCreating interface creator

Page 20: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Interface creatorExtending Templates

Setup TVInterfaceCreating interface creatorConfigure user interface

Page 21: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Interface creatorExtending Templates

Setup TVInterfaceCreating interface creatorConfigure user interfaceLeverage TVMLKit

Page 22: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Setup an interface creator

class MyInterfaceCreator: NSObject, TVInterfaceCreating {

}

Page 23: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Setup an interface creator

class MyInterfaceCreator: NSObject, TVInterfaceCreating {

// Conform to TVInterfaceCreating to provide extended user interface

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

// code to create views

...

}

}

Page 24: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Setup an interface creator

class MyInterfaceCreator: NSObject, TVInterfaceCreating {

// Conform to TVInterfaceCreating to provide extended user interface

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

// code to create views

...

}

}

// Register interface creator with interface factory before application controller startup

TVInterfaceFactory.shared().extendedInterfaceCreator = MyInterfaceCreator.init()

Page 25: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

}

}

Page 26: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = MyBanner.init()

}

}

Page 27: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = MyBanner.init()

// Use myBanner's "animated" attribute to configure banner's animated state

if let animated = element.attributes?["animated"] {

banner.animated = (animated.lowercased() == "true")

}

}

}

Page 28: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = MyBanner.init()

// Use myBanner's "animated" attribute to configure banner's animated state

if let animated = element.attributes?["animated"] {

banner.animated = (animated.lowercased() == "true")

}

// Look for button element and use TVInterfaceFactory to create the view

var button: UIView? = nil

if let buttonElement = self.getButtonElement(element) {

button = TVInterfaceFactory.shared().makeView(element: buttonElement,

existingView: button)

}

banner.button = button

}

}

Page 29: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = MyBanner.init()

// Use myBanner's "animated" attribute to configure banner's animated state

if let animated = element.attributes?["animated"] {

banner.animated = (animated.lowercased() == "true")

}

// Look for button element and use TVInterfaceFactory to create the view

var button: UIView? = nil

if let buttonElement = self.getButtonElement(element) {

button = TVInterfaceFactory.shared().makeView(element: buttonElement,

existingView: button)

}

banner.button = button

return banner

}

}

Page 30: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = MyBanner.init()

// Use myBanner's "animated" attribute to configure banner's animated state

if let animated = element.attributes?["animated"] {

banner.animated = (animated.lowercased() == "true")

}

// Look for button element and use TVInterfaceFactory to create the view

var button: UIView? = nil

if let buttonElement = self.getButtonElement(element) {

button = TVInterfaceFactory.shared().makeView(element: buttonElement,

existingView: button)

}

banner.button = button

return banner

default:

return nil

}

}

Page 31: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

View controllersExtending Templates

Page 32: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

View controllersExtending Templates

Substitute shelf/grid type controllers

Page 33: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

View controllersExtending Templates

Substitute shelf/grid type controllersUsage similar to makeView

func makeViewController(element: TVViewElement, existingViewController: UIViewController?)

-> UIViewController?

Page 34: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Aha!

Page 35: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory
Page 36: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Custom collection view cellsExtending Templates

Custom layout

NEW

Page 37: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Custom collection view cellsExtending Templates

Custom layoutParticipate in focus events

NEW

Page 38: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Custom collection view cellsExtending Templates

Custom layoutParticipate in focus events

func collectionViewCellClass(for element: TVViewElement) -> AnyClass?

NEW

Page 39: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Custom collection view cellsExtending Templates

Custom layoutParticipate in focus events

func collectionViewCellClass(for element: TVViewElement) -> AnyClass?

func makeView(element: TVViewElement, existingView: UIView?) -> UIView?

NEW

Page 40: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

DemoCustom collection view cell

Parry Panesar tvOS Engineer

Page 41: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Recap

Define custom markup

Page 42: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Recap

Define custom markupRegister custom elements

Page 43: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Recap

Define custom markupRegister custom elementsProvide extended interface creator

Page 44: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Recap

Define custom markupRegister custom elementsProvide extended interface creatorConfigure custom user interface

Page 45: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Best Practices

Page 46: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Handling Document Updates

Updated anytime

Page 47: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Handling Document Updates

Updated anytimeCheck update type

switch element.updateType {

case .node:

// Update current element and children

break

case .subtree:

// Update children

break

case .children:

// Update children with changed order

break

default:

break

}

Page 48: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Handling Document Updates

Updated anytimeCheck update typeReuse views

switch element.updateType {

case .node:

// Update current element and children

break

case .subtree:

// Update children

break

case .children:

// Update children with changed order

break

default:

break

}

Page 49: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = MyBanner.init()

// Use myBanner's "animated" attribute to configure banner's animated state

if let animated = element.attributes?["animated"] {

banner.animated = (animated.lowercased() == "true")

}

// Look for button element and use TVInterfaceFactory to create the view

var button: UIView? = nil

if let buttonElement = self.getButtonElement(element) {

button = TVInterfaceFactory.shared().makeView(element: buttonElement,

existingView: button)

}

banner.button = button

return banner

default:

return nil

}

}

Page 50: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = (existingView as? MyBanner) ?? MyBanner.init()

// Use myBanner's "animated" attribute to configure banner's animated state

if let animated = element.attributes?["animated"] {

banner.animated = (animated.lowercased() == "true")

}

// Look for button element and use TVInterfaceFactory to create the view

var button: UIView? = banner.button

if let buttonElement = self.getButtonElement(element) {

button = TVInterfaceFactory.shared().makeView(element: buttonElement,

existingView: button)

}

banner.button = button

return banner

default:

return nil

}

}

Page 51: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = (existingView as? MyBanner) ?? MyBanner.init()

// Use myBanner's "animated" attribute to configure banner's animated state

if let animated = element.attributes?["animated"] {

banner.animated = (animated.lowercased() == "true")

}

// Look for button element and use TVInterfaceFactory to create the view

var button: UIView? = banner.button

if let buttonElement = self.getButtonElement(element) {

button = TVInterfaceFactory.shared().makeView(element: buttonElement,

existingView: button)

}

banner.button = button

return banner

default:

return nil

}

}

Page 52: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

func makeView(element: TVViewElement, existingView: UIView?) -> UIView? {

switch element.name {

case "myBanner":

let banner = (existingView as? MyBanner) ?? MyBanner.init()

// Use myBanner's "animated" attribute to configure banner's animated state

if let animated = element.attributes?["animated"] {

banner.animated = (animated.lowercased() == "true")

}

// Look for button element and use TVInterfaceFactory to create the view

var button: UIView? = banner.button

if let buttonElement = self.getButtonElement(element) {

button = TVInterfaceFactory.shared().makeView(element: buttonElement,

existingView: button)

}

banner.button = button

return banner

default:

return nil

}

}

Page 53: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Custom user interfaceAdapting to Appearance

Listen to trait collection changes

Page 54: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Custom user interfaceAdapting to Appearance

Listen to trait collection changes

What’s New in tvOS Presidio Tuesday 3:00PM

Page 55: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

TVML componentsAdapting to Appearance

Check style update typeswitch element.updateType {

...

case .styles:

// update styles based on new styles

break

default:

break

}

Page 56: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

TVML componentsAdapting to Appearance

Check style update typeMust reuse components

switch element.updateType {

...

case .styles:

// update styles based on new styles

break

default:

break

}

Page 57: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

TVML componentsAdapting to Appearance

Check style update typeMust reuse componentsMust forward to TVInterfaceFactory

switch element.updateType {

...

case .styles:

// update styles based on new styles

break

default:

break

}

Page 58: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Mix Native Controller

Define custom template element

Page 59: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Mix Native Controller

// Register an element for your view controller

TVElementFactory.registerViewElementClass(TVViewElement.self, elementName: "myViewController")

// Vend your view controller

func makeViewController(element: TVViewElement, existingViewController: UIViewController?) -> UIViewController? {

switch element.name {

case "myViewController":

return MyViewController.init(/* initialization */)

default:

return nil

}

}

Define custom template element

Page 60: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Mix Native Controller

// Register an element for your view controller

TVElementFactory.registerViewElementClass(TVViewElement.self, elementName: "myViewController")

// Vend your view controller

func makeViewController(element: TVViewElement, existingViewController: UIViewController?) -> UIViewController? {

switch element.name {

case "myViewController":

return MyViewController.init(/* initialization */)

default:

return nil

}

}

Return your view controller

Page 61: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Sub Application

Host the navigationController

Page 62: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Sub Application

Host the navigationController

// Create hosted controller

let hostedControllerContext = TVApplicationControllerContext()

hostedControllerContext.javaScriptApplicationURL = javaScriptURL

let hostedController = TVApplicationController(context: hostedControllerContext,

window: nil, delegate: self)

// Present hosted controller

let navigationController = hostedController.navigationController

self.present(navigationController, animated: true, completion: nil)

Page 63: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Sub Application

Host the navigationControllerHost in separate UIWindow

Page 64: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Extending JavaScript

Christopher Bonhage tvOS Engineer

Page 65: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Extending JavaScript

JavaScript libraries

Page 66: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Extending JavaScript

JavaScript libraries

Page 67: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Extending JavaScript

JavaScript librariesCalling into JavaScript JavaScriptSwift

Page 68: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Extending JavaScript

JavaScript librariesCalling into JavaScriptBridging to JavaScript

JavaScriptSwift

Page 69: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Extending JavaScript

JavaScript librariesCalling into JavaScriptBridging to JavaScript

JavaScriptSwift

Page 70: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

JavaScript Libraries

Page 71: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

JavaScript Libraries

Load additional scriptsExecutes in the global context

Page 72: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

JavaScript Libraries

Load additional scriptsExecutes in the global context

Page 73: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

JavaScript Libraries

Load additional scriptsExecutes in the global context

const scriptURLs = [

options.BASEURL + "js/DocumentLoader.js",

options.BASEURL + "js/DocumentController.js"

];

evaluateScripts(scriptURLs, function(scriptsAreLoaded) {

// Continue with App.onLaunch

});

Page 74: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

CaveatsJavaScript Libraries

Page 75: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

CaveatsJavaScript Libraries

Evaluate once

Page 76: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

CaveatsJavaScript Libraries

All-or-nothing

Evaluate once

Page 77: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

CaveatsJavaScript Libraries

All-or-nothing

Not a web browser

Evaluate once

Page 78: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Calling into JavaScript

Page 79: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Calling into JavaScript

Request the JSContext Main Thread

TVApplicationController

JS Thread

JSContext

Page 80: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Calling into JavaScript

Request the JSContext Main Thread

TVApplicationController

JS Thread

JSContext

Block

Page 81: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Calling into JavaScript

Request the JSContextEvaluate with context

Evaluate

Main Thread

TVApplicationController

JS Thread

JSContext

Block

Page 82: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Calling into JavaScript

Request the JSContextEvaluate with contextDon’t block main thread

Main Thread JS Thread

Block

TVApplicationController JSContext

Page 83: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Calling into JavaScript

Request the JSContextEvaluate with contextDon’t block main thread

Integrating JavaScript into Native Apps WWDC 2013

Main Thread JS Thread

Block

TVApplicationController JSContext

Page 84: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Calling into JavaScript example

func application(_ app: UIApplication, open url: URL, options: [String : AnyObject] = [:])

-> Bool {

// Request the context

appController?.evaluate(inJavaScriptContext: { (context) in

// Evaluate in context

if context.globalObject.hasProperty("onOpenURL") {

let urlString = url.absoluteString as AnyObject

context.globalObject.invokeMethod("onOpenURL", withArguments: [urlString])

}

}, completion: nil)

return true

}

Page 85: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Calling into JavaScript example

func application(_ app: UIApplication, open url: URL, options: [String : AnyObject] = [:])

-> Bool {

// Request the context

appController?.evaluate(inJavaScriptContext: { (context) in

// Evaluate in context

if context.globalObject.hasProperty("onOpenURL") {

let urlString = url.absoluteString as AnyObject

context.globalObject.invokeMethod("onOpenURL", withArguments: [urlString])

}

}, completion: nil)

return true

}

Page 86: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Calling into JavaScript example

func application(_ app: UIApplication, open url: URL, options: [String : AnyObject] = [:])

-> Bool {

// Request the context

appController?.evaluate(inJavaScriptContext: { (context) in

// Evaluate in context

if context.globalObject.hasProperty("onOpenURL") {

let urlString = url.absoluteString as AnyObject

context.globalObject.invokeMethod("onOpenURL", withArguments: [urlString])

}

}, completion: nil)

return true

}

Page 87: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Calling into JavaScript example

func application(_ app: UIApplication, open url: URL, options: [String : AnyObject] = [:])

-> Bool {

// Request the context

appController?.evaluate(inJavaScriptContext: { (context) in

// Evaluate in context

if context.globalObject.hasProperty("onOpenURL") {

let urlString = url.absoluteString as AnyObject

context.globalObject.invokeMethod("onOpenURL", withArguments: [urlString])

}

}, completion: nil)

return true

}

Page 88: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Calling into JavaScript example

func application(_ app: UIApplication, open url: URL, options: [String : AnyObject] = [:])

-> Bool {

// Request the context

appController?.evaluate(inJavaScriptContext: { (context) in

// Evaluate in context

if context.globalObject.hasProperty("onOpenURL") {

let urlString = url.absoluteString as AnyObject

context.globalObject.invokeMethod("onOpenURL", withArguments: [urlString])

}

}, completion: nil)

return true

}

Page 89: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Calling into JavaScript example

func application(_ app: UIApplication, open url: URL, options: [String : AnyObject] = [:])

-> Bool {

// Request the context

appController?.evaluate(inJavaScriptContext: { (context) in

// Evaluate in context

if context.globalObject.hasProperty("onOpenURL") {

let urlString = url.absoluteString as AnyObject

context.globalObject.invokeMethod("onOpenURL", withArguments: [urlString])

}

}, completion: nil)

return true

}

Page 90: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Bridging to JavaScript

Page 91: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Bridging to JavaScript

Create custom protocol

Page 92: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Bridging to JavaScript

Create custom protocolImplement in Objective-C class

Page 93: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Bridging to JavaScript

Create custom protocolImplement in Objective-C classExpose via AppDelegate

Page 94: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Bridging to JavaScript example

Page 95: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Bridging to JavaScript example

Page 96: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Bridging to JavaScript example

@objc protocol StoreKitWrapperProtocol : JSExport {

// Definition of custom protocol

}

Page 97: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Bridging to JavaScript example

@objc protocol StoreKitWrapperProtocol : JSExport {

// Definition of custom protocol

}

Page 98: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Bridging to JavaScript example

@objc protocol StoreKitWrapperProtocol : JSExport {

// Definition of custom protocol

}

class StoreKitWrapper: NSObject, StoreKitWrapperProtocol {

// Implementation of custom protocol

}

Page 99: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Bridging to JavaScript example

@objc protocol StoreKitWrapperProtocol : JSExport {

// Definition of custom protocol

}

class StoreKitWrapper: NSObject, StoreKitWrapperProtocol {

// Implementation of custom protocol

}

Page 100: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Bridging to JavaScript example

@objc protocol StoreKitWrapperProtocol : JSExport {

// Definition of custom protocol

}

class StoreKitWrapper: NSObject, StoreKitWrapperProtocol {

// Implementation of custom protocol

}

func appController(appController: TVApplicationController,

evaluateAppJavaScriptInContext context: JSContext) {

context.setObject(StoreKitWrapper.self, forKeyedSubscript: "StoreKitWrapper")

}

Page 101: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

// Bridging to JavaScript example

@objc protocol StoreKitWrapperProtocol : JSExport {

// Definition of custom protocol

}

class StoreKitWrapper: NSObject, StoreKitWrapperProtocol {

// Implementation of custom protocol

}

func appController(appController: TVApplicationController,

evaluateAppJavaScriptInContext context: JSContext) {

context.setObject(StoreKitWrapper.self, forKeyedSubscript: "StoreKitWrapper")

}

Page 102: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Summary

Easiest way to provide custom user experiencesBuild on top of existing TVMLKit capabilitiesCreate unique, immersive apps

Page 103: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

More Information

https://developer.apple.com/wwdc16/229

Page 104: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Related Sessions

Designing for tvOS Presidio Tuesday 2:00PM

Mastering UIKit for tvOS Presidio Wednesday 10:00AM

Developing tvOS Apps Using TVMLKit: Part 1 Mission Wednesday 1:40PM

Focus Interactions on tvOS Mission Wednesday 4:00PM

Optimizing Web Content in Your App Mission Friday 4:00PM

Page 105: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory

Labs

TVMLKit Lab Graphics, Games, and Media Lab C Friday 9:00AM

Page 106: App Development Using TVMLKit - Apple Inc.devstreaming.apple.com/videos/.../229/...apps_using_tvmlkit_part_2.pdfApp TVMLKit Extending Templates 1 TVElementFactory TVInterfaceFactory