In several iOS apps, such as Safari or the Camera app, you can click a button that brings up an interface that makes it easy to send or share what you are looking at via messages, Twitter, Facebook, etc. That interface is known as the UIActivityViewController. When I first learned about it, I didn’t even know what to search for. I think I originally started with “share sheet” and went on from there, so it may seem silly to point out something so obvious, but when I first tried, I knew what I wanted, I just had no idea what it was called.
If you’ve paid any attention to WWDC a few years, you have probably saw that this is the new home for Share and Action extensions. Today though, we are just going to cover the built in aspects of using UIActivityViewController in your Swift app. We will cover those sometime later.
Presenting the UIActivityViewController
UIActivityViewController is an Objective-C API. Not a lot has changed about it between iOS 7 and iOS 9. You will see a few things that are unusual in this code compared to standard Swift code, but thanks to Apple’s work on interoperability with Objective-C, it works just fine.
Here is (almost) the most basic code for loading a UIActivityViewController:
@IBAction func shareButtonTapped(_ sender: UIButton) { let textToShare = "Swift is awesome! Check out this website about it!" if let myWebsite = NSURL(string: "http://www.codingexplorer.com/") { let objectsToShare: [Any] = [textToShare, myWebsite] let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil) activityVC.popoverPresentationController?.sourceView = sender self.present(activityVC, animated: true, completion: nil) } }
So, you can see that we put this into an IBAction connected to a button to trigger the sharing. Next we make a String to share. The next line is a bit more complex, but bear with me for a second. That initializer for NSURL is a failable initializer. We send it a string, and if it can create a valid URL, then it will return one. However if it cannot, it will return a nil value. We can use Optional Binding to change it back from an NSURL? (optional NSURL) to a normal NSURL. I could have just forcefully unwrapped, since that is indeed a valid URL, but I personally do not like using the force unwrap operator if I don’t absolutely have to. This is why I said it was “almost” the most basic code.
Anyway, now that we have our textToShare and myWebsite constants ready, we put them into an array. Wait… what? That’s an array of a String and an NSURL! Swift arrays can only take values of the same type can’t they? This is the first place where we see some of the Objective-C showing through. The UIActivityViewController initializer we are about to call takes an NSArray as its first argument. NSArrays can hold any type of object in the same array (unlike Swift Arrays). When this is brought over to Swift, the function prototype for the initializer is:
init(activityItems: [Any], applicationActivities: [UIActivity]?)
In Swift, an NSArray is shown as a Swift Array of the type AnyObject. AnyObject represents an instance of any class type. Since a Swift String and an NSURL are both classes, they technically can be in the same array, but they are cast as AnyObject instead of their primary type.
So, we create our UIActivityViewController with an initializer that takes that array of activityItems, and we set nil as the applicationActivities argument. The applicationActivities parameter takes an array of UIActivity types that are custom to your application. This was particularly useful before extensions. This would allow you to say, make your own custom save to Instapaper button, and add it into the UIActivityViewController yourself. With the new sharing extensions though, the creator of the app to share with can do the work for you. Nonetheless, if you do have some special type of share or action activity that is inherent to your app (or to work with another service that does not have it’s own extension yet), this is where you would put it. Since we have none, we just set it to nil.
I did say that applicationActivities takes an array of UIActivity types. Well, the optional is just so we can set it to nil if we don’t have out own custom UIActivity types. Since the original writing of this article, this API has been updated, it now is an optional array of UIActivity types, instead of the previous Optional Array of AnyObject.
The second to last line is a bit interesting. A UIPopoverPresentationController is a way to show popovers on an iPad. Without this or the popoverPresentationController’s barButtonItem being set, when a popover is generated, it won’t know what view created it, or where to point the little arrow that says what button brought it, and will cause a crash. Setting the sourceView or the barButtonItem properties fix this issue. This doesn’t matter on an iPhone, it will just show like normal, and the popoverPresentationController property will just return nil in that Optional Chaining statement.
Excluding Built In Activities
So, there are some activities that may not make sense for your app. How do you explicitly exclude them? Well, UIActivityViewController has a property that takes an array of the built in UIActivityTypes that you don’t want. For this example, we are sharing a snippet of text and a URL. That sounds like prime Vimeo content, right? Yeah, probably not.
You don’t necessarily have to exclude everything that doesn’t make sense for your app though. With the code in the last section alone, without explicitly excluding anything, there were several services not listed that wouldn’t make sense. What was available was: Airdrop, Message, Mail, Twitter, Facebook, Add to Reading List, and Copy. There was no Vimeo or Flickr to be seen. You can see a great chart on NSHipster’s Article UIActivityViewController that shows what data types are supported for each of the built inUIActivityTypes. The article itself is about the Objective-C form of this class, but much of the information is the same.
For this share though, we are sharing a String of text and an NSURL. I guess we could Airdrop that, or send it to the reading list, but I think it makes more sense to just share it directly with messages, twitter, etc. Copy would make sense if we needed to copy whatever is shared to an app that doesn’t have it’s own extension yet, so we’ll leave that in.
All we do is create an array of the UIActivity.ActivityTypes that we do not want to see, and assign that to our UIActivityViewController’s excludedActivityTypes property. We would modify our code above like so:
@IBAction func shareButtonClicked(sender: UIButton) { let textToShare = "Swift is awesome! Check out this website about it!" if let myWebsite = NSURL(string: "http://www.codingexplorer.com/") { let objectsToShare = [textToShare, myWebsite] let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil) //New Excluded Activities Code activityVC.excludedActivityTypes = [UIActivityTypeAirDrop, UIActivityTypeAddToReadingList] // activityVC.popoverPresentationController?.sourceView = sender self.presentViewController(activityVC, animated: true, completion: nil) } }
Then just run that, and you get your small UIActivityViewController shown without the AirDrop section, or the “Add to Reading List” action.
Preparing for Custom Share and Action Extensions
You don’t have to do a thing.
With my code above, I could scroll over on UIActivityViewController’s share section, and use other custom share extensions like Instapaper or Evernote. I didn’t have to do a thing. As a user, you just click the more button to show the ones you want in the share sheet. As a developer, you don’t have to do anything to your UIActivityViewController to show custom Share and Action Extensions.
Conclusion
Apple made sharing from your apps incredibly easy with the addition of UIActivityViewController. All you need to do is create an Array of whatever you want to share, give it to a UIActivityViewController initializer, and then present that ViewController. Really simple.
If you want to see another take on how to do this, check out David Owens’s article UIActivityViewController (Share Sheet) with Swift.
Also, if you do want to know how to do this in Objective-C, you can see my previous post Add sharing to your app via UIActivityViewController. You can also see there the how to add the sharing button and a list of the available built in UIActivityTypes.
I hope you found this article helpful. If you did, please don’t hesitate to share this post on Twitter or your social media of choice, every share helps. Of course, if you have any questions, don’t hesitate to contact me on the Contact Page, or on Twitter @CodingExplorer, and I’ll see what I can do. Thanks!