Session 217WWDC 2014

Take the plunge into advanced extension concepts such as creating custom action extensions. Dive deep into extension architecture to learn how to provide a consistent experience between extensions and your app. See how to utilize extensions with Safari to bridge the gap between your websites and native apps, and discover how to make great extensions that users will love.

Good morning everybody.

Thanks for coming.

Welcome to Creating Extensions for iOS and OS X, Part Two.

I'm Damien.

I'm from Core OS.

And we apparently have a user facing feature this year.

[ Cheers and Applause ]

Glad to see everybody's excited about Extensions.

Let's dive right in.

So before we talk about what an extension is,let's talk a little bit about what an app isand why Extensions are different.

So for an app, it's still in iOS 8, even with Extensions,is the most important experience to the user.

On iOS, the app owns the entire screen.

On OS X, the cursor focus goes to the front-most app.

This is still the number one priority for our users.

And on iOS, apps are completely managedby the user via the App Store.

And OS X the user can drag them to the trash, move them around.

Apps are entirely managed by the user.

So what about Extensions?

So Extensions are important to the user.

But they're not more important than the current app.

They are there to augment the app's experience.

And rather than directly managing them,Extensions come and go with apps.

So the user isn't going to be purchasingor installing individual Extensions.

They're going to be getting those Extensions with the appsthat they download from the store.

So Extensions are built separately.

They are a separate target in XCode.

So we have this new section in XCodefor app extension template targets.

So when you want to create an extension,you're getting a new piece of code in your appthat is actually a separate bundleand admits a separate executable.

And with that executable comes a distinct set of entitlements.

And when we have a separate executable with its distinctof entitlements on disk, that allows the operating systemto know that these two things, the app and the extension,are different entities.

And with that, you're getting a different process.

So an extension is running in an isolated address spacefrom your app and it executes completely independently.

So this means that the system, even if your app is not running,can still fire up your extension,even if your app is suspended.

That doesn't affect any of your Extensions running for the user.

And because of this, the system can optimize eachexperience separately.

So we can schedule them, and even if the app goes away,your extension still sticks around.

So here's an example of an extensionand what the user might doto invoke your extension and its UI.

Here we just have a little network thing.

So it's a new social networking app.

And it's bundling a social sharing extension.

So we see it in the far right there with the purple icon.

And I go to this site and I want to share this with my friendson my new social network.

So the user will see an icon representing my app.

But what that means is that I'm going to be using the extensionfor social sharing vended by that app.

So in previous releases of iOS we've been able to do this,but the Facebook and the Twitter experiences, et cetera,have all been provided by Apple.

Now we're letting anyone who wantsto provide a social sharing extension not only provide itbut define their own experience.

So in this case, when the user elects to share,they're getting a window that is designed by the developerof this social networking app with whatever experiencewhatever experience that app developer wants to provide.

So that's a high levelof how Extensions are architected on our system.

Let's talk a little bitabout how we actually extend the experience of your appand project it into other parts of the system.

So as we saw yesterday in Part One,Extensions are a very focused experience.

And the operating system takes careof seamlessly merging the experience that you providein your extension with the current appor just whatever the current system UI is.

So you guys are going to want to provide codeto make the experience your own.

And that's going to almost certainly mean that you're goingto want to re-use at least some of the code from your app.

So we hope you've been using the Model View Controller paradigm.

Features like Extensions are exactly why weso desperately encourage you guysto adopt this design pattern year after year,because chances are with your extension, you're going to wantto share at least the data model and probably someof the View Controller layers, too.

You probably don't want to share the view of your appbecause your app is designed around takingup the whole screen whereas your extension will not.

But that's only one-third of your code.

You don't want to haveto rewrite the entire two-thirds of it.

You want to be able to share code between the two.

And if only computer science had come up with a wayto allow the same code to exist in two processes without havingto duplicate those code pages.

I think we might have a solution to this.

And I think that solution's called Frameworks.

So, on iOS, in iOS 8, we're now allowing you to ship Frameworkswithin your app bundle.

[ Applause ]

Don't get too excited.

So this is obviously new to iOS, but you've been able to do thison OS X since the dawn of time.

But it's a brand new capability to iOS.

