UIActivityViewController Tutorial: Sharing Data

In this UIActivityViewController tutorial, you’ll learn all about giving your users the ability to export their data and share it with others.

Version

  • Swift 4.2, iOS 12, Xcode 10
Update note: Owen L Brown updated this tutorial for Xcode 10.1, Swift 4.2, and iOS 12. Andy Pereira wrote the original.

A lot of developers want to be able to share their app data via email, Messages or AirDrop. Sharing is a convenient way for users to send data to each other or between devices. It may even net you some new customers!

Fortunately, since iOS 6, Apple has provided the handy, but much-overlooked, UIActivityViewController class, which offers a clean interface for sharing and manipulating data inside your app.

You’ll learn everything you need to know to use this class in this UIActivityViewController tutorial!

To set up sharing inside your app, you’ll have to configure some keys inside your app’s Info.plist and handle a few system callbacks inside your app’s AppDelegate. Once set up, iOS can open your app with the URL pointing to the data to import or export.

Ready for some book sharing fun? Read on.

Getting Started

First, download the materials for this tutorial at the top or bottom of this page using the Download Materials button. Build and run the starter project in Xcode and you’ll see the following:

IActivityViewController tutorial empty books screen

Well, that’s no good; there are no books to share. Here’s how you can start sharing wonderful RW books with everyone.

UTIs and Your Plist

The first thing you need to do is set up your Info.plist to let iOS know your app can handle Book Tracker Documents.

To do this, you need to register your app as being able to handle certain Uniform Type Identifiers, or UTIs, exporting any UTIs that are not already known by the system.

In summary, UTIs are unique identifiers that represent documents. There are UTIs already built into iOS for handling common document types such as public.jpeg or public.html.

Defining Your UTIs

You’re going to register your app to handle documents with the com.raywenderlich.BookTracker.btkr UTI representing the description of a book.

You’ll give iOS information about the UTI, such as what file name extension it uses, what mime type it’s encoded as when sharing and, finally, the file’s icon.

So now it’s time to see it in action! Open Info.plist and add the following entries under the Information Property List key:

UIActivityViewController tutorial plist

You can read up on what each of these values mean in Apple’s UTI guide, but here are the important things to note:

  • The Document types entry defines what UTIs your app supports — in your case, the com.raywenderlich.BookTracker.btkr UTI, as an Owner/Editor.
  • Document types is also where you set the names of the icons that iOS should use when displaying your file type. You’ll need to make sure you have an icon for each of the sizes listed in the plist.
  • The Exported Type UTIs entry gives some information about com.raywenderlich.BookTracker.btkr, since it isn’t a public UTI. Here you define that your app can handle files ending in .btkr or files that have a mime type of application/booktracker.

Importing Your First Book

Believe it or not, by setting these keys, you have told iOS to start sending your app files that end with the .btkr extension.

You can test this out by emailing yourself a copy of the Swift Apprentice.btkr file from the Download Materials resource. Please make sure you unzip the file before emailing it to yourself. Otherwise, both the file extension UTI and mime type will be wrong.

UIActivityViewController tutorial email book attachment

You can tap on the attachment and it will prompt you to open the book in the Book Tracker app. Selecting Book Tracker will open the app. However, it won’t load the data from the sample file because you haven’t implemented the code for that yet.

Now that you’re a UTI wizard, it’s time for you to sprinkle some magic.

Note: If you don’t see “Copy to Book Tracker” displayed in UIActivityViewController after tapping the attached file in your email, you may need to edit the order of supported apps by scrolling to the end of the list, selecting More, and moving “Copy to BookTracker” to the top of the list.

Importing App Data

Before you can handle opening data from the file, you’ll need some code that can work with the file that you have passed to it.

Add that code by opening Book.swift, and replacing importData(from:) with the following:

static func importData(from url: URL) {
  // 1
  guard 
    let data = try? Data(contentsOf: url),
    let book = try? JSONDecoder().decode(Book.self, from: data) 
    else { return }
  
  // 2
  BookManager.shared.add(book: book)
  
  // 3
  try? FileManager.default.removeItem(at: url)
}

Here’s a step-by-step explanation of the code above:

  1. Verify the app can read the contents of the URL provided to it. Create a new Book object with data from the URL.
  2. Add the new book to your app’s data.
  3. Finally, delete the document that iOS saved to your app’s sandbox after opening it.
