Guides and Sample Code


App Search Programming Guide

On This Page

Index Activities and Navigation Points

The NSUserActivity class provides methods that let you capture specific app states and navigation points that the user has previously visited and then restore them later using Handoff (to learn more about enabling Handoff in your app, see Handoff Programming Guide). In apps that run in iOS 8 and later, users expect Handoff to help them start an activity on one device and continue it on another.

In addition to supporting Handoff, using NSUserActivity in iOS 9 and later lets you:

  • Index activities as users perform them in your app. Activities could include creating or viewing content, viewing a set of items (such as a results list), or visiting a navigation point within your app.

  • Mark specific items as available for public searching (for some examples of items that can be appropriate for public searching, see Example Implementations)

  • Provide indexable metadata about an item, which gives users rich information in search results

To provide the best search results, avoid creating multiple NSUserActivity objects at one time. Also, note that the NSUserActivity class is not intended to help you index arbitrary data in your app. If you want to index app-specific data, use the APIs of the Core Spotlight framework and use the appropriate relatedUniqueIdentifier to link indexed items together (to learn more, see Index App Content).

Using NSUserActivity APIs also lets you take advantage of Siri suggestions and smart reminders. Siri suggestions are displayed in the Spotlight search screen and can include searchable activities. (Note that only activities with a high engagement ratio are eligible to be included in Siri suggestions. For more information about engagement, see Combine APIs to Increase Coverage.) Users can use Siri smart reminders to be reminded about specific content related to your app. When users receive a smart reminder, the activity they specified is displayed in the reminder.

image: ../Art/ZKW_results3_2x.png
image: ../Art/Siri_result_2x.png

As the user uses your app, you create activity objects associated with various navigation points and app states. Each item is added to the on-device index by default. In iOS 9 and later, marking a public item as eligible for public indexing also adds it to the on-device index and confers an additional advantage: When you use web markup to make your related website content searchable, user engagement with publicly eligible search results from your app can help improve the ranking of your website’s content. When a user taps a searchable activity or state in Spotlight search results, you use NSUserActivity APIs to continue the activity and return the user to the relevant area in your app.

Creating Searchable Activities

To make an activity or navigation point searchable, create an NSUserActivity object to represent it. Use NSUserActivity properties to identify the item’s type, provide metadata that describes it, and make it eligible for search. Setting an item as eligible for search means that the item gets added to the on-device index when the item becomes current. Listing 3-1 shows how to create an activity.

Listing 3-1Creating an activity
  1. // It's recommended that you use reverse DNS notation for the required activity type property.
  2. var activity: NSUserActivity = NSUserActivity(activityType: "com.myCompany.myContentType")
  3. // Set properties that describe the activity and that can be used in search.
  4. activity.title = "My Activity Title"
  5. activity.userInfo = ["id": ""]
  6. // Add the item to the private on-device index.
  7. activity.eligibleForSearch = true

Although it’s not shown in Listing 3-1, NSUserActivity also defines the contentAttributeSet property, which lets you specify as many attributes as you need to describe an item. The contentAttributeSet property takes a CSSearchableItemAttributeSet object, which is a Core Spotlight object you use to provide indexable metadata that enriches search results. Core Spotlight defines a large number of properties that specify metadata in several topic areas, such as media, events, and messages. Only the title, userInfo, and contentAttributeSet properties are required, but to give users the best experience, it’s recommended that you provide values for as many properties as possible. In particular, it’s recommended that you always provide content-specific values for the thumbnailData and contentDescription properties. For a full list of properties you can use, see CSSearchableItemAttributeSet Class Reference.

Figure 3-1 shows how three common properties can be used to provide metadata about a searchable item.

Figure 3-1A searchable item can use various properties to display metadata image: ../Art/movie_2x.png

Three NSUserActivity properties warrant particular mention:

Activities are private by default. When you set an item’s eligibleForPublicIndexing property and you use web markup to make your related website content searchable, user engagement with the item can help improve the ranking of your website’s content. To learn more about using web markup, see Mark Up Web Content.

If you don’t set the expirationDate property appropriately, the system automatically expires the activity after a period of time.

The webpageURL property is useful when your app content is also available in your website and you use both NSUserActivity APIs in your app and web markup in your website. In particular, you can use the webpageURL property to avoid duplicate indexing of the same item (to learn more, see Combine APIs to Increase Coverage). When you set the webpageURL property, also set the requiredUserInfoKeys property, using the keys of the userInfo dictionary that must be stored. If you don’t set the requiredUserInfoKeys property, the userInfo dictionary will be empty when the activity is restored.

When a user performs the activity or enters the app state associated with the NSUserActivity object you created, your app calls the becomeCurrent method to mark the activity as current. A current activity that’s eligible for search is automatically added to the private on-device index (that is, CSSearchableIndex). Additionally you can enable user actions within a search result, such as calling a phone number or getting directions to a location (to learn how to do this, see “Supporting Actions” in CSSearchableItemAttributeSet Class Reference).

To guarantee that the activity and its metadata get indexed, you must hold a strong reference to the activity until it gets added to the index. There are two ways to do this: The first way is to assign the activity to a property in the controller object that creates the activity. The second way is to use the userActivity property of the UIResponder object. If you use the second way, you need to set the metadata—such as information in the userInfo property—in the updateUserActivityState: method; otherwise, the metadata you set on the activity will not be persisted.

If you want an activity to be eligible for search but not for Handoff between devices, set the eligibleForSearch property to true and the eligibleForHandoff property to false.

Use Core Spotlight APIs to remove items you indexed using NSUserActivity. When an item is indexed using both NSUserActivity and Core Spotlight APIs and the item is connected using the relatedUniqueIdentifier property, removing the item by using the Core Spotlight APIs makes the activity ineligible for indexing. For more information about using the relatedUniqueIdentifier property, see Combine APIs to Increase Coverage.

Continuing Activities Chosen in Search Results

When users tap a search result for an NSUserActivity item that you added to the index, your app should open and restore the context associated with that item. To accomplish this, your app delegate implements application:continueUserActivity:restorationHandler:, checking the type of the incoming activity to see whether the app is opening because the user tapped an indexed item in a search result. The application:continueUserActivity:restorationHandler: method is the same method you currently use to continue an activity using Handoff.

Listing 3-2 shows a skeletal implementation of application:continueUserActivity:restorationHandler:.

Listing 3-2Continuing a user activity
  1. func application(UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: [AnyObject]? -> Void) -> Bool {
  2. if userActivity.activityType == "com.myCompany.myContentType" {
  3. // Restore app state for this userActivity and associated userInfo value.
  4. }
  5. return true
  6. }