WWDC2018 Session 413

Transcript

[ Music ]
[ Applause ]
>> Good morning.
>> Welcome to Create Your Own
Swift Playgrounds Subscription.
>> We hope you had a great time
at the bash last night and we
know you're all feeling bright
eyed and bushy tailed and ready
to learn about Swift
Playgrounds.
My name is Grace.
>> And my name is Holly.
>> I'm a software engineer on
Swift Playgrounds.
>> And I'm a software engineer
on Xcode Source Editor.
Swift Playgrounds is an app that
allows anyone to code on the
iPad using the Swift Programming
Language.
As authors, you can share your
Playground Books with others by
hosting your own subscription.
>> Today we'll be talking about
how to make a subscription
starting from making Playgrounds
and Playground books and moving
all the way through hosting your
content online as a feed for you
subscribers.
>> Today's session will be
broken up into four parts.
First we'll talk a quick look at
the Playground book format and
new Swift Playgrounds Author
Template for Xcode 9.3.
Then we'll look at the Swift
Playgrounds subscription format
and walk through how to host
your own feed online.
>> And I'm going to go watch you
from offstage so I'll see you
later.
>> Grace and I have been working
on a set of Playground books for
all of you to explore the core
image APIs.
Today we're going to build
another Playground book so that
all of you can explore the CI
filters, some of the built in
ones.
And here you can see me having a
lot of fun going through the
chapter of our book that teaches
about the distortion filters,
which are my personal favorites.
Playground books are a mechanism
for you to construct a guided
interactive exploration of a
particular topic.
Using a Playground book you can
guide your learners through a
sequence of chapters, which are
then further subdivided into
pages.
Each page contains a source
editor, which you see here on
the left.
And you can also choose to
implement an optional, always on
live view, which you see here on
the right.
Live views are used for
visualizing the results of
running the code in the source
editor on a page.
To bundle all of this into a
single file, we use a package
based file format.
This means that a Playground
book is itself a file hierarchy.
It contains a subdirectory for
each chapter and nested within
each chapter is a folder for
each page in that chapter.
And each Playground page folder
contains all of the resources
that are required to run the
code in the source editor and to
display the live view for that
page.
Each level in the Playground
book hierarchy also contains a
property list file for metadata
that Swift Playground uses to
configure the structure of the
book and to construct the table
of contents.
And finally, in addition to the
content that is shown to your
learner in a page, Playground
books may contain additional
Swift files called auxiliary
sources.
And these are stored in folders
names Sources.
Auxiliary sources allow you to
provide additional Swift code
like classes or helper functions
that can be used throughout the
pages in your Playground book.
You can use auxiliary source
files to achieve many different
tasks.
And by utilizing these sources,
you can greatly simplify the
code that you need to write in
each page in your book.
Let's look at an example of
using auxiliary sources to
simplify communicating with the
live view.
You can send values to the live
view by calling the send method
from the Playground Live View
Message Handler protocol, which
is declared in the Playground
Support framework.
Messages are sent to the live
view as Playground Values.
Playground Value is an enum that
is also declared in the
Playground Support framework.
To simplify converting objects
to Playground values I wrote a
protocol called
PlaygroundValueConvertible in a
file called
LiveViewSupport.swift.
And I include this file in the
book-level sources folder of
every Playground book that I
write.
Then for any type that I want to
send to the live view, like a CI
filter for example.
I can extend that type to
conform to
PlaygroundValueConvertible and
implement the asPlaygroundValue
method.
This method will convert the
original object to a
PlaygroundValue.
I also wrote a helper function
called sendValue, which takes in
a PlaygroundValueConvertible and
sends it to the current pages
live view as a PlaygroundValue.
And finally, when I have an
object in a playground page that
I want to send over to the live
view, I can simply call
sendValue and send in that
object as the argument from a
hidden-code block in that
pagescontents.swift.
So as you can see the code that
I wrote in my auxiliary source
file greatly simplified the code
that I needed to write in my
Playground page for sending a
value over to the live view.
For more information on the
Playground book package, I
recommend you take a look at the
Playground Book Format
Reference, which you can find on
developer.apple.com.
Now, let's take a look at the
Swift Playgrounds Author
Template, which you can use to
get started authoring your
Playground books.
The Swift Playgrounds Author
Template is a starter Xcode
project that will help you
create, debug, and produce a
Playground book.
Using the template you can step
through the code for your live
view as if it were an app so
that you can identify bugs more
easily and develop an efficient
workflow for developing your
Playground books.
Here you can see me stepping
through the code for the live
view of the CI filter Playground
book that I showed your earlier.
The Swift Playgrounds Author
Template is available for you to
download from
developer.apple.com.
This Xcode project is compatible
with Swift Playgrounds 2.1 and
Xcode 9.3, both released earlier
this year.
This project includes some
frameworks that were built using
the Swift 4.1 Compiler since
this is what Swift Playgrounds
2.1 currently uses.
So it's really important that
the version of Xcode that you
use for this project also uses
Swift 4.1.
The Swift Playgrounds Author
Template includes three
different targets whose products
will help you author your
Playground books.
The first target is called
Playground Book.
The second is called Book
Sources.
And the third is called Live
View Test App.
The Playground Book Target
produces a Playground book as
its output.
And you can see this in the
products group in the Xcode
Project Navigator.
All of the files for this target
are in the PlaygroundBook group
in Xcode.
And the template contains the
starter files for a playground
book with one chapter and one
page.
The template also includes two
book level auxiliary source
files that provide a default
implementation of the always on
live view for the Playground
book.
Next, the Book Sources target
compiles all of the book-level
auxiliary sources.
And you can see all of the files
for this target in the sources
group inside of the
PlaygroundBook group in the
Xcode Project Navigator.
Compiling these sources allows
you to develop your book-level
sources with full editor
integration.
This means that you'll be able
to use all of the Xcode source
editor features available in any
other Xcode project like code
completion or quick help.
And finally, the LiveViewTestApp
uses this target for displaying
the live view.
So you're implementation for the
live view of your book must be
in your book-level sources if
you want to use the test app for
debugging.
Lastly, we have the
LiveViewTestApp Target.
You can find all of the files
for this target in the
LiveViewTestApp group in Xcode.
This target produces an app that
displays the live view of your
Playground book similarly to how
it would be shown in Swift
Playgrounds.
As I mentioned before, the
implementation for your live
view must be in your book level
auxiliary resources.
The LiveViewTestApp allows you
to debug your live view in a
full screen or in a side-by-side
mode without first having to
export your Playground book to
Swift Playgrounds.
The LiveViewTestApp works on
iPad and in the iOS Simulator.
The Swift Playgrounds Author
Template comes with three
supporting frameworks.
The first two are the
PlaygroundSupport and the
PlaygroundBluetooth Frameworks
from Swift Playgrounds.
Including these frameworks in
the project allows the book
sources and the LiveViewTestApp
Targets to take full advantage
of the APIs from these
frameworks.
And the third supporting frame
work is called LiveViewHost.
And this framework is used by
LiveViewTestApp for displaying
the live view.
To implement your live view,
you'll need to add all of your
code in the book level auxiliary
sources for your Playground
book.
Included in the template is a
view controller for your live
view in a file called
LiveViewController.Swift.
Also included in the template is
a helper function for loading an
instance of your live view in a
file called
LiveViewSupport.Swift.
You can add any other files that
you need to implement your live
view and you can use any of the
Playgrounds frameworks in your
book sources code.
Also included in the template is
a storyboard for you to
configure the UI for your live
view.
You can add any other resources
that your Playground book needs
in the private resources group.
And finally, to configure your
live view test for the test app,
you'll need to implement a
method in AppDelegate.Swift.
Specifically, you'll need to
implement the setUpLiveView
method.
By default, this method loads an
instance of LiveViewController
from LiveView.storybaord from
the helper method that I
mentioned in
LiveViewSupport.swift.
And this is called
instantiateLiveView.
Now I want to invite Grace back
up to the stage and we'll take a
look at the Playground book that
we've been working on using the
Swift Playgrounds Author
Template.
[ Applause ]
OK, so here we're looking at my
Xcode project for the test out
CI filters Playground book that
I showed you a sneak peak of
earlier.
And the idea for this book is
that a learner can create and
manipulate core image filters in
the Source Editor and these
filters will be sent over to the
live view and applied on top of
live camera output for them to
see what those filters look
like.
Here we are looking at the
LiveViewController.Swift folder
and I've implemented one of the
methods that came in the
template and below that I've
added the rest of the code that
I need to display the live
camera output in the live view.
As I mentioned, I also want to
apply core image filters on top
of each frame of the live camera
output, so I've added a few more
files in my book level sources
and implemented a filter
renderer for applying this
filter on top of the live camera
output.
So now if I select the
LiveViewTestApp Target, I can
actually run this code and see
what my live view will look
like.
And I've configured this app to
show the live view in a
side-by-side mode.
So where we can see what the
live view will look like in a
side-by-side mode similarly to
how it would be shown next to
the Source Code Editor in Swift
Playgrounds.
And to simulate sending filters
over to the live view, I've
added a couple of buttons, which
you see here on the left.
And these are implemented in my
test app code.
So now if Grace taps on one of
the filters, we should see that
filter applied to the live
camera output.
So this looks great.
I want to try out some of the
other filters, so Grace I really
like the CIPointillize filter.
So if she taps on that this
looks pretty close but if you
can -- if you notice the pink
filter from before is still
around some of the edges and the
pointillize filter is a little
smaller than we want.
So I'm going to head back over
to Xcode because I think we have
a bug in my filter renderer that
I wrote in a function called
Render.
So I'm going to navigate to that
function using Open Quickly with
Command Shift O.
And I'm going to set a
breakpoint right before this
method returns.
And since each frame of the live
camera output is getting a
filter applied on top of it, we
should hit this breakpoint right
away because this method is
constantly called.
OK great. So we've hit the break
point and now I can inspect any
of my variables here using the
debug console.
So specifically I want too look
at the size of the source image
and the size of the filtered
image and see how those differ.
OK, so as we can see the size of
the filtered image is larger
than the size of the source
image.
And on line 59 I'm rendering the
filtered image to the size of
the filtered image, but really
what I wanted was the size of
the source image.
So I'm going to fix that.
Disable the breakpoint and run
it again.
Let's head back over to the
iPad.
And let's have Grace take the
same steps as before.
So let's tap on CIColorMatrix
and then tap on CIPointillize
and we see that the Pointillize
filter is the correct size, it's
the same size as the original
live camera output, so now I
think all of my code is correct
so I actually want to package up
my Playground group, copy it
over to Playgrounds and see what
this live view actually looks
like.
So if I head back over to Xcode
and select the Playground Book
Scheme, I can press Build, and
then in the Project Navigator my
Playground Book is under the
Build Products Group.
So at this point, you'll want to
copy your Playground Group over
to Swift Playgrounds using
Airdrop or iCloud, but for the
sake of time I've all ready done
that.
So if we head back over to the
iPad and have Grace open Swift
Playgrounds, we'll see that my
test out CI Filter Playground
Book is all ready there.
So let's have Grace open it up
and we'll see what our live view
looks like.
So as you can see we have a CI
filter in the Source Editor and
we've manipulated some of the
input values for that filter.
So if she taps Run My Code, we
should see that filter applied
on top of the camera output.
OK, I really like this filter.
I love this color.
And hey Grace, do you know what
we look like here?
>> What's that?
>> I think we look like
engineers.
>> Yes!
>> Yes [laughing].
[ Applause ]
>> So you just saw us using the
Swift Playgrounds Author
Template to write and debug the
live view for our Playground
book and we hope that these new
workflows will help you be more
efficient in authoring your
Playground books.
Now I'm going to hand it back
over to Grace and we'll learn
about these Swift Playground
Subscription.
[ Applause ]
>> Awesome.
Thank so much, Holly.
So now that we're refreshed on
the Playground Book format and
have learned about the Swift
Playgrounds Author Template,
let's take a look at how to take
those documents and put them
into a subscription.
So first off what is a
subscription?
You should think of a
subscription like Podcasts or
like a magazine subscription.
So when new content is published
by the author, subscribers will
become aware of it.
Subscriptions show up here along
side Apple content.
When you publish a new document
to your subscription, Swift
Playgrounds will fetch it and
display it to the user as a
another document to check out.
Users can subscribe to your
subscription by visiting your
website.
Subscriptions live online as a
feed of downloadable content
that you publish.
The way that you publish your
content will be through
publishing JSON files that have
all of the data that Swift
Playgrounds needs to download
your content.
In case you haven't used it
before, JSON is a techs-based
document format for storing and
exchanging data.
The goal is to communicate to
the consumer of the JSON object
what value your content should
have for each key.
So for example in our
subscription the key title has
the value, WWDC Photo Filters.
The Playground Feed Format is in
two parts.
One part to determine some of
the overarching characteristics
of your subscription and then
one part the documents to tell
us about teach of the documents
within your subscription.
So let's take a look at the
Playground feed format that
you'll use when creating your
subscription.
Our first key is Title.
This value should be a string,
the title of you subscription.
Here's what it should look like
in JSON and here's where the
title shows up in your app
within your subscription cell
within Swift Playgrounds.
The next key is the name of the
publisher, and that's you.
This keys value should also be a
string and it will be the name
of the publisher of the
subscription.
It will show on the detailed
view of each of the documents
within your subscription.
Next is the feed identifier.
This should be a reverse DNS
string for the domain that's
hosting your feed.
We'll get to domains later in
this session and reverse DNS
just means that it will be that
website backwards.
So for example, if I'm hosting
my feed at developer.apple.com,
my feed identifier would become
.apple.developer.
The next key is contact URL.
And this what will be used to
report issues with your feed.
Next is the feed format version.
This will be the version of the
feed format to which your feed
conforms.
This feed format that we're
talking about right now is
Version 1.0.
And once updates are made to the
feed format that you'd like to
incorporate with your
subscription, you can update
your feed.JSON file with the
changes and bump this format
version up within your feed.JSON
file.
And remember that this is a
string so it should go in
quotes.
And lastly we need our documents
key.
So this is the beginning of the
second section of the Playground
feed format.
The value for this key should be
an array of objects that
represent your Playground Books
within your feed.
So next we'll talk about the
format of these objects.
Documents is an array of objects
that represent documents with
key value pairs.
Let's go through what you need
to represent a document and then
we'll put it all together.
Title and overviewSubtitle are
strings.
They should be the tile and the
subtitle for each of your
documents.
And they show up within your
subscription cell and also
within Detail Views for each of
your documents.
Detail subtitle is an optional
string that you can use to
create a different subtitle to
be shown in Detail Views like
here.
If you don't provide one, we'll
just omit that section.
Description is text that should
describe the purpose of your
document.
And it will also show up within
Detail Views and Swift
Playgrounds.
contentIdentifier is another
reverse DNS identifier.
It must be unique to the book
and it must match the
contentIdentifier within your
books manifest.plistfile.
It should start with the feed
identifier of the feed that
contains this book.
So in this example
io.github.WWDCPhotoFilters.
You should host your content at
the same place where you host
your feed.JSON file.
But if you don't that's OK,
you'll just need to include a
secure hash of your Zipped
Playground Book as another key.
And you can learn about this
more in the feed format online.
And there's the
contentIdentifier.
Content version is the way that
you can do versioning with your
book.
You need to increment this when
you update your book, and it
always must match the content
version in your book's manifest.
So next is the URL.
This is very important because
it tells Swift Playgrounds where
to download your book when your
book when your user wants to
download it.
This should be a link to the
zipped copy of your Playground
Book.
The additionalInformation array
allows you to store additional
metadata about your document.
And you can store whatever you
want here.
This is structured as an array
of objects with each object
having key and value pairs.
This example name, made for, and
value WWDC would show up like
this in Swift programs within
the detailed view.
You'll need to include the
publish date and last updated
date of your content.
These dates need to be ISO 8601
formatted and should reflect the
day that you publish this piece
of content and the day that you
last updated this piece of
content.
And lastly, there are three keys
for images used in your
subscription.
The thumbnail URL would show up
here within Swift Playgrounds,
as well as within the detail
view for any of your documents.
Preview Image URLs would show up
here in the detail view for each
of your documents and can show
users a little bit of extra
information about your
Playground.
And in older versions of Swift
Playgrounds, we used this as the
banner image URL.
So to support users that are
using older versions of Swift
Playgrounds, you'll also need to
include this image.
So OK, now that we have finished
up with the feed format, let's
jump into publishing.
So you might be wondering, how
do I publish all of these files
that I've made?
You'll need to put both your
feed.JSON file and all of your
documents that you've written on
the web.
For this, you'll need a web
host.
Publishing your subscription
requires a web host.
There are a number of different
ways that you can do this like
using GitHub pages, using
Squarespace, and others, but for
today we'll be working with an
example of GitHub pages.
GitHub pages is a tool that lets
you create a website for you and
your project and it's hosted
directly from a GitHub
repository.
It uses Git to manage content.
So let's walk through some of
the steps that you'll need to
take to use GitHub pages.
First you will need a GitHub
account.
You can create one through
GitHub's website.
Next, you'll have to make a
repository called
username.github.io.
It must be named in this way or
else it won't work.
And this will be the repository
where you'll store your content.
Once you've cloned that
repository to your Mac, you can
create an index.html file to
serve as the homepage of your
website.
This one here will just display
Hello WWDC.
To learn more about source
control workflows in Xcode,
check out this session from
earlier this week.
After you've created that file,
make sure it's in your
repository, commit your changes,
push, and then visit your
website at username.github.io.
As you continue adding more
files and folders to your
repository and continue to
commit and push them up to your
website, it will update your
repository and therefore
GitHub's website.
So right now the folder only has
one file, index.html.
This will serve as your landing
page for your website.
But as we talked about earlier
you'll need a couple more files
to support your subscription.
So as Holly mentioned, we have
been working on a subscription
called WWDC Photo Filters that
has some really cool photo
filtering content using Core
Image within Swift Playgrounds.
I'm going to walk you though the
levels of our repository to show
how we've organized it as an
example.
The first file that needs to be
included is your feed.JSON file.
We've put ours in our repository
at the same level as our
index.html file.
And next you'll need to store
all of your documents.
Each playground that we've
published is stored in a folder
to keep our repository clean.
We have a folder for each of our
pieces of content.
So ImageTransitions, IntrotoCI
and so on.
So at the top level of our
repository we have our
index.html file, our feed.JSON
file and a folder for each
document.
If I open one of the folders for
a document I see four things --
a zips.playgroundbook file and
three images.
These three images are a banner
image, one preview image, and a
thumbnail image.
The zipped Playground book will
be the Playground book that a
user downloads.
So let's look at how this
compares with our feed.JSON
file.
At the top level we can see that
the feed identifier is the
reverse DNS of our website,
io.github.wwdcPhotoFilters.
In the documents array, there's
an element for each of the four
documents that we've posted.
And if we look at our first
document the contentIdentifier
matches the feed identifier and
adds the first book's title.
For the URL of the book we have
our website
/IntrotoCI/IntrotoCI.
playgroundbook.zip.
And again this is really
important to get right because
it's where Swift Playgrounds
will go to download your
content.
The URLs of your images can be
relative URLs.
So you only need to include the
folder underneath where your
feed.JSON file is stored and
downwards.
So here I just have
IntrotoCI/thumbnail.png.
And each of the documents in
your subscription should mirror
this format.
Once everything is online,
anyone can subscribe to your
feed.
They could do it by manually
typing in the URL that points to
your feed.JSON file, or you can
use universal links so that a
user can tap on a link from
within Safari and get redirected
to Swift Playgrounds.
To do that you'll need to
combine the URL for your feed
and the Universal link prefix
for Swift Playgrounds.
So here's the code for the link
in our index.html file.
I've combined the universal link
prefix,
https/developer.apple.com/ul/ --
you get it [laughs], with our
subscription URL.
Then you can imbed that link in
an anchor element with an href
attribute so users can simply
tap subscribe and be directed to
Swift Playgrounds.
So next I'd like to demo the
steps that you should take to
add a book to your subscription.
[ Applause ]
OK, so like I said, we're
working on this photo filtering
subscription that I think is
really cool.
So I've actually just finished
another book about content aware
resizing.
Content aware resizing is a way
that you can resize your images
without losing the most
important parts of your image.
So I have this photo of Monument
Valley that I think is really
beautiful, but I'd really like
to trim it a little bit and make
the width a little bit smaller.
But I don't want to scale it
down and I don't want to crop it
because I don't want to miss out
on the beautiful sunset and the
monuments.
With content aware resizing, I
can take that photo and look
through all of the different
pixels in the photo, find the
least important vertical seams,
and remove those one-by-one so
that the width gets a little
smaller each time, but I still
have the really important
monuments and the sunset, the
road, and everything is still
there.
So I've written all that code
within a Playground book that
I've called Content Aware
Resizing.
And it's stored within my
Content Aware Resizing folder.
So this is almost done.
All I need to do is zip it up,
so I'm going to select File,
CompressContentAwareResizing.
PlaygroundBook.
So now I have a zipped file of
my Playground book and I'm going
to go ahead and move this to the
Trash.
And lastly, I'm going to need to
move in a couple of images from
the thumbnail and the banner
image, the two required images
within the feed format.
So luckily I have two images on
my desktop called Thumbnail.png
and BannerImage.png.
Adjust these two.
Perfect.
So I'll go ahead and drag that
into my folder.
So if I look within my WWDC
Photo Filters Repository, I have
three folders here right now and
each of them have an image, a
zipped Playground book, and then
another image for the thumbnail.
So this looks pretty good.
I think my folder mirrors that
perfectly.
So I'm ready to put it up and
publish it.
So I've created a workspace for
my repository.
So I'm going to take this folder
and drag it over, put it within
my repository, and now I have
another folder for
ContentAwareResizing.
Double check that everything is
still there and it looks good.
So the last step that we'll need
to take is to update our
feed.JSON file.
So here's that file and you can
see in My Documents array I have
my Image Transitions object, my
Intro to Core Image object, and
my Test Out CI Filters Object.
So I need to add one more object
for ContentAwareResizing.
And luckily I've made a snippet
for it and here we go.
So I've all ready filled most of
this out because of my nails
[laughs], so all I need to do is
type in the title and I'm going
to call this
ContentAwareResizing.
I've decided to omit the
detailed subtitle and I just
have my overview subtitle try
out ContentAwareResizing with
Swift.
I have a description and my
content identifier is
io.github.wwdcphotofilters.
ContentAwareResizing, the title
of my book.
It's the first time I'm
publishing it so my content
version is 1.0.
And my URL maps to my website
and then I have my folder name,
ContentAwareResizing --
/ContentAwareResizing.
PlaygroundBook.zip.
My publish date is right now at
9:40 [laughs].
And my last updated date is also
at 9:40 since publishing it
counts as an update.
I've also included my thumbnail
URL and my Banner Image URL.
For additional information I
have English as a language.
And my Preview Image URLs I've
decided to leave blank for now.
All right, so this all looks
good and now all I need to do is
going to Xcode Source Control,
Commit, make sure all four of
these files are selected.
So I've added three files and I
modified feed.JSON.
I'm going to commit and say
Adding Our Demo Book.
Select Push to Remote.
Cross my fingers.
Invite Holly back on stage.
And, great.
It worked.
Cool.
[ Applause ]
So now I'm going to have Holly
go to our website and subscribe
from there.
So awesome, we have our website
here and you can see we have a
nice subscribe button.
So if Holly taps that she'll be
navigated to Swift Playgrounds,
Subscribe--
Restart QuickTime --
There she is [laughs].
Well, anyway, it's a really cool
book [laughs].
And you can all download it
actually as well because we've
published it to our subscription
now.
It's online at
WWDCPhotoFilters.GitHub.io and
so you can download all of the
four books that we've published.
One is Intro to Core Image.
One is Image Transitions, using
the built in transition filters
within Core Image.
One is Combining Filters within
Core Image.
You can add them on top of each
other.
And then the last one is this
Content Aware Resizing book.
[ Cheering ]
Thank you.
[ Applause ]
And check it out [laughs].
Well, in a second.
There we go.
There's our subscription
[laughing].
[ Applause ]
So now if Holly downloads
Content Aware Resizing --
And opens it up.
Cool, it worked.
So, in the live view on the
right I have this beautiful
picture of Monument Valley and
I'm going to have Holly crop it
a little bit and then run the
code and we'll see what it
produces.
So what this algorithm does is
it looks at all of the vertical
seams in an image, decides which
of the seams are least different
from the ones around it and
removes those one by one.
So now we can see it's a little
bit cropped and it looks
beautiful.
[ Applause ]
That's all we have for today.
For more information please come
visit us in our lab Creating
Content for Swift Playgrounds
today at noon.
>> And for more information on
this session and on our
subscription, you can visit the
Session 413 website on
developer.apple.com.
>> Thanks for joining us today.
>> We can't wait to subscribe to
all of your published
playgrounds.
Thank you.
[ Applause ]