Note: If you don’t delete these files as they come in, your app will continue to grow in size with no way for the user to clear the app’s data — except… by deleting your app!

Next, when an external app wants to send your app a file, iOS will invoke application(_:open:options:) to allow your app to accept the file. Open AppDelegate.swift and add the following code:

func application(
  _ app: UIApplication,
  open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]
  ) -> Bool {
  // 1
  guard url.pathExtension == "btkr" else { return false }

  // 2
  Book.importData(from: url)

  // 3
  guard 
    let navigationController = window?.rootViewController as? UINavigationController, 
    let bookTableViewController = navigationController.viewControllers
      .first as? BooksTableViewController
    else { return true }

  // 4
  bookTableViewController.tableView.reloadData()
  return true
}

Here’s a step-by-step explanation of the code above:

  1. Verify the URL’s extension is btkr, since your app only supports files with that extension.
  2. Use the static method on Book you added above to import the data into your app.
  3. Verify the root view controller is an instance of a UINavigationController and that its first view controller is an instance of BooksTableViewController.
  4. Reload BooksTableViewController‘s table view to show the newly imported book, then return true to inform iOS that your app successfully processed the provided book information.
Note: The method still returns true even if the view controller hierarchy was not set up correctly. This works because your app has, in fact, processed the provided book information in step two above.

Build and run your app. If all works well, you should be able to open the email attachment and see the book imported into your app as shown below.

UIActivityViewController tutorial list of books imported

Exporting App Data

So far in this UIActivityViewController tutorial, you’ve added functionality to your app that handles importing data from other apps. However, what if you want to share your app’s data?

You’re in luck, as Apple has made exporting data nice and easy.

Your app will need code to handle exporting your favorite books. Open Book.swift and replace the existing exportToURL() definition with the following:

func exportToURL() -> URL? {
  // 1
  guard let encoded = try? JSONEncoder().encode(self) else { return nil }
  
  // 2
  let documents = FileManager.default.urls(
    for: .documentDirectory,
    in: .userDomainMask
  ).first
    
  guard let path = documents?.appendingPathComponent("/\(name).btkr") else {
    return nil
  }
  
  // 3
  do {
    try encoded.write(to: path, options: .atomicWrite)
    return path
  } catch {
    print(error.localizedDescription)
    return nil
  }
}

Here’s a step-by-step explanation of the code above:

  1. Encode Book as JSON.
  2. Verify that your app can access its Documents directory without error.
  3. Finally, save the data to your Documents directory and return the URL of the newly-created file.

Now that you can export Book data to a file, you’re going to need an easy way to share that data. Open BookDetailViewController.swift and replace the implementation of share(_:) with the following:

@IBAction func share(_ sender: UIBarButtonItem) {
  // Get latest changes
  saveBook()
  
  // 1
  guard 
    let detailBook = detailBook,
    let url = detailBook.exportToURL() 
    else { return }
  
  // 2
  let activity = UIActivityViewController(
    activityItems: ["Check out this book! I like using Book Tracker.", url],
    applicationActivities: nil
  )
  activity.popoverPresentationController?.barButtonItem = sender

  // 3
  present(activity, animated: true, completion: nil)
}

Here’s a step-by-step explanation of the code above:

  1. Ferify that you have a detail book and that you can retrieve the URL from exportToURL().
  2. Create an instance of UIActivityViewController and, for activityItems, pass in a message and the URL to your app’s data file. Depending on the activity the user selects from the activity menu, iOS uses the message you pass in to pre-populate its content. For example, if the user chooses to share the book via Email, the message you passed in will pre-populate the body of the email. Since not all activities have such capability, such as AirDrop, iOS may discard the message. UIActivityViewController will do all of this heavy lifting for you and, since you defined all of the required information in your Info.plist, it’ll know just what to do with it.
  3. Present the UIActivityViewController to the user.

Build and run your app, open a book and try to share it. You’ll notice that you see a few options available to you as shown below:

UIActivityViewController tutorial book sharing

UIActivityViewController has been around since iOS6, but despite how useful it is, it’s often under-appreciated. Perhaps one of the best options is the ability to AirDrop. If you have two devices — or better yet, a friend with the Book Tracker app installed — you can test AirDropping books!

Where to Go From Here?

You can download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.

Now that you know how iOS imports and exports app data, you’re ready to take this knowledge and start sharing your favorite books or any other data of your choice.

Here are some resources for further study:

Contributors

Comments