[ Music ]
[ Applause ]
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?
I think we look like engineers.
[ 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 ]
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.
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.
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.
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.
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.
[ 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 ]
[ 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.
[ Applause ]