iOS 9: Introducing Search APIs

Introduction

At WWDC 2015, Apple officially announced iOS 9. In addition to many new features and improvements, this update also gives developers the opportunity to make the content of their apps more discoverable and accessible through Spotlight search. New APIs available in iOS 9 allow you to index any content or interface state within your app, making it accessible to your users through Spotlight. The three components of these new search APIs are:

  • the NSUserActivity class, which is designed for viewed app content
  • the Core Spotlight framework, which is designed for any app content
  • web markup, designed for apps that have content that is mirrored on a website

In this tutorial, I'm going to show you how you can use the NSUserActivity class and the Core Spotlight framework in your own applications.

Prerequisites

This tutorial requires that you are running Xcode 7 on OS X 10.10 or later. To follow along with me, you also need to download the starter project from GitHub.

1. Using NSUserActivity

In the first part of this tutorial, I'm going to show you how you can index an app's content through the NSUserActivity class. This API is the same one that is used for Handoff, a feature introduced in iOS 8 last year, and handles both saving and restoring an application's current state.

If you have not worked with NSUserActivity before, then I suggest you first read my my tutorial covering the basics of Handoff and NSUserActivity before continuing with this one.

Before writing any code, open the starter project and run the app in the iOS Simulator or on a test device. At this stage, you will see that the app simply displays a list of four TV shows and a detail page for each one.

Show list
Show detail

To begin, open the starter project and navigate to DetailViewController.swift. Replace the configureView method of the DetailViewController class with the following implementation:

The code that configures the labels in the view controller is unchanged, but let's go through the user activity code step by step:

  1. You create a new NSUserActivity object with the unique identifier com.tutsplus.iOS-9-Search.displayShow. The starter project has already been configured to use this identifier so be sure to leave this identifier unchanged.
  2. You then assign a userInfo dictionary to the user activity. This will be used later to restore the state of the application.
  3. You give the activity's title property a string value. This is what will show up in the Spotlight search results.
  4. To ensure that the content is searchable by more than just its title, you also provide a set of keywords. In the above code snippet, the set of keywords includes each word of the show's name as well as its genre.
  5. Next, you set a number of properties of the NSUserActivity object to tell the operating system what you want this user activity to be used for. In this tutorial, we are only looking at the search component of the API so we disable Handoff and enable search.
  6. Finally, you call the becomeCurrent method on the user activity at which point it is automatically added to the device's index of search results.

In the above implementation, you probably noticed the two lines in comments. While we won't be using these properties in this tutorial, it's important to know what each property is used for.

  • With the above implementation, a user activity and search result is created for each individual show only once the application has been opened. When you make your user activity eligibleForPublicIndexing, Apple begins to monitor the usage and interaction of this particular activity from the user's search results. If the search result is engaged by many users, Apple promotes the user activity to its own cloud index. Once the user activity is in this cloud index, it is searchable by anyone who has installed your application, regardless of whether they have opened that particular content or not. This property should only be set to true for activities that are accessible by all users of your application.
  • A user activity can also have an optional expirationDate. When this property is set, your user activity will only show up in search results up until the specified date.

Now that you know how to create an NSUserActivity capable of displaying search results in Spotlight, you are ready to test it out. Build and run your app, and open up a few of the shows in your application. Once you have done this, go back to the home screen (press Command-Shift-H in the iOS Simulator) and swipe down or scroll to the far left screen to bring up the search view.

Start typing the title of one of the shows that you opened and you will see that it shows up in the search results as shown below.

Start typing the title of one of the shows

Alternatively, enter the genre of one of the shows you opened. Because of the keywords that you assigned to the user activity, this will also cause the show to be listed in the search results.

Enter the genre of one of the shows

Your application's content is correctly indexed by the operating system and results are showing up in Spotlight. However, when you tap a search result, your application doesn't take the user to the respective search result. It merely launches the application.

Luckily, as with Handoff, you can use the NSUserActivity class to restore the correct state in your application. To make this work we need to implement two methods.

Implement the application(_:continueUserActivity:restorationHandler:) method in the AppDelegate class as shown below.

Next, implement the restoreUserActivityState(_:) method in the MasterViewController class.

At the time of writing, the latest version of Xcode 7 (Beta 3) contains an issue where the userInfo property of a user activity being restored can be empty. That is why I handle any errors and display an alert with the userInfo that is returned by the operating system.

