It's so great to see so many of you here today.
for session 505, "What's New in Photos API."
My name is Eric Hanson, I'm the Photos Platform evangelist and I'm joined here this afternoon by two of my colleagues from the Photos engineering team to talk to you about a whole lot of great things new in Photos for iOS and for macOS High Sierra.
So, obviously, we're all here because we care about photography.
And our users as I'm sure most of you know, care deeply about photography.
Every day around the world millions and millions of photos are captured on iOS devices.
Leading to ever-growing libraries filled with tremendous amount of memory and meaningful moments that delight users when they reexperience them.
And so, we want to talk to you about creating great experiences in your apps and integrating with the Photo library.
And we've got some great new API to make this easy for you.
We also want to talk to you about doing this in a way that is high-performing within your app.
Ensuring that the responsiveness of your application is the best it can possibly be.
So, we're going to talk to you about that as well.
And finally, we want to do this in a way that we're not violating the trust with the user.
We're not forcing the user to give up privacy just because they want to integrate with your application and with their photos.
We're going to talk to you about that too.
And on this last point, I'd like to welcome to the stage, my first colleague in the Photos Engineering Team, Hasan Adil.
[ Applause ]
Thank you, Eric.
It's great to see you.
UI Image Picker Controller is a simple and easy to use API for selecting photos and videos in your app.
In iOS 11, we have some great improvements and new features that I'm really excited to share with you today.
At Apple, we care deeply about our users' privacy and security.
Therefore, whenever you presented the UIMessagesViewController, we require you to get the users' authorization for their entire library in order to select a single photo or video.
I'm sure you all well aware, familiar with this alert.
This cause friction in your app.
As well as the user giving up a level of privacy that perhaps they didn't really mean to.
As well as apps that will fail to perform even though there are great features, because the user didn't want to give them access.
Well, we thought we could do better.
So, in iOS 11, we have revamped the privacy and security fundaments of UIMessageViewController.
We started off with three goals.
Put the user in charge of their content.
Create a great user experience in your apps.
And third, give a higher level of privacy to our users.
So, I'm happy to announce that in iOS 11, this alert is no longer needed.
It just works.
[ Applause ]
Let's look at a demo and we'll get into it.
So, here's an app I've just downloaded from the app store.
I'm really excited to use it.
I've filled out, I'm having a great day at WWDC, a little bit nervous, but that's OK.
But I'd like to attach a photo.
Now, let's see what presenting UIMessageViewController in iOS 11 looks like.
It just works.
UIMessageViewController in iOS 11 is now an auto process API.
What that means is that we present the contents of our API from an auto process sandbox and secure environment.
And apps no longer get access to users' photo library.
Only the user is able to interact with UIMessageViewController UI.
When the user makes a selection, we take that photo or video and send it over to your app.
We feel that this removes friction from your app.
As well as gives users a really high level of privacy.
Because no authorization is granted, none is asked for.
We hope you'll like it.
Using it is really easy.
You have to make no additions.
It will just work.
Photos contain rich metadata within them.
This includes the created date.
The format of the photo.
As well as other various metadata.
And we've made it really easy to get to this in iOS 11.
We now provide you a brand0new key with every result of UIImagePickerController.
The key is called UIImagePickerControllerImageURL.
This URL is a file URL, which points to a file in the temporary of your app.
So, if you would like to work with us later, we suggest you move the file to a more permanent location so it stays there.
You can us a URL as is, or you can read the NSDate into your app and process as needed.
In iOS 11 we have introduced a new format called HEIF for photos.
Now we realize that it will take some time for the ecosystem to adopt HEIF fully.
And we made it really easy to do so with UIImagePickerController.
We have a new property called imageExportPresent.
It could be set to two types.
It could be compatible mode, or we can set it to current mode.
Let's look at them.
In compatible mode, if the source photo that the user selected exists as a HEIF formatted photo we will transport a Jpeg and give you a Jpeg version of it.
This is also the default value for the property.
And if you don't need anything different, you don't need to do anything.
However, if you would like the photo as we have it, set the value to current and we'll give you the photo as we have it in Photo library and you might get HEIF and you can deal with that.
We have some great changes when it comes to selecting videos.
But let me step aside for a second, the AVFoundation is Apple's framework for rich editing as well as playback of photos.
And AVFoundation has a rich set of export presets, or formats you can say.
And I'm happy to announce UIImagePickerController supports all of them.
We have a new property called videoExportPreset.
You can use this as a way to tell us what format would you like selected with you to be given to you.
Let's look at an example.
After importAVFoundation you will create an instance of UIImagePickerController and tell us what format you like.
Here, I'm asking you to give me the highest quality video.
And then you present the picker.
When the user makes a selection regardless of what format it was, we're cross coded to a matching format and give you back the video.
This is especially great for getting the videos back in the original format that they existed in.
For a full list of available presets, please see this interface called AVAssetExportSession, or come see us in the lab and we'd be happy to help you.
To my earlier point about increasing the privacy, we also took a deep look at what it takes to add content into a photo library.
Now, since we've made picking seamless, we thought we would make adding awesome also.
So, in iOS 11, if you are to use either of these two methods for saving a photo or a video into the user's library, we have a new security model and a permission level.
The permission level for either of these two methods, the UIImagePickerController one is called UIImageWriteToSave ForusAlbum.
And the other one is UISaveVideoAtPath ToSavedPhotoAlbum.
These require add only authorization.
These are really library questions to get from the user.
Because these will allow you to add in library and not read.
So, we feel like users are going to be very likely, will give you this authorization.
And like before, come see us in the lab if you have any questions.
For our users of PhotoKit, we have something great.
Now, with every result of UIImagePickerController, if you're a PhotoKit user, we also give you back PHAsset object matching the user selection.
This makes it really seamless to integrate PhotoKit across APIs.
Let's look at an example.
So, here's I've implemented the delicate method of UImagePickerController delegate.
And when I get the result dictionary, I have a brand new key, the key is called UIImagePickerController, PHAsset.
You get the value of that key and this key will be the asset object and you are free to use it.
Now, going along with this, we had previously deprecated the ALAssets laboratory framework and now the ALAssets Library reference URLS, which we used to pass to you using a key called UIImagePickerController referenceURL has now be deprecated also.
Yeah, PhotoKit is great and you will love it.
We feel that with these changes to enhance the user privacy, features to make UImagePickerController a powerful and full feature API, that this will satisfy the needs of the majority of apps out there.
However, there are times when you do need deep integration with the Photos frameworks.
And for that we recommend PhotoKit.
To tell you what's new in PhotoKit in iOS 11, I'd like welcome my colleague, Andreas Karlsson.
[ Applause ]
Thank you Hasan.
So, apps related to photography are consistently some of the most popular apps on the App Store.
It takes, both great features and a great user experience to succeed in that market.
I'm very excited to be here today to talk about improvements we have made in PhotoKit that we hope enable you to write both exciting new features and makes it easier to improve the user experience of your apps.
So, let's jump right in.
Let's look at live photo effects that were announced in the keynote on Monday.
So, live photo effects include these loops, which are created by carefully analyzing the video and seamlessly stitching them together into these endless loops.
Also, include bounce which works in a similar way, but as you can see, it works better with dogs.
And finally, there is long exposure, which analyzes the video frames in a live photo to create these amazing looking stills.
So, we believe users are going to have a lot of fun with these, and we're also really excited for what you come up with in your apps when integrating with these new kind of media types.
So, let's look at how you would do that.
Let's look at some code.
So, these are the PhotoKit Media types that currently exist.
They're great, they describe what Asset is, but what's even more important is how the asset gets presented.
And let me explain what I mean by that.
So, if a user shot a video, they would really like to see and use that asset as a video in your app.
If they shot a live photo, they care equally about the still part and the video part.
So, they would like to see that asset as a live photo in your app.
To do this currently, you would look at these three media types.
Image, video and photo live to do the right thing.
With live photo effects this become a bit more muddy and to make this really easy to get right, since it's so important, this year in iOS 11, we're introducing a new property of PHAsset called PlaybackStyle.
Now, PlaybackStyle is the single property you can look at to determine which kind of image manager API to use, what kind of view to present it in, and what kind of UI limits should accompany the view.
So, the PhotoKit has been updated to cover all these new playback styles, but I'd like to go into detail on three of them that relate to life photo affects here in this session.
So, let's start with image animated.
So, new this year, the built in Photos app is afford for animated GIF playback.
[ Applause ]
To playback GIFs in your own apps, you would request the image data from the image manger and then use image iO and core graphics for playback.
Now, the sample app, does include a sample of how to do this.
So, please have a look there in case you would like to do GIF playback.
Next, is live photo.
So, live photos, users care a lot about live photos.
So, getting them presented in your app in the right way is really important, but also really easy.
So, in this case you would request a live photo from the image manager and then you say PHLivePhotoView for playback.
You set the live photo, you'll get back on the view and users can then use three touch to playback a live photo.
Users [inaudible] in the built in photo's app inside your app.
PHLivePhotoView can also be used with live photos outside the user's photo library.
For example, if you transfer them over web service or something similar.
Finally, there is looping video.
And these include both the bounds and loop live photo effects that were introduced this year.
Now, to play these back in your apps, it's very similar to regular video.
So, you would request the player item, and use AVFoundation for play back.
But you would use an AVPlayerLooper to get the looping effect.
So, I hope you have seen how easy it is to present the user's media how they really wanted to be presented.
And we cannot wait to see what you guys come up with in your apps related to these new media kinds.
Next, I'd like to talk about iCloud Photo Library.
So, iCloud Photo Library is really great because users can now put their entire photo library in their pocket.
And this is really great for some users who have really large libraries.
Some users have more than 100,000 photos in their photo library, and they're not that uncommon actually.
So, what kind of user has that many photos?
Well, to get 100,000 photos, you have to take 28 photos per day, every day for 10 years straight.
So, these users obviously love to use the camera and camera apps, but they also tend to download and use a lot of photography-related apps.
These users are really important to all of us in this room.
Now imagine one of these users, after taking their daily 28 photos, they go to the App Store to find an interesting app to use.
They find your app.
They decide to download it and give it a try.
And the first thing they see when they start using your app, is this.
Now, spinner for multiple seconds are not a great user experience.
And this user might uninstall your app right away, or even worse, leave a bad review.
So, you might be thinking, well my app wouldn't do that, or if it does, I'm using PhotoKit and this user has a really large library.
So, maybe this is to be expected.
PhotoKit was designed from the beginning to be really fast and efficient with large photo libraries.
But there are some common mistakes clients make that can mean the difference between operation taking 10 milliseconds, and 10 seconds.
So, how do I fix this?
Well, since it's so easy to end up with something taking a long time, step number 1 is to test your app with a large photo library.
Now we already covered, it's kind of difficult to get that many photos using the camera app.
So, this year we want to make that really easy.
So, we're providing a sample app that you can download called photo library filler.
Download this app and install it on your test device.
It will quickly generate a large library for you to use for testing.
[ Applause ]
So, great you have a large library, you test your app.
Chances are you might start seeing some delays.
So, I'd like to talk about two common problems clients have with PhotoKit and their solutions.
So, let's look at some code.
So, this is how you fetch assets from the users' photos library.
There are two parts to this.
There is the database fetching part, and then dealing with a result.
Let's focus on the database fetching part first.
So, here we're fetching all assets on the library, but we're filtering with a filter predicate on favorite assets.
And we're sorting by creating day.
If you're doing this kind of custom fetches, they are definitely supported, but if you start seeing delays in these kind of custom fetches, it's definitely worth trying to simplify the predicate or simplify the sort descriptor.
And that can mean the difference between this query taking 10 milliseconds and 10 seconds.
The reason for this drastic difference is that you might end up outside the optimized path in the database and trying to get back into the optimized path can really pay off.
So, even better than doing these kind of custom fetches, is to avoid them if it's possible.
So, in this case we can actually fetch the user's favorite smart album and then fetch the assets inside of the smart album.
That gives both the predicate and the sort descriptor for free.
And you're guaranteed to end up in the optimized path in PhotoKit.
So, next, let's look at the result you get back from one of these kinds of fetches.
So, this object is a PHFetch result.
Now in a PHFetch result looks a lot like an array and you can use it a lot like an array.
You can ask for object and index.
You can ask for its count, and you can enumerate it.
But internally, a fetch result works very differently from an array, and is part of the reason PhotoKit can be so fast and efficient with large libraries.
So, let's look at how it works internally.
So, initially it just contains a list of identifiers.
And this means you can get back one fairly quickly.
But as you start using it, additional work has to be performed.
So, let's look at enumeration as an example.
And here we're starting enumeration at index 0.
So you only have an identifier so far, so we need to fetch metadata form the database in order to create a PHAsset object to return to you in the block.
Now, the fetch result is pretty smart.
It's actually going to create a batch at the same time.
So, as we continue enumeration, index 1 and 2 are already in memory.
And then enumeration continues and you get the idea.
It's going to access the disk to get the metadata for subsequent assets.
So, for this kind of small fetch result this doesn't matter.
But I would image this fetch result has 100,000 assets in it.
Each batch takes a couple of kilobytes of memory.
But when you have 100,000 of them you're looking at hundreds of megabytes of memory usage.
And even worse, each batch take a couple of milliseconds to fetch.
But when you have 100,000 of them, you're looking at 10 seconds to enumerate a large fetch result.
So, enumeration is clearly something we should try to avoid if at all possible.
We have found that it's almost always possible to avoid enumeration.
And I would like to look at one example of how it can be avoided.
So, in this case, we're trying to find the index of an asset that inside a fetch result.
Now, we could enumerate the fetch result and compare the objects we get back using is equal.
But as we saw enumeration can be quite slow.
So, even better is to actually use high level API.
In this case, we can use index of object.
And that is able to internally, in the fetch result be really smart and compare the identifiers with the object you're looking for.
And array will define this index without any additional disk access or database fetching at all.
Same goes for contains object.
So, I hope you have seen how easy it is to get a large library to test your app with.
And how easy it can be to really make a huge different in the performance of your app.
Small fixes can mean multiple seconds of time savings.
If you do have questions on PhotoKit performance, please come see us in the lab tomorrow morning.
If you do encounter issues that you're not able to resolve, please file [inaudible].
And if there's one thing you remember from this part of the session, please test your app with the large photo library and take really good care of these really important users.
Next, I'd like to welcome Eric Hanson back to the stage to talk about Photo Project Extensions.
Thank you Andreas.
Thank you very much.
I am really, really excited to finally be able to talk about something we've been working really hard on this year in High Sierra.
So much so that I need a sip of water, sorry.
So, we're going to talk about Photos project extension.
And I think to kick this off we have to talk about what are projects.
You know Apple has been allowing users to create these really rich creative photo centric projects in the photos apps for a very long time.
Actually, going all the way back to iPhoto 1.0 when we first released photobooks.
But this year, we wanted to do something different.
Because during that time, 14 years, you as developers have been building up some really great experiences yourself with your own apps.
And we thought, you know, let's bring this together.
Let's give you an opportunity to actually create something that's a fantastic experience directly within the Photos app.
And that's exactly what we've done with the extensions.
We started working on the API, engage just a few developers to kind of see what they would do with it.
Companies like Shutterfly, who are going to be launching with their own photobooks and photos in the fall.
A company called WhiteWall that allows you to do these gallery quality framed prints.
Wix.com that created a brand-new feature allowing users to easily create web photo albums.
Animoto, that allows users to create these really beautiful movies that are server hosted and integrated with social media.
And a company called ifolor that did something really novel.
They kind of started from the ground floor and looked at this as an opportunity for you know what could they build that really tied into the photos ecosystem and really created some magic for the user.
And I think rather than explain it.
I want to show you a quick demo.
So here we are in the photos app on High Sierra.
And I'm in memories.
And I've got this favorite memory here, together that I'm just going to select.
And I can hover over my project section in the side bar and you see this little button.
And you'll notice that in addition to the Apple offerings we currently have, photos has automatically discovered that I have another application installed, called ifolor wall décor.
So, this extension is now exposed to me.
I simply select that and I'm presented with some choices.
Now these choices are coming from the extension itself.
So, before we've even loaded the extension, the extension is notifying us that you know, before you push a project to me I want the user to make a choice.
I want to be able to fork my own code.
So, they give us the title and the description and the image.
Photos actually lays it out beautifully in the sheet.
And I'm just going to pick that first option.
I hit the create button, and now, their extension, their view controller is going to be pushed directly into photos.
Full view, but this is their UI, this is their experience inside photos.
Now, they've leveraged the memory in this case and taken the hints we provided to lay out this grid.
But they've also taken hints we provided to let me get at all of the images that were considered when the memory was created.
So, you'll notice over here on the bottom right, if you can see it, you can't because it's behind me, 283 images.
And what's was really cool about that is I can actually customize.
So, I'll switch this to unused images, because there's a photo that I like a little bit better.
I'll take this one, that I think would be a really great hero shot.
So, I can just drag that up and customize this layout.
And they went a step further than that.
They let me customize the grid itself in a really novel way.
So, I want to give a little more emphasis to this row.
And maybe move this down.
And I'll move this down to line it up and you know let's do one more.
And I really like that.
So, I could just hit the buy button now, still within photos.
Choose my size, this would show up in the mail.
And I have this memory hanging on the wall in my den.
It's pretty cool.
That's just a really quick tour of ifolor.
[ Applause ]
So, what you want to know is how does this all work.
If you're familiar with the editing extensions in Photos, you already have a good sense of how this works.
We've added a new extension point to Photos; com.apple.photo-project.
And we've added a new template within Xcode that lets you easily create one of these extensions in your own app.
As you saw, in the demo, we automatically discovered your extension, raising the discoverability of your app on the system.
But we took discoverability a step further.
By offering users a direct link to the App Store that brings up the App Store window, but doesn't require them to search for an app with that extension.
It automatically shows only the apps that support that extension point.
And we think this is really going to heighten the ability for users to discover your apps and quickly download them, and start working with them.
So much so that we put a similar App Store link in edit.
And so, if you're already doing image editing extensions, users will have a direct link into the App Store to immediately discover you editing extensions.
It's pretty cool.
So, your extension lives within the app, within your app.
And that's really a great opportunity for you.
Because you may already have an app in the App Store that's got a lot of app specific code, but you probably have some resources and some other sharable code that you could easily move kind of into this extension space and leverage those.
You obviously also have some extension specific code that you would need to write.
A very small amount.
And finally, you just need to add a view controller that implements this protocol.
The PH project extension control protocol.
With all that in place, Photos can immediately discover your extension.
Let the user choose to you know to create a product with that and we simply call this protocol method begin project.
And when we do we send over a couple bits of data.
So, in addition to the photos we're sending you, the project extension context, and we're sending you an object called PHProjectInfo.
You can consume that in whatever way you want.
And then you just quickly call back the completion closure that we hand you.
And that let's Photos know it can install your view controller, full view inside the Photos app.
And from that point, as you saw, it's totally your UI.
It's your experience.
You have all of that API available to you on macOS to leverage from and build a really killed experience for your users.
So, the protocol itself is really simple.
There's an optional property for supported project types and you saw this in the demo I just did.
And this lets you quickly describe the choices you want a user to make.
And you can opt out of this if you want, you just want to straight into the extension.
That's totally possible as well.
And then there are few required functions you need to implement in your view controller.
The first is begin project.
That's where we hand you the context.
And we hand you the product info.
And that's what we call the first time a project is created with your extension.
Now, if a user is coming back to your extension for a project they already created, we instead call resume project.
And again, hand you this extension context.
And finally, if a user is in your extension and they decide to switch away to do something else within photos, we're simply going to call finishProject.
Allowing you to clean up any kind of data you're holding onto.
Maybe quiet down any processor intensive tasks or animations thing like that that you might be doing.
So, PHProject extension context is a container for two really important objects.
One is PHProject, and the other PHPhotoLibrary, which is the library from which you're going to fetch all the assets.
PHProject itself is just a subclass of PHAsset collection.
You may already be familiar with PHAssetCollection.
It's a container.
It's got an array of assets.
It's got a title.
It's got a key asset, key photo.
And what we've done in sub classing that, creating PHProject, is we've added just one property.
But it's a really, really important property for you.
And that is the projectExtensionData.
So, this is where you, the extension can save any data you need to that represents the project the user created.
So, it's really intended for that critical project data.
That is your list of the assetIdenfiers that you're using and that maybe is some basic layout information configuration information.
That's not for images and you know cache, thumbnails, and rosters, things like that.
Because you can create those on the fly or cache those away somewhere else.
So, we want that to be small, but useful.
And we settled on this limit of 1 megabyte.
Because we think you know, an array of assetIdenfiers compressed is really, really easy.
They're just strings.
And we think you can live within 1 megabyte.
And by doing that, we're not bloating user's libraries as they create project after project and explore all these amazing extensions that you're going to create.
So, setting the data, really easy.
We have an object called PHProjectChangeRequest that you simply instantiate and then once you do, you can all this perform changes and weight function on the Photo library.
Inside that, set the data to whatever you want it to be.
In this case, I'm just using an NSKeyedArchiver archive an array of identifiers.
And that's it, it's simple.
So, let's get into some fun stuff.
I want to talk about where the magic begins.
So, you saw in the ifolor demo they really leveraged the memory's feature.
The memory's feature is really, really popular.
Users love this.
Right, while you're sleeping, Photos is working hard all night, going through kind of your photo library, learning sort of about you, right on your device.
It's all happening right there locally.
And it's building this graph of kind of the events that are meaningful to you and the people in your life that are relevant to you.
And through that it's able to serve up these great memories that users just consume on a daily basis.
And so we wanted to make sure you had access to that level of data, right .
These extensions aren't interesting if we just give you an array of photos.
We've got to give you context from which you can create something great.
And that's what we've done with PHProjectInfo.
So, ProductInfo at the top level is broken into sections.
We give you this array of PHProject section objects.
And for a given section, we tell you the type.
So, you think about a memory, we've got like a key photo at the top.
And we call that type cover.
And then we've got this editorial grid that we call type content.
And then we give you this array of content.
It will look something like this.
And inside the contents we actually give you access to the elements, and the asset identifiers and some layout information.
And you might be asking yourself when you look at this construct, why the array and then the array, right.
Why this kind of nested structure.
But if you think about the memory feature it makes sense, right.
We allow users and memories to toggle between showing a summary of photos and showing all photos.
The memory itself is built up from a large pool of assets.
We call these curation levels.
And we wanted to make sure you had access to these different levels of information, right?
We've already done all this hard work.
We've run all this intelligence.
Let's just share it with you and let you build something on top of it.
So, that section content array, is an ordered array, where you always know the object at index 0 is going to be the best of the best.
The most premium.
The most condescended summary of that collection of assets, whereas the object at the very end of the array is going to be the most.
It's going to be everything we considered.
And you get to decide what you want to use.
The fewest, the most, everything in between.
Maybe you want to offer your users a choice.
You want to give them the ability to switch between these.
And you can do that with the context we're giving here.
Next up, cloud asset identifiers.
This is kind of a new concept.
If you're familiar with PhotoKit on iOS, you've not seen this before because it's new.
But, we've never had a construct where we wanted you to save data into a user's photo library.
Data that represents assets but data that might be synced to other devices, that might appear somewhere else at some point.
We want to make sure that the data you're saving is meaningful wherever it shows up.
And so, we've introduced a new object called the PHCloudIdentifier.
And you can think of this as a global identifier for the asset.
But it's not as simple as just a global string.
You know, dealing with the cloud and sync states and all that is really, really complicated.
And we've solved all that for you.
The only thing you have to do with this is just make sure you're always converting from a global identifier to a local identifier before you fetch.
And for that we've just given you a convenience method inside PHPhotoLibrary to do that conversion both ways; from global, from pod identifier to local identifier, and vice versa.
Next, I want to talk about layout.
So, we didn't just want to give you assets and some constructs around the curation.
We wanted to give you some hints about how we present those assets to a user right.
Help you with some of the difficult problems of things like grid layout.
All right, you look at a memory and we've done a lot of hard work already in laying out this curated grid in a really interesting way that's pleasing to the user.
Wouldn't it be great if you had access to that layout.
And you do.
But to do that, we had to establish first kind of set of rules, a coordinate system for you.
So, if you look at the memory, you notice everything aligns to a very specific grid.
It's grid of 4x3 aspect ratio cells.
But that's an odd, non-square kind of dimension to share back and forth.
That's a weird multiplier for you.
So, we simply divided that yet again.
And in this case, this layout is really comprised of 20 uniform columns.
What we call our grid spaces.
And once we have this coordinate system established, you can scale this however you want.
It's just a multiplier for you, for whatever your output is.
Right? If you're rescaling on a resizable window, or working with web browsers of different size, you can use this data to know how to layout the content.
And it also lets us communicate to you placement information.
So, in this example, I have this photo that wants to live in the upper left-hand corner.
So, I can now easily tell you it's at position 00.
It's 8 grid spaces wide and it's 9 grid spaces tall.
Next thing I want to talk about are elements.
So, inside the section constant we give you an array of elements.
And all the elements are subclasses of PHProjectElement.
And there's two really important properties there.
One, is placement, which we just talked about and the other is something called weight.
So, again going back to the memories feature.
We talked to you about, like all the intelligence that we're doing, right?
And ascertaining the most relevant photos in a large pool of assets.
And so, our scoring system.
And we wanted to share that with you.
And so, we do that by given elements weight, right.
it's a normalized weight from 0 to 1.0, the default value is 0.5 meaning it's not horribly significant, but is not horribly insignificant either, if that makes any sense.
But you know it's this normalized score across the entire section.
And you can do amazing things with that, right?
Just really easily, right?
Sort your assets by that.
Decide where you want to chop off, you know a large array of assets and only work with the significant ones.
Right? Present those as choices to a user where you're serving up the higher weighted assets first.
And predicting that that's probably what they're looking for, what they want.
And there's one other bit here.
And this is specific to one of the elements, which is the PHProjectAssetElement.
We have this concept of regions of interest.
You know, as you know there are several ways already in the macOS API to run face detection to find faces in an image.
But form that you don't know the relevancy of those faces.
You don't know if those faces represent someone that is meaningful in someone's life, or it's a face in the crowd.
It's the person walking behind you at a theme park, when you're trying to photograph somebody in your family.
You really don't have an ability to tell the difference.
We wanted to give you something that let you know, and let you trust that if we've marked, if we said it's interesting, it's interesting, right.
And if you leverage this, you create magic for your users.
Without necessarily even knowing why.
And we went one step further.
If you notice we have identifiers on these.
And we actually repurposed those identifiers across images.
So, if we know that this thing that's interesting in this photo is also representing this same thing, or same person in this other photo, we'll give them the same identifier .
So, if you're doing like animation, slideshows, things like that, this is tremendously useful to you.
Because you now can actually correlated positions of images across a large set.
S, I could keep going, in a code walk.
But, I'd rather give you a demo.
Because I think it's really important to show you just how easy it is to create one of these extensions.
So, I'm here in Xcode.
And I promise I will zoom in where necessary, so you will be able to read this.
So, I'm here in Xcode.
And I have a project I started, but it actually does nothing yet.
The only thing it has are some assets that a designed gave me.
And what we're going to build right now, is a slideshow.
And the slideshow is going to be the marriage of the content that Photos is providing and seenkit to do a really compelling kind of 3D animation.
So, let's begin.
So, the first thing I can do is just, I'm on the project and I have this little plus button here at the bottom add a target.
And I'll just add a target here.
And you'll notice we've got this new template, right for PhotoProject extension.
So, I'm going to select that and I'm going to give this a name.
Hit the finished button.
And yes, I want to activate that as a scheme it makes it really easy to run later.
And then, I mentioned that my designer is going to need these assets.
So, they're already in the project, I just want them, basically referenced from within the extension as well.
So, I'm just going to add those via the copy phase.
And that's the whole set of assets.
I just hit add and with that we're ready to write some code.
Now, if you're looking closely, you'll notice that Xcode has already added this group for me for Picture Show for my target.
And inside of it, it's already laid down a view controller for me that conforms to the protocol that we have to implement.
So, I'm going to go into that and first going to add some properties.
So, just a very small set of properties here.
I'm holding on to the context that's handed to me.
I have some arrays to differentiate landscape and portrait assets for my slideshow.
I have an outlet for my scene view.
And I have an animator.
And I have two expected compilers.
I have not imported seenkit.
So, that's an easy one to fix.
And animator is my own class.
I just haven't created it yet.
So, let's go ahead and do that right now.
So, I hit new, I want a Swift file.
And we will call this animator.
And there's my animator.
I'm not going to walk you through all of this.
But it's really, really simple.
So, I'll just tell you a few things it's doing.
When I'm initializing the animation I want to kind of reach into the scene and get out some specific elements of the scene.
I want to find these tagged photo frames in this 3D scene.
And then reach kind of inside them, behind the glass and get at the material that is going to be the photo I'm showing behind the glass of these frames.
So, that's really all I'm doing in the initialize.
And then from that point, the scene, I know it's just going to be spinning around.
It's just this kind of rotation on a table and I have a little trickery that you're like a good magician when you're not looking on switching photos.
And so, I'm just doing that through a couple of timers.
And that's basically the animation.
So, we'll go back to the controller and start filling in the interesting bits.
When a user creates one of these projects, I want to save the data.
Because I want them to be able to come back to this slide show at any point in time.
So, I'm just going to add some data methods.
And what I've got here is a SaveProjectDataFunction that does exactly what you saw on the slide, right?
So, this should look very familiar with what we just talked about.
And then load data, I'm simply reading that back.
I'm getting the Cloud asset identifiers by unarchiving my data.
And I'm just converting to local identifiers.
And from that point, I'm able to do a PHAsset fetch assets request with those local identifiers.
Let's go back up to the top and start filling in the rest.
I just need to initialize my animator.
We talked about that.
Supported project types.
In this case, I don't need to ask the user for anything.
So, I won't fill that in.
It's just a slide show.
But begin project, obviously, I've got some work I want to do here.
So, we'll fill that in.
And what I'm doing in this case is I'm getting at the actual sections array.
And I'm looking for the first section of typed content.
Right? I'm really designing this around a memory, like we just talk about.
And form that, I want the most curated assets.
I want the top-level summary.
And so, I asked for the first object in that array.
From that, get the cloudAssetIdentifiers and I'm good to go.
Now, in the background, I am just saving the project data so that it's there later if the user comes back to the slide show.
Get into resume project, and that's really easy.
I simply hold on to my context load my project data, initialize the animation.
And finally, in finish project, I'm just suspending animation.
I don't want these timers firing, I don't want the fans running while user's doing something else.
I just suspend it.
And believe it or not, that is the entirety of the code for this extension.
That is my slide show.
Now, what I haven't don't is wire up the UI, which I can do really quickly.
So, the template gives me the view for my view controlled.
I'll just delete the default string.
And I'm going to add a scene to this.
And so, we add a seenkit view.
I'll just resize that and just pop in here, set my auto resize and I just want this to be full view.
And the only other thing you need to do to that is choose the scene itself, which I already have in the assets that we loaded in.
And I just need to wire it to my view controller.
So, I'll control drag form file's owner and I see the outlet that we've already added in properties.
And that's it.
We're ready to run.
So, I'll hit play.
It's going to ask me to choose the app, obviously, it's Photos in this case.
And that will build, and succeed.
Photos launches, and I'm just going to pick a memory.
In this case, I want to use, I've got this really cool trip to Hong Kong I'm going to choose.
Hit the plus button and look at that, there's the extension showing up in Photos.
I choose that.
Now, when I do, this is the very first time I run this extension, so I don't have permission as an extension to the entire photo library.
You remember the our API is handing the entire photo library to the extension.
So, user does have to grant that access once.
And just hit okay.
And then the slideshow loads.
[ Applause ]
And I'm just going to show you one additional detail, if you look in the sidebar, there's the project we just created, Hong Kong Island.
This is saved inside that library right next to all the other projects.
So, I choose that and I can see this was created by an extension called Picture Show.
And I can open that.
And it will pop right back into the same slideshow.
So, that is PhotosPojects Extensions [applause].
So, we've talked about a lot in the past 55 minutes or so.
Talking about the frictionless photo picker in iOS.
Really, really nice advancements there, allowing you to get at original URLs.
Having the video quality.
Some great, great stuff there for you.
Andreas took you through the new media presentation types, I can't wait to see how you're going to consume those and the kind of things you do within your apps.
Allowing users to see their content played back the way they'd expect.
He also talked about testing with large image libraries.
And just a reminder there is a sample app now to let you fill out a library with tens of thousands of assets so that you can test that way.
And then, finally we talked about the project extensions.
And I'm really, really excited to see what your all going to create and have in the App Store when macOS High Sierra ships this fall.
So, for more information please check out this link, the developer.apple.com website.
And I want to talk about some related sessions.
Right after this in this hall is going to be a killer, killer session introducing you to vision framework.
I know you want to stick around for that.
Later tonight over in the executive ballroom is the first of two sessions covering depth in iPhone photography with some amazing demos and you really, really want to be there for that as well.
And finally, tonight we're doing something we've never done that WWDC.
We're hosting a photography get together.
It's going to be downstairs in technology lab area, specifically lab J.
And I'll be there, the other 2 speakers in this session will be there.
All of the speakers today talking about Cameron Photos will be there as well as a ton of engineers, management, and we hope to see all of you there.
Enjoy the rest of your show.
Thank you so much.
[ Applause ]