WWDC2016 Session 229

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Music ]
>> All right.
[ Applause ]
Good afternoon everyone
and welcome
to app development
using TVMLKit Part 2.
There are many amazing
apps out there
on the App Store
based on TVMLKit.
And some have even been
customized with styles
to give a unique experience
and branding for all your apps.
So today I'm extremely
excited to be talking to you,
to tell how you could bring your
apps to a whole other level.
And this is done by extending
TVMLKit by extending interfaces
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And this is done by extending
TVMLKit by extending interfaces
and also the functionality
that's provided in JavaScript.
This will basically let
your app stand out even more
with all your own
unique branding.
TVMLKit is a thoughtful
framework, we've also tried
to make sure that there is some
thought in how it's structured
as such that only
two extension points
that you have to worry about.
In the first half of
the talk I'm going
to tell you guys how you can
extend the user interface
in TVMLKit by extending
templates.
In the second half, my colleague
Christopher will be explaining
how you can enhance your apps by
adding application functionality
to the JavaScript engine
that powers TVMLKit.
So, let's talk about
extending templates.
The very first thing
that everyone encounters
when they use TVMLKit is
this idea of templates,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
these are defined in the
TVML, TV mark-up language.
They use XML as a way to
describe what's on the screen
and when people encounter
this, they start by saying huh,
I know this this
is a web browser.
I can assure you we are
absolutely not a web browser.
What TVMLKit is however, is
a powerful templating engine,
but that doesn't mean you are
limited to what we provide.
In fact, Apple's own apps
use TVMLKit but extend it
in really subtle ways that allow
it to coexist with the rest
of the framework and
still feel right on tvOS.
Let's look at, take
a look at an example,
this is the App Store app.
The App Store theme had a
requirement for a unique cell
within a shelf, as you can see
they have reused what TVMLKit
provides, an image
and three labels.
But over here they
have a custom layout
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But over here they
have a custom layout
with custom focused behaviors.
Another example that we
are all really familiar
with is the concept
of the Buy button.
Once again the App Store
theme had a requirement
that this button had to reflect
the various installation states
of an app.
Whether you're buying the app,
whether the app is being
installed or downloaded,
they did all these by
reusing what TVMLKit provides.
And that's the common theme we
want to stress to you today.
Reuse TVMLKit as much
as possible and extend
for the parts that
we do not provide.
So templates.
If you've used TVMLKit it
follows a set path when it,
when you inject it into
the framework it ends
up on the screen.
TV mark-up language is
consists of multiple elements,
all with unique names.
And when it enters the framework
it goes to the TVElementFactory.
This is the central registry
that knows about all elements
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is the central registry
that knows about all elements
and is able to translate
that into data structures
that the rest of the
framework understands.
The TVInterfaceFactory
is the class we use
to generate user interfaces
and place them currently
on the screen.
And this is how TVML
ends up on your screen.
So let's look at what happens
when we extend templates.
When it comes to extension
of templates, it's as simple
as adding your own mark-up in
the TVML that you send to us.
It goes through the
same process,
it enters the element
factory, gets translated,
but when it hits the
TVInterfaceFactory,
because we do not know
about your user interfaces,
we'll ask you for it.
When you've given us the user
interface the TVInterfaceFactory
will put it on the screen
itself, very simple.
So now that you have an idea
of how everything works,
let's look at things in detail.
There are three steps
that you have to worry
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
There are three steps
that you have to worry
about when you want
to extend templates,
and the very first thing
is to define mark-up.
Mark-up in TVML is
basically XML.
And you have an idea of what
your user interface looks
like on the screen.
You have to translate that
into a structure that kind
of resembles what
it should appear
on the screen in mark-up itself.
In our example, we wanted a
banner on the stackTemplate.
This banner had an animated
background and if you wanted
to be able to control the
animations using a switch,
within TVML.
Therefore, this element,
myBanner has a property
called animated.
Additionally, we
also wanted a button,
but because there
is no requirement
for additional functionality,
we could just use
what TVML provides,
and this is a form of a button.
So now that you have an idea
of what your user interface is
represented in mark-up you have
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of what your user interface is
represented in mark-up you have
to tell the framework about it.
And this is as simple
as registering your unique
element name with us.
Registration has to be done once
before application controller
startup so that we're fully
aware of all the elements
that we have to take care of.
It's as simple as telling the
TVElementFactory that you want
to associate a TVViewElement
class
and your custom, element name.
The TVViewElement is the base
data structure that we use
to translate your mark-up
into something that the rest
of the framework understands.
Along with TVViewElement,
there are two other
subclasses that we use.
TVImageElement deals
with images specifically
and TVTextElement has special
handling for text itself.
Now that we have registered the
elements, this is the next step,
the third step that involves
a little work on your end,
but still we try to
keep things simple,
with only just two steps.
The very first thing
you have to do is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The very first thing
you have to do is
to setup an interface
creator that conforms
to the TVInterfaceCreating
protocol.
This particular object
is the one
that vends your user
interface when we ask for it
and there are some call
back methods that you have
to implement from the
TVInterfaceCreating protocol
declaration that
pertains to what sort
of UI you want to return.
The next step is when we call
into your interface
creator class,
configure your user
interface and return it to us.
As I stressed before, reuse
TVMLKit as much as possible
because we have done a
lot of work to ensure
that our elements are
performing and look
and feel good onto tvOS.
So let's take a look
at an example
of what this interface
creator looks like.
Over here I have a
MyInterfaceCreator class
that conforms to
TVInterfaceCreating.
Because we are only
interested vetting a view
for the better we are going to
implement the makeView element,
existingView call back method.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
existingView call back method.
Once this class has been set
up, all you have to do is
to register an instance of it
with the TVInterfaceFactory.
Looking at makeView in detail,
we can see that TVMLKit
furnishes you with an element
and a optional existingView.
So in the case of the
banner, we just need
to inspect the element
name itself.
We're particularly interested
in the myBanner element name
and when we find
something like that,
we create an instance
of this view.
Because the myBanner has an
element property we can easily
inspect this using the element
that the call back
method provides
and then assign it
to the view itself.
We also know that we have
a button in the view,
and because this is a
TVMLKit button, it's as simple
as asking the TVInterfaceFactory
for this particular element
and returning the view
to all myBanner view.
Finally of course,
return your view.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In the case of default
framework behavior,
you have to return nil.
Now we've talked
a lot about views,
what about view controllers?
TVMLKit has view controllers
and they are exposed in a form
of a shelf lockups that
expands horizontally or a grid
that expands vertically.
So by using the TVMLKit
call back
to return view controllers
you can substitute these
for your own view controllers.
The usage is similar to
makeView and in this case,
we still furnish
you with an element
but an existingViewController
and we expect an
existingViewController
to be returned.
Now you're thinking, Aha!
Collection of views.
Collection of views has
views that are cells,
so this is how I can
customize my own lockups.
Remember this example?
The App Store theme specifically
only had a requirement
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The App Store theme specifically
only had a requirement
to have a unique cell.
Of unique custom layouts
and focus behaviors,
everything else, as you can see,
is extended to UMLKit shelf.
The titles go up
and down depending
on whether the focus is
on the element beneath it.
So, new in tvOS 10,
we are allowing you
to specify your own custom
collection view cell.
This allows you to have
custom layouts for the cell
and most importantly
participate in focus events
when the cell comes into focus.
To do this there are two
things you need to do.
The very first thing is to use
this new API that we're exposing
that allows you to give us
a collectionView CellClass
when we ask for it for
a particular element.
And when we build the user
interface on the screen,
we would use makeView to
allow you to customize,
configure the cell
and return it to us.
We would provide you the custom
collection view cell that's deep
queued from the collection
view using the existing view
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
queued from the collection
view using the existing view
parameter itself.
So I'd like to invite Parry on
stage to give a demonstration
of how this works, Parry.
[ Applause ]
>> Thank you, Jeremy.
Hi, my name is Parry and
I'm going to demo you how
to use custom cells in TVMLKit.
Now custom cells
are really nice,
if you want to use TVMLKit
collections like shelves
and grids, but you want
to add your own cell
to showcase your content
through a custom layout
and focus mechanism.
So I'm going to show
you a sample app
that I am working
on based on TVMLKit.
And then later on, I'm going
to enhance it with custom cells
to make appear better.
So let's get to it.
So I'm going to switch
over to my computer,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and I have here Xcode project
open for my application
that I'm working on
based on TVMLKit.
Now let me talk about
this application.
It's an app that lets users
browse through their photos.
So the application
that JavaScript
and the associated XML files are
actually hosted on my machine,
and let me go over them
right in front of you.
So here's one of the pages
from that app that is going
to showcase user's photo albums.
Now you can see it's a stacked
template that has a nice banner
with a background
image, and it has a shelf
to showcase the albums and each
album is basically represented
by a lockup.
Now each one of these
lockups embeds an image
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
from the album that
it represents.
Other than some custom styling
to make this lockup
a little bigger,
I have not customized
TVMLKit at all.
So it's kind of out
of stock TVMLKit app.
So let's run this real quick
and see what it looks
like right now.
And for that I'm going to
switch over to Apple TV.
So there's the app, that's
the stacked template document
that I talked about.
So you see the nice
banner on the top
and the shelf at the bottom.
And you know, I have to say just
out of the box it
looks pretty nice.
It's functional and the
bigger lockups do make a lot
of difference.
But I think it can
be a little better.
So, consider this, how about
instead of just taking one photo
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, consider this, how about
instead of just taking one photo
from the album, to
represent it on this page.
What if we chose multiple
photos, featured photos
from that album, and use that to
put the album on this document?
Now I'm going to just
think about it a little.
How about we create a
collage of these photos
when the album is not
focused, and then fly them
out into a nice grid when
the album does get focused?
That will be cool.
But more than that, it'll give
a nice context to the user
of what the album is about.
Because the user gets to see
more photos from the album.
Now this is a really
nice use case
for having custom
cells with TVMLKit.
So let me show you how to do it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So I'm going to switch
back, to my computer
and the first thing I want
to do is create a mark-up
spec for what I just said.
It's kind of a translation of
what your visual representation
of your user interface
is in terms of an XML
that TVMLKit can understand.
So I have that here right
now, and as you can see,
it's again a stacked
template that has a shelf,
but instead of lockups,
it has a new element
that I have created
called FlyoutCell.
That's the cell that
I just described.
I'm calling it flyout because
the images just fly out from it.
And as mentioned
in the description,
I want multiple photos
in this cell, hence,
I have multiple image
elements as children.
Now there's one important
thing to note,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now there's one important
thing to note,
is that for all custom cells,
they have to be accompanied
with three styles, and
they are width, height,
and a new style we've added into
tvOS 10 called TV focus margin.
Now TVMLKit uses
width and height
to give your cells a nice
frame, in the collection.
And it uses TV focus
margin as a hint
to know how much
your cell is going
to grow when it gets focused.
It uses this information
to create nice spacing
between shelves, and also
to readjust the shelf header
when the cell underneath
it gets focused.
So now that we have the
spec, what's the next step?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We know we have to add this
new element into TVMLKit,
so let's do that real quick.
So for that I'm going to
head over to AppDelegate
and in the method application
didFinishLaunching WithOptions.
I'm going to quickly
drop the code
that I wrote earlier,
to do just that.
So using this I've just
added my FlyoutCell,
using TVElementFactory
to TVMLKit.
Now TVMLKit also wants me to
enhance the interface creator
by extending it, so that I can
configure my cell myself, right.
So let's do that
real quick as well.
So, that's all the configuration
required for TVMLKit,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, that's all the configuration
required for TVMLKit,
now let's have a look at the
implementation of these classes,
starting off with the
ExtendedInterfaceCreator.
Now for custom cells you
need to implement two APIs.
First, the
collectionViewCellClass,
this is required to map
your custom elements
to the collectionViewCellClass
you want to use for it.
And second, makeView,
this one is required
to configure your cell
with your element.
So let's quickly fill in these
blanks, with a bit of code
that I've written before.
So there goes the
mapping for my custom cell
with the collectionViewCellClass
that I want to use for it.
And similarly, the
mapping to configure
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And similarly, the
mapping to configure
that collectionViewCell
with my element.
Now an important
thing to note here is
that the existing view
parameter would always be valid,
because TVMLKit just dequeued it
from the collection view
to get it configured.
So it's always going to be
there, for custom cells.
Now before I jump into the
configuration of my flyout cell,
let's have a look at the
FlyoutCell class itself.
So that's the
FlyoutCollectionViewCell class
that I'm using to
represent my flyoutCell.
And as you can see, it
basically subclasses a
UICollectionViewCell, in
itself, it's got nothing to do
with TVMLKit, it's
just a cell class.
I can use it in a native
app or any other app.
The important point to note
here is that it accepts an array
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The important point to note
here is that it accepts an array
of image views that it uses
to configure its contents.
And these image views are the
ones that we want to configure
in our extended interface
creator
from the TV view element.
So let's head back to
extended interface creator
and add that code.
So that's the configuration,
it's not much,
but the important
part here is this.
I am trading over all the
children of the element
and extracting the
image elements out of it
and simply reusing TVMLKit to
create an image view for me.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and simply reusing TVMLKit to
create an image view for me.
Now out of the box,
this is really,
really good because what
it gives me is downloading
of remote images, it gives
me scaling and cropping
to fit the bounds so that the
user interface is performing.
And it also gives
me some caching
in case I reuse those
images somewhere else.
So reusing these TVMLKit views,
and other infrastructure
is really beneficial.
I highly encourage it.
So, with that we've configured
all the code and everything
in TVMLKit knows
about our element.
There's only one thing remaining
to do, which is to go back
to the stacked document
that I showed earlier,
and replace all the
lockups with the FlyoutCell
that I have just added.
So I'm going to head back there,
remove all of these lockups,
and add my FlyoutCell.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and add my FlyoutCell.
Now there were three albums,
there are three FlyoutCells
still,
each FlyoutCell has,
four images in it.
And when you add these cells,
don't forget to add the style
as well, that's required,
it's a must.
So now that we've added
everything, let's rerun this app
and see what it looks like now.
So I'm going to switch
over to Apple TV,
and there's the flyout cell.
[ Applause ]
And you can immediately tell
it looks so much better,
then just having one
image, it just looks
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
then just having one
image, it just looks
so much more immersive.
And notice that the cell
just fits into TVMLKit,
all the spacing is right,
even the header, the album,
it moves up and down as the
cell underneath it gets focused.
It just feels like it
belongs inside TVMLKit,
although you added it.
So there you have it,
custom cells are really easy
to implement, and it lets
you add a lot of value
to your application, by
reusing what TVMLKit provides
but by also showcasing your
content in the way you want.
Thank you.
[ Applause ]
>> Thank you, Parry.
I think Parry spend more
time building the FlyoutCell
than actually configuring
TVMLKit for that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
than actually configuring
TVMLKit for that.
So before we continue, I'd
like to do a quick recap
of what we've seen today.
The very first thing when it
comes to extending templates is
to define a custom mark-up that
describes your user interface.
Register it with a
TVElementFactory so we know
about it and are
able to translate it
into TV view elements.
Provide an extended
interface creator
so that you can vend this user
interface whenever we stop
building the UI on the screen.
And most importantly, use the
TVViewElement and its properties
and attributes to configure your
user interface before displaying
it on the screen.
So that's all there is
to extending templates,
it's really simple.
And we are all really excited
to see what you can
build with this.
But before we continue, there
are a few important things
that we want you to know.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Your user interface is
represented by elements
within the document in TVML.
And this document can
be updated at any time.
Take for example a
shelf with lockups
as results, in a
search template.
As you search this shelf will
get updated using JavaScript
and the contents will change,
that's what a document
update is.
Now, when we build the user,
rebuild the user interface
when document updates happen,
we would call into the,
extended interface creator,
and it is your job to look
at the update type
in the element
and figure out what's changed.
For example, the children might
change, and as a good parent,
you don't really want
to throw away children,
because that's not a nice
thing to do [laughter].
Instead, reuse cells, reuse
views as much as possible.
In our initial example
for returning the banner,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In our initial example
for returning the banner,
we weren't really
being a good citizen
in the TVMLKit ecosystem, we
didn't reuse views at all.
Let's see if we can change this.
It's as simple as
changing two lines of code,
in this case we look at the
existingView that's part
of the call back
and we try to figure
out if this view is a
view that we expect,
in this case a MyBanner view.
If it's not, we instantiate
a new copy of it.
Now because we have a TVMLKit
button, based on TVMLKit,
we have to do the right thing as
well, and reuse it by passing it
to the extended, by passing it
to the TVInterfaceFactory, in,
the existing view parameter.
Now in this particular example,
because MyBanner is
a really simple view,
that is totally fine to
update it all the time,
we don't really look
at the update type.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But if your view hierarchy
is way more complex.
For performance reasons, we
highly encourage you to look
at the update type and
figure out what has changed.
That's the first line that you
have to change and the second.
Now, new in tvOS
10 is this concept
of light and dark appearance.
If you have a custom view that
you're using with TVMLKit,
you can listen to trait
collection changes to figure
out if you're in light or dark.
We have a session,
What's New in tvOS
that absolutely explains
what you must do,
and I highly encourage
you to check that out.
In the case that you are
a good citizen of TVMLKit
and you reuse our components,
thank you very much.
We highly encourage you to
check the style update hint
from the element update type.
This gives you an idea
of whether your view is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This gives you an idea
of whether your view is
in the light or dark appearance,
and this reuses the
document update facility
and it's the only
avenue available for you
to update your views for
light or dark appearance.
Because they are TVMLKit
components you have
to reuse them.
And more importantly,
you have to forward
into the TVInterfaceFactory
so we can do the right thing.
If you have a native app
or rather you have your
own view controllers
and you have a TVMLKit based
application, you can mix them
with the framework itself.
This is as simple as defining
a custom template element,
once again registering
it with element factory.
And where we built
the user interface
for a particular
template via loading,
return your view controller
and you're all set to go.
Another way to use TVMLKit with
your existing apps, native apps,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Another way to use TVMLKit with
your existing apps, native apps,
is by hosting the
navigation controller
that we provide, as
a sub application.
You've already learned how
to create a TV application
controller,
and I'd like to highlight that
in this case you do not have
to specify a window,
because you already have one.
Choose the view controller
that you're presenting
in navigation controller with.
Once you have a TV
application controller,
take its navigation
controller and present it.
An alternative to this is to
use an instance of UIWindow,
and in this particular
example, you would have
to specify the window parameter.
Once JavaScript starts up and
application logic executes,
TVMLKit will do the right thing
and bring your window
key invisible.
And with that, I'd like to hand
over the time to Christopher,
to talk to you about how you can
extend application functionality
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to talk to you about how you can
extend application functionality
through extending
JavaScript, Chris.
[ Applause ]
>> Thanks Jeremy.
Hi, I'm Christopher,
I'm a TVMLKit engineer.
So we just saw how you can
extend the templating engine
in TVMLKit to use
custom mark-up,
implement your own
views, view controllers,
and collection view cells.
You can also extend the
scripting engine of TVMLKit
which is powered
by JavaScriptCore
to implement your own app
specific functionality
in JavaScript or
expose to JavaScript.
There are three main
ways to inject code
into the JavaScript context
of your TVML application,
let's take a look.
First, you can simply load
additional JavaScript libraries
at run time.
Second, you can use native
code to interact directly
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Second, you can use native
code to interact directly
with the JavaScript context in
your application and do things
like invoke functions into
JavaScript or pass data back
and forth between environments.
Third, you can take
native classes
and you can actually
bridge them into JavaScript
to make them accessible to your
scripts using some simple class
conventions in JavaScriptCore.
Let's go into detail
into each one
of these methods starting
with the simplest.
When your TVML application
loads,
the first thing that's going
to happen is, TVMLKit is going
to fetch a JavaScript file
that contains the
app.onlaunch call back
where control will be
handed over to JavaScript
for your TVML application.
Startup has to wait until this
application.js file is fetched
and evaluated before
app.onlaunch can execute.
If you have a large application,
it's a good idea to break
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you have a large application,
it's a good idea to break
up the code into separate
files to speed up startup time.
This is a common pattern
and TVMLKit supports this
by allowing you to load
additional JavaScript
at any point in the
application lifecycle.
Your JavaScript libraries are
where you will define variables
and functions that get shared
globally across your scripts.
Let's take a look at the
evaluate scripts global function
that TVMLKit JS provides.
Generally you'd want to call
this in your app.onlaunch
but you can actually
use it anywhere.
The function takes an
array of script URLs
and a completion call
back as arguments.
When your completion call back
is executed, you'll be able
to use the variables
and functions
that were defined
in your libraries.
But there are a few
things to keep in mind.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
When you call evaluate
scripts, TVMLKit JS is going
to execute the code,
including any side effects
in your JavaScript files.
So don't call evaluate scripts
multiple times on the same file.
Also, be careful if you
have scripts that depend
on other scripts, that you
load them in the correct order.
Evaluate scripts fetches
the array of script URLs
in parallel, and then
executes them in sequence.
If any of the scripts
are unavailable,
none of the scripts
will execute,
so always check the
success argument
to your completion
call back to make sure
that your library
functionality is available.
And finally, I'd just
like to remind everyone
that even though TVMLKit
offers many web like APIs,
your TVML application
is not a web browser.
So you may find some
JavaScript libraries on the web
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So you may find some
JavaScript libraries on the web
that will be helpful to you
but some may not be compatible,
especially if they rely
on browser functionality
like a global window object
or a global document object.
Just keep that in mind.
But you don't have to limit
yourself to just JavaScript
in your TVML applications,
you can actually call
into the JavaScript
environment from native code.
From here you can do things
like pipe UI application events
down into JavaScript
or push and pull data
between JavaScript and native.
In TVML, your JavaScript context
is managed for you by TVMLKit
in a class called the
TVApplicationController.
JavaScript executes on a
separate thread so you have
to schedule your
interactions with it.
In the simplest form, all you
have to do is call a method
on this TVApplicationController,
and pass in a block
to be evaluated.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and pass in a block
to be evaluated.
When your block executes,
you'll get a reference back
to the JS context, from
here, you can eval strings
as JavaScript code, you can
invoke methods on objects,
and you can get and
set properties
into JavaScript using
native values.
Just make sure that you
don't retain this JSContext
or use it anywhere
outside of the block.
Since your JavaScript is all
happening on a separate thread,
you also want to be careful
that you don't perform any
blocking operations while you're
evaluating this block,
as you may deadlock
with the main thread.
For more information on
JSContext and JavaScriptCore,
please see the 2013 WWDC
session on JavaScriptCore.
Let's take a look at an
example of how we would call
into JavaScript code from
our Swift application.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
into JavaScript code from
our Swift application.
Here we're looking
at the Swift code
for our TVML app's app delegate.
We've implemented a stub here
for the UIApplication
delegate method
to handle custom URL schemes.
If we wanted to pass this
URL down into JavaScript,
all we have to do is
ask the appController
to evaluate a block in
the JavaScript context.
When this block executes,
we'll have a reference
to the JSContext, from here we
can access properties directly
on the JavaScript
global scope object.
We can take native values
or objects and use them
as JavaScript properties
or in this case,
as a function argument.
Here, we're invoking the
on open URL global function
that was defined in JavaScript
and passing along a string
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that was defined in JavaScript
and passing along a string
of the URL from the
UIApplication delegate
call back.
Just like that we've
exposed new functionality
into our TVMLKit application
and exposed application
events into JavaScript.
Next, let's talk about bridging.
So we just saw how super easy
it is to take native values
and use them in JavaScript,
for simple types like strings,
numbers, and arrays
this is already handled
for you by JavaScriptCore.
If you want to use your
own classes, all you have
to do is follow a few
simple class conventions
and JavaScriptCore can actually
bridge your classes as well.
Let's take a look.
So there are three
main steps here.
First, you have to
declare a custom protocol
that extends JSExport,
extends JSExport,
which comes from JavaScriptCore.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which comes from JavaScriptCore.
Second, we're going to define
our classes using Swift
and extending this
native, this protocol
to expose our native classes.
And third, we're going to take
the instance of our classes
or the class itself that we want
to expose and use a call back
on the TV application
controller delegate
to prepare the JSContext
before control gets handed
over to JavaScript
during app on launch.
Let's take a look at an
approach of how we would go
about creating a wrapper
around store kit if we wanted
to expose something like in
app purchase functionality
to JavaScript.
We start off by defining
our protocol,
here's where we'd specify
properties or methods
that we wanted JavaScriptCore
to bridge for us.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that we wanted JavaScriptCore
to bridge for us.
Here we'll just leave it
as a stub but you can see
that we've extended JSExport
and defined a protocol called
StoreKitWrapperProtocol.
Next, we will create a class
for our store kit wrapper
that extends NSObject and
implements this custom protocol.
Once again I've left the details
stubbed out but this would be
where you'd define your
native functionality
that you wanted JavaScript
to call into.
And finally, we implement the
TVApplicationControllerDelegate
method to evaluate app
JavaScript in context.
This gets called before
app.onlaunch executes
and allows us to expose our
custom functionality before
control gets handed
over to JavaScript.
That's really all
there is to it.
We've now defined
a native class,
we've gone through the
steps to make it accessible
to our TVML application's
JavaScript.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to our TVML application's
JavaScript.
So in this session we've seen
how you can leverage native
functionality to enhance
your TVML applications.
You can extend templates
using custom mark-up
for your own views and
collection view cells.
You can actually host TVMLKit
inside of a native application
or use your own native view
controllers inside a TVMLKit.
You can even extend the
scripting environment in TVMLKit
to bridge native classes, type
application events through,
and load additional libraries.
I hope we've shown
you how easy it is
to build app specific
functionality
in your TVMLKit apps
that's custom to your brand.
TVMLKit is a really simple
API for building complex apps
with high quality results
and minimal overhead.
I encourage you to
check out the TVML guide
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I encourage you to
check out the TVML guide
and TVML catalog sample
applications for more ideas
on how to extend
and use TVMLKit.
Please also check out the
Apple developer website
for programming guides, sample
code, and documentation.
Also, check out these other
sessions that happen this year
at WWDC 2016, especially
Developing Apps
for TVMLKit Part 1,
which has a great demo
of building an app
from start to finish.
Thank you, and enjoy
the rest of WWDC 2016.