Hi everyone!
Today I want to share with you building share
extensions using Swift.
We're going to write a simple app that lets
us select an image in our photo album, and
share it to our application.
So first what is a share extension?
A share extension is a mini app we can associate
with our main app, that can run from the common
share sheet.
For example, when you select an image, and
then select the share icon, you have a choice
of applications to share the image to.
The usual suspects are Facebook, Twitter,
Message and so on.
Our goal is to make our application available
here.
So I said that this is really a mini app that
we can associate with our main app.
That means the life cycle of the share app
is a bit different for our main app.
A share extension is started by the user selecting
the icon for our app.
iOS will launch the share app.
This has to happen very quickly, or iOS will
shut us down.
We don't want to do anything time-consuming
here.
If the user selects and posts an item, our
code will run.
The item can really be anything shareable.
It can be a URL, image, text, or all of the
above.
Once selected and processed, the app is shut
down.
Let's start by looking at the app we're going
to build.
This app allows us to select a photo from
the photo album on our device.
We'll also select a color to associate with
the photo so we can demonstrate selecting
information outside of the defaults.
The color will tell our app which page it
should save the image.
We then will share the image and the page
with our application.
We're going to ignore the text the user types
in, but you can read it and process it with
the variable contentText.
It's trivial.
When we launch our app, there are two buttons.
One for the red page, and one for the blue
page.
When we go to the red page, the image we selected
for red will be displayed.
The blue page will display the image we associated
with blue.
Our app is composed of the following parts.
We have the main view controller with two
buttons.
Each segues to a view controller capable of
displaying an image.
The image view controllers are assigned a
color red, and a color blue - just so we can
tell the difference.
They look in the user defaults for an image
saved to either red or blue.
In our project we also have a separate target
for the share extension.
This is the "mini" app I talked about eariler.
For this tutorial, we're going to use Apple's
out of the box view controller for sharing.
This view controller is the SLComposeServiceViewController
class.
If we want to do a custom share extension
view, we'd just use our own view controller.
However, we'd also lose the built in functionality.
Since we want the user to select where to
display an image, we have a second view controller
in our share extension.
This is just a table view with a list of selectable
choices.
This could be dynamic and read from a database,
but we'll just use red and blue.
Alright!
Let's implement this app.
The first part is our application.
I won't go into too much detail here.
There's not too much to it.
Two buttons segue.
In the destination view controller code, we
read the image from the user defaults, using
either a red key or blue key.
This is the code for the red view controller.
The next thing we need to do is create our
share extension.
With our app loaded, we go to "File | New
| Target".
We create a share extension, and give it another
project name.
I usually add something like share-extension
at the end of the project name.
This creates a project with single view controller
and storyboard.
Since our app extension is really a second
application, it's in it's own sandbox.
We need a way to share data from this share
app to our main app.
Apple allows you to do this though app groups.
We need to add our app and our share extension
to the same app group.
We'll go to the project page, and select the
Capabilities tab.
From there we'll open up the App Groups section
and turn it on.
We'll also add a app group for these apps.
It starts with groups, and then I usually
use the project name.
We need to do this for both the app and the
share app targets.
The app group name is the name we use for
the user defaults suite name.
This is how we are sharing data between the
applications for this example.
You'd still need to add each to a common app
group if you were using some other way to
share data, such as a common file system or
core database.
When apps are part of the same app group,
they can share the same user defaults.
Back in our share extension target, lets look
at the ShareViewController.
The view controller is a subclass of SLComposeServiceViewController.
This is the default, and for most sharing
tasks, it will accomplish what we need.
It presents a controller with a text edit,
and a place we can display a thumbnail image.
It also allows us to cancel or post.
There are three methods provided for us in
the view controller.
configurationItems, isContentValid, and didSelectPost.
isContentValid is where we would check to
make sure the input data is valid.
It's called first, and will disable the post
button when it evaluates to false.
We'll always return true, because we're not
doing anything with the text.
We'll use another method later to force them
to always pick images.
Configuration items is where we can add more
things for the user to select when they are
sharing.
In our app they are sharing a photo, but they
are also selecting which page to add the image.
This is what we will use to select between
red and blue.
A configuration item has a title, value, and
a tapHandler.
The title is the name of the configuration.
We'll call ours color.
The value is the currently selected value.
When a user selects a configuration item,
we'll launch another sub view controller for
this particular configuration item.
The method to launch the color selection controller
is called the tapHandler.
The color selection view controller is a table
view with the selection items.
There's nothing fancy in the table view controller,
other than the selection choices.
We could make this dynamic, but for this example
we'll just hard code the choices.
We'll pass back their selected value through
delegation.
When the user presses the post button, didSelectPost
is called.
This is where we do something with the user
input.
The view controller has a extensionContext
where we get a list of NSExtensionItems.
This is an immutable array of data sent to
our extension from a parent app.
For our case, the photos app is the parent
app.
The extension item will have a list of attachments
all typed as NSItemProvider.
NSItemProvider items are lazily loaded images,
videos, URLs and so on.
Since we only want a photo, we'll loop through
the attachments, and look for one typed as
an image.
It will have the type identifier kUTTypeImage.
Once we find an image, we'll load it using
loadItemForTypeIdentifier.
This has a completion handler, where we'll
read the image from the URL, and then we'll
save it to defaults.
We save the actual image instead of a pointer,
because the Photos app is not in the same
app group as our app or share extension.
The share extension is saving the image somewhere
where we can read it again.
At this point the app should run, with two
slightly minor points.
The first is, we can select more than one
image.
In fact we can share other things our code
isn't prepared to handle.
The second is when we compile we'll get a
warning when we compile.
It says, "Warning: Embedded binary's NSExtensionActivationRule
is TRUEPREDICATE".
Apple wouldn't accept this in their app store.
What this error is trying to say is "hey this
extension is activated for everything, and
you can't do that."
We need to tell iOS when to show our share
extension, and what can be selected.
Open the info.plist as source code by right
clicking on it.
We're going to change the NSExtensionAttributes
section.
Replace it with this XML.
This tells iOS to only allow the share extension
to be activated when we select a single image.
This means our extension is activated only
for images, and only when it's a single image.
If you select two, the extension won’t activate.
Wow.
That was a big tutorial for a simple thing.
The source code is up on Github, so you'll
want to look over it.
If you have any questions let me know in the
comments.
New videos are out every week, so make sure
you subscribe.
This puts new videos in your YouTube feed.
If I did a good job, let me know!
And with that, I’ll see you in the next
tutorial!
