Learn more about the new features in Swift Playgrounds, such as support for localized content and user-added pages. Learn how to leverage these new features to build engaging content in the latest playground book format. Harness external accessories using the new PlaygroundBluetooth framework, and take advantage of new frameworks added in iOS 11.
Hello, everyone, and welcome to What's New in Swift Playgrounds.
My name is Connor. I'm an engineer on the Swift Playgrounds Team. And today, along with my colleagues Grace and Najla, I'll be sharing with you some of what's new in Swift Playgrounds since last year's conference.
Today's session will be broken up into three parts.
First, we'll take a quick look at the Playground book format to ensure that everyone is on the same page.
Then, we'll talk about many of the enhancements which have been made to support building better Playground books.
And finally, we'll introduce a brand-new API for interacting with and connecting to Bluetooth accessories in Playgrounds, allowing you to provide a consistent user experience. So let's get started by talking about Playground books.
Swift Playgrounds supports two file formats, the classic Playground file format used by Xcode as well as the Playground book file format, which allows you to control the experience which your users see.
Playground books are split up into chapters, which are then further subdivided into pages.
Playground books may contain resources which are used either at runtime or in the prose which you show to your users. All of this is done with a package-based file format.
If you're not familiar with what a package-based file format is, essentially instead of being a flat file, it's a folder which itself contains other files and folders which make up the document.
If we take a peek inside the Playground book, we can see inside there some PLIST files, some Swift files, and a bunch of directories which make up the structure. Let's first take a look at the manifest files. You can think of these as something that's very similar to an app's info.plist.
The manifest PLIST provides book-, chapter-, and page-level metadata, such as the name of the page or the icon which is used in the document browser.
Manifest files also specify the options for the book, chapter, or page, such as whether or not the live view is visible by default or if you want Playground logging to be turned on.
The other major component of a Playground book are Swift files, and there are three different kinds of Swift files inside of Playground books.
The first of these is the Contents.swift file.
This is the source file with which your users interact, and it's where you can store the prose which is shown to your user inside of special markup comments in the Swift file.
There's also the LiveView.swift file. This allows you to provide an always on live view, which provides a rich and interactive experience for your users for the entire time they're on the page instead of just when they're running their code.
And finally, you also have the auxiliary source files.
These are stored in the book, chapter, and page and allow you to provide additional API through separate Swift modules which are automatically imported at each level.
For more information on the Playground book file format, I'd really recommend that you take a look at last year's session, Introducing Swift Playgrounds, where some of my colleagues go into this in a lot more depth.
There's also really great documentation available on developer.apple.com.
Let's now take a look at some of the new features in Swift Playgrounds since last year.
First up is support for copying code between pages.
This allows you to build a Playground book which continues a narrative from page to page while allowing users to evolve the code that they're writing.
So when I open up a page that uses this feature, as a user, I see a prompt to either bring over my code from the previous page or to start coding immediately.
If I then tap on the button to bring my code forward, then my implementation from the previous page is automatically copied for me and the source editor is shown, allowing me to begin coding.
The next new feature is support for speed control in Swift Playgrounds.
This allows you to control the speed of execution, and there's two forms for this.
First up is support for stepping through code as it executes.
So if you tap the speed control in the live view at the bottom left, you can select Step Through My Code, and then as the code executes in the live view, the line of code, which corresponds to the current action, is highlighted in the source editor. So you can see, as Bite moves around the puzzle world, the line of code directing the action is highlighted.
Swift Playgrounds now also supports running faster than the default speed if your Playground book supports it. So again, you can tap on the speed control in the live view and then select Run Faster or Run Fastest.
Learn to Code 1 and 2 take advantage of this feature to make Bite move more quickly throughout the puzzle world.
Swift Playgrounds will now show runtime errors which occur in your Playgrounds.
So in this case, I have created an array with five items, and then I try and access the item at index 5, which results in an index out of range error.
Swift Playgrounds is able to determine which line of code caused execution to crash and then highlights the line with the text that's provided. Users are now able to add, delete, rename, reorder, and duplicate pages inside of Playground books, which they create inside of Swift Playgrounds, including all of the Apple-provided starting points.
Swift Playgrounds is now localized into a few more languages to increase its reach.
So Swift Playgrounds and all of the Apple-provided content is now available in simplified Chinese, Japanese, French, German, and Latin American Spanish. And you as an author can localize into any of these languages or any of the others which iOS supports.
Coming in Swift Playgrounds 2 is support for the iOS 11 SDK, and this means that a handful of new frameworks are now available for use in Playgrounds in Swift Playgrounds 2. This includes ARKit, CoreML, IOSurface, PDFKit, and Vision.
Additionally, Playgrounds may now access the camera if they're running on iOS 11.
You can use the AVFoundation APIs to get access to the camera.
It's important to note, though, that this won't work on earlier versions of iOS, so if your Playground depends on the camera, we recommend that you set its deployment target to iOS 11.
And now, let's hop into a demo to take a look at a couple of these features.
OK, so here I have Swift Playgrounds, and I'm going to go ahead and launch it. And Najla, Grace, and I are each working on Playground books representing kind of our kitchen where we're going to use Swift code to make some things. And I'm going to start out by making a cake.
So I'll go ahead and open up my Playground book. And we're going to start from the very beginning by making our, making some butter on our own.
So we've got this makeButter function and we've got the cream that we need for the butter. So I'll go in and just add some code to churn that cream, which will then produce the butter that we want. I can then run my code, and then we'll see in the live view that, hey, we got the cream, we've churned it, and then we have butter. So it's then, Swift Playgrounds is then telling us that we've successfully completed the task. I'll go on to the next page, and we're going to use that butter to make some frosting. And instead of having to take a author-provided version of butter, I'm going to be able to pull my butter function from the previous page.
So I'll tap on Bring Over My Code, and then I see the makeButter function that I implemented is copied over to this page.
Additionally, the authors provided a makeFrosting function, which I'll then fill out. So we've got all the ingredients we need for the frosting: the butter, powdered sugar, vanilla, and milk.
So I'll go ahead and make this return frosting, which I can do by mixing together these ingredients.
Let's look at the powdered sugar, the butter, the vanilla, and the milk.
And because I want to see exactly what happens to make this frosting, I'm going to enable Step Through My Code.
We'll see that we start the makeFrosting function, then we start to make butter, and we see the live view update as we make the butter. Look at the powdered sugar, the vanilla, and the milk. Then, we mix it all together to get frosting.
And so there we've completed the task on this page that we want.
So I'll move forward. And now, we're going to go on and start making the cake.
But if I look at this, there's a lot of ingredients here that it wants me to collect, and I think there's going to be a little bit more work that I need to make this cake, and I'm kind of running short on time.
So I'm going to pretend that I'm on a cooking show and move straight to the end.
So I'll tap on this Let's Eat Cake page.
And Swift Playgrounds is telling me that I should go back and finish making this cake, but because I can go to any page at all, I'm able to tap in this Start Cooking on This Page button, which will then use the default implementation of the cake. So we'll see the authors provided a makeButter and a makeFrosting function.
Then, the author has all of the ingredients needed for the cake. The ingredients are then mixed together into a batter, which is then baked in an oven, and then we let that hot cake cool before frosting it. So I'm going to come in here at the bottom and just call a function to eat the cake.
Because I want to go as quickly as possible to get through this, I'm going to actually tap on Run Fastest, which will then go through each step very, very quickly. We can see in just a matter of moments I have the cake that I was looking for.
So great. I've now showed you a handful of features that are new in Swift Playgrounds.
Let's now take a look at how you can adopt them in your Playground books.
The first feature I showed you was support for copying code between pages.
This allows you to craft a Playground book where the user is constantly refining their implementation of a particular function or of other code.
For a user, when I look at a page which is being used as the source of copyable code, I really don't actually see much difference.
I just see an editable area where I can insert some code. But if we take a peek at the code underneath, there's a little bit of stuff that you as the author provide to let Swift Playgrounds know what should be copied.
That is these copy source tags, which allow you to tag a region of the page with an identifier, which then you can reference later.
On a page onto which code is being copied, as a user, when I first open it, instead of being presented with a source editor, I'm presented with the option to either copy my code from the previous page or use the default implementation.
If I haven't yet successfully completed that page, instead of being asked if I want to copy code, I'm asked if I want to go back to that page to finish it first.
But I'm still presented with the option to start working on this page immediately.
Once the user makes a selection to either copy code or use the default implementation, then the regular source editor's presented with a code they expect. Let's take a look at how this happens in the source code itself.
And it's very similar to the other case.
Instead of providing copy source tags, though, you provide a copy destination tag, which tells Swift Playgrounds the page from which you want to copy as well as the identifier on that page for the range of code which should be copied because you're able to copy code from multiple sources onto a single page.
Then, you place this inside of the editable code region into which you want to place the copied code. There's also a little bit of stuff that needs to be placed in the manifest file to support copying code between pages. So there are a couple of keys, the ready to copy instructions and the not ready to copy instructions.
These refer to markup text, which is shown with Swift Playgrounds is either ready to copy because the user has successfully completed the previous page or when it's not ready to copy because the user hasn't yet finished the page. And you're able to provide the text that makes sense for your playground book to tell the user what they should be doing here.
There are also a handful of optional keys -- the CopyCommandButtonTitle key, the NavigateCommandButtonTitle key, and the DefaultCommandButtonTitle.
These all refer to the titles of the buttons so that you can customize them to your Playground book.
It's worth noting, though, that if you don't provide any of these keys, Swift Playgrounds will use a default title instead. It's not possible to hide any of these buttons in the UI.
The other feature, which I showed you, was support for controlling the speed of execution in Playgrounds.
Swift Playground now supports both stepping through code as well as running faster than the default.
The Step Through My Code mode as well as its sibling, Step Slowly, is enabled for all Playgrounds.
This is because users should always be able to enable this mode to see what's happening in their code.
Run Faster and Run Fastest, however, we can't enable those by default because not all Playground books can actually run faster. Some operations, you just can't make it go faster.
So Playground pages in books may opt into run faster or in running fastest. Let's take another look at how Step Through My Code works.
So when the user taps on the run, the speed control, rather, and selects Step Through My Code, then their, the code runs normally, but the line of code which is running is highlighted on the left.
Let's see how this works under the hood.
So if you have in your Playground book some straight-line code that's running synchronously like this where we create a string, iterate over each character of the string, and then print it out, there's actually nothing that you need to do.
Swift Playgrounds will automatically insert delays so that every visible line of code takes an appreciable amount of time so this code will highlight correctly.
There is one case which needs some special care, and that's if you as a Playground book author are providing asynchronous API to your users, which under the hood is actually implemented asynchronously.
So in this case, we have a moveForward function, which is going to just schedule some work on a background queue.
While this would be a good practice in an app, it's not so great for a Playground because when you -- when the user calls the moveForward function, it will only be highlighted for the amount of time it takes to schedule this background work, not for the amount of time it takes to actually move forward. So instead, you need to make your functions which appear to be synchronous actually be synchronous, and you can do this with a little bit of code.
So first, at the top of your function, you can get the current run loop and then have a variable, which indicates whether or not the asynchronous operation has completed. Then, at the end, you need to make sure that the function doesn't exit until the asynchronous operation has finished. So you can do that by having a while loop which keeps the current run loop running until the didFinish flag is set to true.
In the callback, after your, whatever work you would be normally doing in the callback, you need to do a little bit extra.
First, you need to set the didFinish flag to true so that that while loop will exit.
You then need to run a lock on that run loop to tell it to stop so that the CFRunLoop run call will terminate.
And then, because of how the CF API works, you need to tell that run loop to wake up so that it will actually perform with the block that you scheduled.
The other half of speed control is support for running faster than the default speed.
Again, this is accessed through the speed control in the bottom left of the live view. The user can tap on Run Fastest if it's supported, and then the Playground book does whatever it can to run faster or run fastest.
Since not all Playground pages can actually run faster, this requires an opt in from the author to enable these modes, and that's by setting the maximum supported execution speed to the maximum speed at which you can run.
If you leave this out, Swift Playgrounds will infer the default, the speed to the normal speed, which would mean that only the Run My Code Speed would be shown.
But you can also set it to faster or fastest depending on the fastest possible speed you support.
To adopt this feature, you just need to listen for a notification, which is posted when the user changes the execution speed.
That's this playgroundPageExecution ModeDidChange notification.
Instead of this callback, you can then ask the current Playground page for its execution mode and then update animation speeds or anything else for the new mode that the user has selected. So with that, I'd like to bring my colleague, Grace, up on stage to talk about a handful of the other enhancements we've made to Playground books.
Grace? All right.
Thanks, Connor. I'm so excited to talk to you about some of the enhancements that have been made to the Playground book format to better serve you all as authors and developers.
The first thing that I'd like to talk about is the introduction of the minimum Swift Playgrounds version key.
This is an optional string that will allow you to specify the minimum app version that can be used to open your documents.
Next, let's talk about the deployment target and the Swift version keys.
These keys have been present since the original release Playground book format, but earlier versions of the app had hard-coded iOS 10.0 and Swift 3.0 to these keys.
However, now your selections are honored.
Additionally, Swift version is now a required key for you to fill in.
This is all stored in the book level Manifest.plist. And for Swift version, you should use the major and the minor version of Swift that you used to write your book.
Swift Playgrounds now allows you to specify subtitles for your document.
This is another optional string in the book level Manifest.plist, and if you don't provide it, Swift Playgrounds will just fill in the Swift version of your book.
So here in Grace's Kitchen, I've used Cooking with Playgrounds for my subtitle, and it shows below my document in the document picker.
Next, Swift Playgrounds has replaced the single Resources directory with two resources, two Resource directories, PublicResources and PrivateResources.
Any files that you want your users to be able to access while they're using your book, either in the file picker or the image picker, should go in the PublicResources directory.
And any files that you don't want your user to be able to access should go in the PrivateResource directory.
Those files could be localization files or hints files that you don't want your user to peek at while they're using your book.
Next, Swift Playgrounds now allows you to create specific runtime issues that will show up in line.
So to do this, you can call fatal error, and the string that's passed in will show up in line with other results while your user is using the book, if they ever hit it.
So next, let's talk about how you can support user-editing in your Playground books through the use of template pages.
A new feature in Swift Playgrounds allows your users to add, remove, rename, duplicate, and reorder pages within your Playgrounds books.
You can see this functionality already in our starting points templates.
But to show it off a little bit here, I'd like to hop into a demo.
So I'm going to go ahead and open up Grace's Kitchen, and this is a book that I created for my users to have a recipe book on their iPad with Swift code. So in my kitchen, I have three recipes: butter, frosting, and cake.
And my mom would tell me that this is not the most healthy recipe book, so I want my users to be able to add some of their own.
So if we go into the Edit button, I can add a page through the + button in the top left.
And then, I'm going to add a recipe for pancakes.
Not the most healthy, but we're getting there. So if I tap Done and then I navigate to my Pancakes page, we can see that I as the author have provided some prose, and then for sake of time, I've also written out our pancakes recipe in code.
And now, when I tap Run My Code, this Playground book will intelligently generate a recipe for pancakes.
And to show you how you can adopt this in your books, let's hop back to the slides.
The first thing that you'll need to do is specify a template page.
Template pages are supported in the last chapter of your book, and this key should go in the chapter's Manifest.plist. And what I mean by template page is the page that's instantiated when your user adds a new page to your book. So to specify this, you should use the TemplatePageFilename key.
This is a string, and the string should be the value of the file that should be instantiated.
So here I've used Template.playgroundpage.
Next, I'd like to talk about the difference between InitialUserPages and pages.
Both of these are keys that store an array of page filenames.
InitialUserPages are pages that the author has created that they want the user to be able to interact with in that way of duplicating, renaming, reordering, et cetera.
If you don't want your user to be able to interact with them in that way, then you should store them in the pages key instead.
So here's the file structure for my Playground book.
We can see that the Manifest.plist in -- is in the chapter level, and that should hold the InitialUserPages key and the TemplatePageFilename key. And then, in my Pages directory, I have my Butter, Frosting, and Cake pages, and I also have my Template page, which is what should be instantiated when a user adds a page. And next, I'd like to pass it off to Najla to talk about localization.
So as Connor mentioned earlier today, the Swift Playgrounds app, along with Apple-provided content, is now localized into six languages.
But if you wanted to localize your own Playground books, then you're not limited to these six languages.
Localizing a Playground book is a lot like localizing an app in that you have the same resource directories, and strings files.
So to localize your Playground book, you're going to need to set the development region key.
The development region key specifies what base language this book was written in, and it's required even if you haven't localized your book yet. If you've, if you are familiar with localizing apps, the development region key is the Playground book equivalent of CFBundleDevelopmentRegion. So just like apps, Swift Playgrounds supports localizing content with strings files, and there are four kinds of strings files that we want to mention today: ManifestPlist, Prose, EditableFields, and QuickHelp.
Now, earlier in this session, Grace talked about public versus private resource directories in your Playground books. And since the strings files are used to communicate with the app itself, it's best that they live in the PrivateResources directory of your book.
So let's hop into some more detail about these strings files.
So Swift Playgrounds supports localizing content from ManifestPlists using a ManifestPlist.strings file.
And an example of some localizing ManifestPlist content in Learn to Code 1 is the table of contents that you can see with all of the exercises. Let's take a closer look at the first exercise in Learn to Code 1, which is called Issuing Commands, and here it is in simplified Chinese.
So Playground book has a ManifestPlist at every level -- at the book level, chapter level, and page level.
Information about an exercise's title is pulled from the page level ManifestPlist, and here's the page level ManifestPlist for the Issuing Commands exercise.
You can see that there's a key called Name, and its value is the title.
The simplified Chinese title for Issuing Commands is pulled from the simplified Chinese ManifestPlist.strings file. And here you can see that the name is defined as a simplified Chinese of Issuing Commands.
So Playground markup blocks are also supported. You can also localize Playground markup blocks in Swift Playgrounds using a Prose.strings file at the page level.
And here's some prose from Issuing Commands that's been localized into German.
To do this, in the Contents.swift file, it specifies a block of localized prose using a localized tag, which takes a key. This key is then defined in the German Prose.strings file as the German translation of our prose.
You can also localize editable fields in Swift Playgrounds by using an EditableFields.strings file.
An example of an editable field in Learn to Code 1 is that Tap to enter code string that you see in some exercises. And here it is in French.
So in the Contents.swift file, it specifies an editable field with an editable code tag that takes the key that's the placeholder that we want to localize.
In our case, the placeholder is called Tap to enter code.
That placeholder is then defined in the EditableField.strings file for French as the French translation of Tap to enter code.
So in Swift Playgrounds 2.0, which you got a beta of on Monday, you can localize API documentation. And here's an example of some API documentation from Learn to Code 1.
It's a move forward command that you can use to move Bite in its little world.
To localize your API documentation, you can use a QuickHelp.strings file.
In you AuxiliarySources file for your exercise, it specifies a block of localized documentation by using a localization key.
That key is then defined in the QuickHelp.strings file. In our case, our documentation is in English, so this is the QuickHelp.strings file for English.
So along with using strings files to localize your Playground books, you can use a Hints.plist to localize default hints.
Here's an example of a hint from Issuing Commands that's been localized into Japanese.
So Issuing Commands only has one hint.
So in our Hints.plist for Japanese, we have one entry that represents our one hint, and its value is the Japanese translation of our hint.
So the localization support in Swift Playgrounds allows you to create really detailed and immersive Playground books for a larger audience, and we're super excited to see all of the Playground books that you localize.
If you want more information about how to localize your Playground books, we have a session later today on Localizing Content for Swift Playgrounds at 3:10.
So let's switch gears and talk about the PlaygroundBluetooth API, which is in Swift Playgrounds 1.5, which shipped on Monday.
So Swift Playgrounds provides full access to CoreBluetooth, which allows you to integrate accessories into your Playground books.
And if you've taken a look at some of the accessory Playground books available, you'll notice that they all have a really great and consistent Playground book experience. And the Playground book API allows you to integrate that experience into your own Playground books.
So there are two main components of the PlaygroundBluetooth framework.
The first is the PlaygroundBluetooth Central Manager, which is responsible for all the logic to interact and manage accessories.
The second is the PlaygroundBluetooth Connection View, which allows you to customize a user interface that users use to interact with accessories.
They both have their own delegates, and the PlaygroundBluetooth Connection View has a PlaygroundBluetooth Connection View data source that provides specific information about an accessory.
So the PlaygroundBluetooth Central Manager provides an interface for connecting to and interacting with accessories.
It's really similar to CoreBluetooth's CBCentralManager, so if you've implemented that before in a Playground, then you could reuse code here.
The Central Manager can take an array of accessory UUIDs to search for, or you can specify to search for all accessories in the vicinity.
The PlaygroundBluetoothCentral ManagerDelegate has methods for interacting with accessories, such as connecting to and disconnecting from accessories.
So the PlaygroundBluetooth ConnectionView provides an interface for displaying the connection status of accessories and allows users to discover, connect to, and disconnect from accessories.
Here's an example of a Connection View that I've customized because my Playground book searches for a Bluetooth printer.
The PlaygroundBluetooth ConnectionViewDelegate has methods for customizing the UI and handling user interactions.
For example, you can use the titleFor delegate method to customize the Connection button.
In my case, I've customized it to say Select Printer.
Lastly, the PlaygroundBluetooth ConnectionViewDataSource is a protocol that's adopted by the Connection View that provides specific information about an accessory.
In my case, the data source provides information about my printer, its title, which is Najla's Printer, and that cute printer icon that's to its left.
You can provide this information using its one method.
So let's hop into a quick demo of the PlaygroundBluetooth framework in action.
So earlier today you saw Grace create a Playground page for making pancakes, and I love pancakes a lot, but I cannot cook.
So what I would really like to do is I would like this Playground book, in addition to generating the recipe, to be able to connect to a Bluetooth printer so that I can print it out and then give it to someone when I want them to make pancakes for me.
So let's go into my Playground book. And what I've done is I've taken Grace's Pancakes page and I've integrated this cute, little Bluetooth printer.
So when I tap on Connect Printer, it's going to search for my printer. And in addition to being able to generate this recipe, when I select Najla's Printer, it's going to print out the recipe.
So keep an eye on the printer and cross your fingers.
Here we go.
So, so now, I have the recipe for pancakes and I can give it to Connor after this session.
So we talked about a lot today.
You got an overview of all of the format changes that have happened in the past year.
You learned how to integrate copy code forward into your Playground books so that you can create a really nice narrative, how to create interesting user editable books so that users can then modify your template pages, how to localize your Playground books, and finally, how to integrate accessories into your Playground books.
For more information about this session, please visit developer.apple.com.
There are also a few related sessions that you can visit or watch online.
Thank you for watching our session, and we hope that you enjoy the rest of the conference.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.