And what we're doing with it is we're also encrypting theframeworks that you ship in your app bundlewith the same encryption that your apps are encryptedwith to give you that same level of protectionagainst piracy and well, piracy.

[Laughter] So it's critical to notethat these frameworks are not general code sharing mechanisms.

So you're not going to have many appson the system referencing the same copy of a framework.

These frameworks are here to facilitate sharing betweenand an app and all of its Extensions.

So the code that that framework contains can be used by the appor any of the Extensions it bundles,but nothing else on the system.

So when you use when you bundle a frameworkwith your app, there are some implicationsfor your minimum deployment target.

If your app links the framework,we're going to change its minimum deployment targetto iOS 8 because as I said before,we're encrypting these frameworks.

And previous versions of the operating system don't knowabout how to decrypt them when you use them.

However, if you're just shipping your appand then there's a few Extensions you havethat all link in a framework,your app's minimum deployment target doesn't change at all.

Your extension functionality obviously won't be availableto previous versions of iOS, but the app will still be ableto run without any problems.

So that's a very brief overview of embedded frameworks on iOS.

To learn more, I encourage you to go to the session tomorrowat 3:15 in Presidio, Building Modern Frameworks,where it'll cover API usage, how to write a good framework,how to bundle it, all that good stuff.

But for now, you've got Frameworks.

And it seems like you guys are excited about it.

So, another topic for code sharing is API availability.

If you're writing one of these frameworks,or if you're bundling one of these frameworks,what code are you going to be usingbetween your app and your extension?

So, the vast majority of our API is going to be availablefor Extensions to use.

But there are going to be some exceptions.

And these exceptions are going to be marked explicitlywith a new kind of unavailability macro.

And here's an example of what that looks like.

So, UIApplication or with UIApplication,the shared application method has been explicitly markedas unavailable.

And the UIKit folks have helpfully provided an errormessage that says: Use a view controller based solutionwhere appropriate.

I'm in Core OS, no idea what that means.

But I'm sure you guys have an idea.

Now, if you're dropping down to Super [inaudible] APIthat has underscores, there's goingto be a corresponding availability macro therethat is evaluated the same way by the toolsand will generate the same errors at build time.

So that's unavailability.

Like I said, the vast majorityof cases you probably won't need to worry about it.

But if you do trip across an API use in your extensionthat is not allowed, you'll know as soon as possibleat build time before you can even run the extension.

So that's how you share codewith your extension and your app.

But at run time you're going to wantto create a consistent experience, too.

And a consistent experience often means sharing the same setof resources and making sure that changes the user has madeto their data in your extension are reflectedin the app the next time they see it, or vice versa.

So we have a few data sharing solutionsfor you for Extensions.

So the first thing to understand isthat an extension has a separate containerfrom its app by default.

It's just like how two apps are segregated from each other.

They don't have access to each other's data.

But for any extension you bundle,you can opt to share specific bits of datathat will help you provide that consistent experiencethat all of our users expect.

And you can do this with what's called a shared container.

So this is based on a new concept called an App Group.

And this provides a shared storage area for kindof just general data sharing between your app your extension.

So if you have some custom data models or custom databasesthat your app and your extension need to use,this is a good place to put those files and access them.

However, you have to rememberthat there's nothing stopping your extension and your appfrom running at the same time.

Your app may be in a long-running background task.

It may not have been suspended yet.

And it might be writing some data to that shared container.

And then the user might bring up your extension.

So what this means is that you have to make sureto safely coordinate all the readsand writes for those files.

You have to make sure that you only write to the filewhen there are no readers contending for it.

And that you're only reading when the file isin a consistent state.

Otherwise, you're going to blow up your file,or it's just going to get corrupted.

So we introduce some sort of synchronization scheme hereso that if the extension writes, it holds off the app.

And if the app writes, it holds off the extension.

And they're both dealing with a consistent view of the universe.

And here are a few of those technologies.

The first one is NSFileCoordination,which kind of provides a general inner process synchronizationstrategy for your extension andfor your extension and your app.

If you're using CoreData, you can get a lot of this for free.

There are certain CoreData backing storesthat are documented as being usablefor multiple processes at the same time.

And sqLite also makes some of these guarantees.

So if you're using one of those two technologies,chances are you're already set.

But if you have something more custom, you're going to wantto use NSFileCoordination.