Build and run your app again, and search for a show. When you tap on a show in the search results, the app should take you straight to the detail view controller and display the current information for the show you tapped.

Application being restored correctly

2. Using the Core Spotlight Framework

Another set of APIs available in iOS 9 to make your content searchable for users is the Core Spotlight framework. This framework has a database-style design and lets you provide even more information about the content that you want to be searchable.

Before you can use the Core Spotlight framework, we need to link the project against the framework. In the Project Navigator, select the project and open the Build Phases tab at the top. Next, expand the Link Binary With Libraries section and click the plus button. In the menu that appears, search for CoreSpotlight and link your project against the framework. Repeat these steps for the MobileCoreServices framework.

Adding the CoreSpotlight framework

Next, to ensure that the search results our app provides are from Core Spotlight, delete your app from your test device or the iOS Simulator and comment out the following line in the DetailViewController class:

Finally, open MasterViewController.swift and add the following lines before the Show structure definition:

Next, add the following code to the viewDidLoad method of the MasterViewController class:

Before we test this code, let's go through each step of the for loop.

  1. You create a CSSearchableItemAttributeSet object, passing in a content type for the item. If your search result links to a photo, for example, you would pass in the kUTTypeImage constant.
  2. You assign the show's name to the title property of the attribute set. Just like with NSUserActivity, this title is what will appear at the top of your search results.
  3. Next, you create a descriptive string and assign this to the contentDescription property of your searchable attribute set. This string will be displayed below the result's title in Spotlight.
  4. You create an array of keywords form the search result just as you did with NSUserActivity.
  5. Lastly, you create a CSSearchableItem with a unique item identifier, unique domain identifier to group items together, and an attribute set. Unlike with NSUserActivity, which returns the user activity from the search result, the unique identifiers you use for a CSSearchableItem are the only information that you receive from the operating system when your search result is selected by the user. You need to use these identifiers to restore your app back to the correct state.

Once you have created a CSSearchableItem for the TV shows, you index them using the indexSearchableItems(_:completionHandler:) method on the default CSSearchableIndex object.

Build and run your app, and all of your shows will be indexed by Spotlight. Navigate to the search view and search for one of the shows.

CoreSpotlight search result

Core Spotlight search results are handled by the same methods as those from NSUserActivity, but the process is slightly different. When a CSSearchableItem is selected from the search results, the system creates an NSUserActivity object for you that contains the unique identifier of the selected item.

In your app delegate's application(_:continueUserActivity:restorationHandler:) method, you can use the following implementation to retrieve the information you need from a Core Spotlight search result:

A good practice when indexing content from your app with the Core Spotlight framework is to also delete your items when they are no longer needed. The CSSearchableIndex class provides three methods to delete searchable items:

  • deleteAllSearchableItemsWithCompletionHandler(_:)
  • deleteSearchableItemsWithDomainIdentifiers(_:completionHandler:)
  • deleteSearchableItemsWithIdentifiers(_:completionHandler:)

As an example, add the following code to the end of the viewDidLoad method of the MasterViewController class:

Build and run your app one more time. When you try to search for any of your shows, no results are returned, because they have been deleted from the index.

3. Combining NSUserActivity and Core Spotlight

Another new addition to the NSUserActivity class in iOS 9 is the contentAttributeSet property. This property allows you to assign a CSSearchableItemAttributeSet, just like the ones you created earlier. This attribute set allows your search results for NSUserActivity objects to show the same amount of detail as Core Spotlight search results.

Start by adding the following imports at the top of DetailViewController.swift:

Next, update the configureView method in the DetailViewController class with the following implementation:

Build and run your app one final time, and open a few of your shows. When you now search for a show, you will see that your results, created with NSUserActivity, contain the same level of detail as the Core Spotlight search results.

NSUserActivity result with CoreSpotlight detail

Conclusion

In this tutorial, you learned how to make your application's content accessible through iOS Spotlight by using the NSUserActivity class and the Core Spotlight framework. I also showed you how to index content from your application using both APIs and how to restore your application's state when a search result is selected by the user.

The new search APIs introduced with iOS 9 are very easy to use and make your application's content easier to discover and more accessible to your application's users. As always, if you have any comments or questions, leave them in the comments below.

Tags:

Comments

Related Articles