But if you're talking about more structured data that is, say,vended by Apple's APIs like NSUserDefaults,you can end up sharing much more easily.

So, an app and its extension both have differentdefaults domains.

But you can set up a shared domainwith the initWithSuiteName API.

And you create this suite, and the API manages access to itfor your app and your extension so that you don't have to worryabout making sure that you're not writingto that backing storewhen someone else is trying to read from it.

The API coordinates all of that for you.

And this is a really easy way for, say,the user to modify some setting in the appwhich then the extension can pick up on its next invocation.

There's a similar story for keychains.

So the shared keychain is based on an app group.

And the app group can encompass a few appsas well as your Extensions.

So by default, as I said, the extensionand the app have a different keychain.

But you can set up a shared keychain with an access group.

There's an issue right now in the first betawhere this is actually team ID-based.

So if you're familiar with thatwhere you pre-fix your bundle identifier with a team IDin order to facilitate sharing,that's how you do it in the first seed.

We're going to fix this up for App Groups by the time we ship.

So in terms of privacy, it's a slightly different story.

When I say privacy, I mean the dialog that comesup when an app is tryingto access certain sensitive user data like photos or contacts.

You'll get a dialog saying:"Would you like to allow this app to have accessto this piece of data?"

And the user can either decline or allow.

So when the user allows your app to have accessto a certain piece of data, it's actually goingto cover the entirety of your app bundle,including Extensions.

So that the user, once they have approved your app for accessto your photos, they don't have to then go and approve allof your Extensions for access to the same data.

Now, there are going to be some Extensions to thisor sorry some exceptions to this rule.

But in general, the rule isthat approval covers the entirety of your app.

So let's go over best practices a little bit.

As we said at the beginning,the front-most app is the most important thing.

So it's very important that your exceptions be lean.

These things do not have the full runof the system like the app does.

The app's still there.

It's still using the lion's share of system resources.

The Extensions are very focused, very purpose-built.

And it's important that they get in, do their job, and get out.

And be stateless.

You might know that we kill apps aggressivelyor suspend them on iOS.

We're doubling down on that with Extensions.

And we're going to be more aggressive.

And because of this, there is no general multi-taskingfunctionality available to Extensions.

So no VoIP, no long-running background tasks,that kind of thing.

We do support a short task completion before we suspendor kill the extension.

But this is meant to give you time to flush any dirty stateto disk so that the user doesn't lose their data and sothat the app can pick that up.

And finally, be awesome.

Make these things seamless.

Make them useful to our users.

And as a user of your products, I can't wait to be surprisedand delighted by what you guys turn out.

With that, I'd like to turn it over to Aki.

[ Applause ]

Thank you.

Thank you Damien.

Hi, I'm Aki Inoue from Cocoa Group.

Today, I'm discussing an exciting new feature,Action Extensions for iOS and OS X.

Yesterday in Part One, Ian, Matt and Guy introduced Extensionsand two Extensions point along with key technologiessuch as remote view controller and activation rules.

Damien explained foundation of technologies for Extensions.

Action is an extension point that utilizesand integrates all these best technologies.

Let's get started.

So, Action is a screenshot [inaudible] system to services,an inter-application collaboration technologyavailable since the first release of OS X.

Action operates with user selection inside the hostapplication that is it extends the system framework,not just the single application or service.

Earlier in this conference, you have seen oneof Action Extension's Markup operating inside manyapplications on Yosemite.

In fact, this extension is availableto image attachments throughout the system.

And we're going to go down to viewDidLoad,which is where we should consume the extension item.

To add something to uphold the input itemfrom the extension context, and we're goingto grab the first image item provider.

And we're going to make sure that it has an item conformingto our type identifier of a type image.

And then we're actually going to load that image.

And with the magic of NSItemProvider,we're going to it's going to be coerced from a URLinto an item auto-magically for you.

We actually take a look at the signatureof these block parametersand perform all the coercions behind the scenes for you.

I thought that was cool.

[ Applause ]

And then we're going to take that item,we're going to assign it to our image propertiesso that we can hold onto it.

And then we're also going to show it in our imageView.

Once we're done with it, I'm scrolling past,we're going to need to be able to take this dataand send it back to the host testing application.

So let's set that up.

We're going to create an extension item.

We're going to check that we're not editing for the Web.

That will come later.

And we're going to attach the newly-created image,the flattened image, the image containing all the adornments,into the extension item using NSItemProvider.

This time we're just, we're not going to supply a URL,but we're going to supply an image.

And then as Aki talked about earlier,we're going to finish the requestby calling completeRequestReturningItemsand passing the extensionItem.

Let's build and run.

And let's edit.

Pulling it up and annotating the image.

And you can see we actually have data flowing across the wire.

We can dismiss, and the data goes back.

That wasn't all that interestingbecause I didn't actually make any edits.

So I'll make an edit this time.

Put an appropriate label in here, in the speech bubble.

Having fun at the park.

Hit Done. And you'll notice now our image has been replaced.

The data has made it back from our custom extensionto our test application.

And we have round-tripped a custom action on iOS.

Now, while this is cool, I'm really here to show youabout how this works, can work, with Safari and the Web.

So let's go ahead and enhance this custom actionto actually pull its data out of a live DOMand then replace the data in that DOM when it's done.

Let's do that now.

Going back, and stop.

And now you may have seen some of my notes earlierabout adding Web support.

We're going to scroll back up.

And this time we're going to add an else conditionto receive a URL from Safari.

You notice we're going to have an else.

And if we have an itemConformingToTypeIdentifierKUTTypePropertyList, this is important because we're goingto be sending a dictionary.

We're going to unpack the image URL out of this dictionary.

Also set up our little editing for Web flag to Yes.

And then we're setting up an NSURLSessionDownloadTaskto actually perform the download.

If the download succeeds, we unpack the image dataand render into a UIImage.

Again, stashing the image away in our propertyand assigning it to the imageView.

If we're unable to download, we'll get an NSLog.

And on the other side of it, in Done,when we're done editing the image,we need to pack it back into a property list.

And I've got some code to do that here.

You'll see that we're going to take the flattened imageand write out a temporary file here.

And then we're going to actually create a JPEG string of thatand pack that into a Web dictionary basically creating adata URL that Safari can then swap back into the DOM.

So, everything's wired up there.

Let's go into our JavaScript.

As I talked about earlier, we are expected to provide the runand finalized functions.

And let's do that now.

Run, we're going to iterate over all the images in the DOM.

And we're going to send themover in the imageUrls key to the custom action.

And we're also going to send the base URI.

Our custom action is only going to consume the first image,but you know, this is written for growth.

And then finally, when the data comes backfrom the custom action, we're going to replace the imageby taking that encoded data URL and shoving itinto the image using theor replacing the image source property.

Save. Build and run.

Up comes our application.

We know this works.

Let's home out.

And let's to go Safari.

I happen to have a Web server running in local hostwith a picture, again,of my kids just hanging out at the park.

Let's see if we can edit this image.

Hitting Annotate Image.

Up slides the custom action with the data from Safari.

Now let's edit and provide an appropriate speech bubble.

Hit Done. And now you can see there's a live replacementof the data right there in Safari using the JavaScriptthat I just showed you.

[ Applause ]

So, Safari Custom Actions, as you just saw,provide the flexibility of the Web marriedto the power of Extensions.

You can transform Web data really, really easily.

And you can float a native interface right over the topof it, which allows you to create these rich work flowsthat were unimaginable in previous releases.

So as Damien talked about,Extensions are secure by default.

They don't share data unless you tell them to.

And they have a one-to-one correspondencewith the hosting app.

That way you have your own address space in whichto make your mistakes and your action.

And the last thing we really want to encourage youto do is just to have fun with this feature.

And don't think of it as sticking new thingsonto things like barnacles.

Think of it as constructing these awesome new workflowsthat you were really unable to explore before now.

If you've never been to the Apple Developer Forums,you can interact with employees like myself,Aki and Damien there, and provide peer-to-peer support.

Thank you for coming to learn about Extensions.

And we can't wait to see what you guys do with the feature.

Thank you.

Apple, Inc.AAPL1 Infinite LoopCupertinoCA95014US

ASCIIwwdc

Searchable full-text transcripts of WWDC sessions.

An NSHipster Project

Created by normalizing and indexing video transcript files provided for WWDC videos. Check out the app's source code on GitHub for additional implementation details, as well as information about the webservice APIs made available.