iOS 9: How to use the new search API


With iOS 8, Apple introduced Handoff, a technology allowing a user to start an activity on his Mac and seamlessly continue it with his iPhone, or vice versa. A few months ago, when the Apple Watch was released, Handoff also allowed continuing an activity started from the Watch on the phone.

With iOS 9, Apple upgrades Handoff, associating it with Spotlight. Indeed, it is now possible to search inside Spotlight, for performed activities, application content, and even popular activities from other users, even without having the application installed on the device.

For this, the application simply needs to register the launched activities (with NSUserActivity), as well as the content it presents (with Core Spotlight); then the system handles that information, indexing it either locally or on Apple servers.

NSUserActivity : recover an activity

In the same way as NSUserActivity can be used to create a link between devices or resume activities with Handoff, it is now possible to add additional information so as to allow indexing, searching and thus resuming an activity. The only prerequisite is to add some information about the activity when created:

NSUserActivity * userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.applidium.test-activity"];
userActivity.title = title;
userActivity.keywords = keywords;
userActivity.userInfo = userInfo;
userActivity.eligibleForSearch = YES;
userActivity.eligibleForPublicIndexing = YES;
userActivity.eligibleForHandoff = YES;
userActivity.contentAttributeSet = attributeSet;
[userActivity becomeCurrent];

defines all the keywords used to search the activity and userInfo owns the mandatory information to rebuild the activity (in the same way as Handoff did). The different eligibleFor(…) fields define where the system can use the activity : with Handoff, for search, and for public search.

Apple stipulates that keywords should not be overused, with the following warning for developers: irrelevant keywords will be detected and the activity will not be searchable through them.

Activities can now be public, meaning they are searchable by other users, even if they do not have the application installed on their device. For this, iOS handles two indexes, a local one, for each user, and a remote one, shared by all. When an activity is declared as public, iOS sends its hash to the shared index server ; when several users send the same hash, the activity is added to the index. Doing so garanties each shared activity does not contain any user specific data but is truly generic. When a user selects an activity for an application he does not own, Spotlight presents an AppStore view suggesting its installation.

To handle a search result (like with Handoff), a specific method in the appDelegate has to be implemented:

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray *restorableObjects))restorationHandler

This method should recreate the view associated to the activity and present it to the user.

Core Spotlight : Make content searchable

It is now possible to index the application content, in a local way, as a Spotlight source, by using Core Spotlight.

Core Spotlight

keeps, as local index, a link between content identifier and keywords; the developer only needs to feed it some data:

CSSearchableItemAttributeSet * attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString*)kUTTypeJSON];
  attributeSet.title = content.title;
  attributeSet.contentDescription = content.contentDescription;
  CSSearchableItem * item = [[CSSearchableItem alloc] initWithUniqueIdentifier:content.uniqueID domainIdentifier:domainID attributeSet:attributeSet];
  [[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:@[item] completionHandler: ^(NSError * __nullable error) {
    NSLog(@"Search item indexed");

@CSSearchableItemAttributeSet@’s contentType comes from UTCoreTypes inside MobileCoreServices. In addition to the item identifier, it is possible to set a domain. It can be useful to perform actions over the whole domain, like deleting all the items. CSSearchableIndex is made for application indexed content management, it can be used to add, update or delete entries.

Once an item has been added to the index, it can be searched through Spotlight; when an item is selected by the user, the system calls the appDelegate method:

- (BOOL)application:(nonnull UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * __nullable))restorationHandler

When the activity comes from an indexed content search, the following is true:

[userActivity.activityType isEqualToString:CSSearchableItemActionType]

And it is then possible to find the content identifier with:

[userActivity.userInfo objectForKey:CSSearchableItemActivityIdentifier]

Therefore, it is necessary to recreate the content screen. The idea is to bring the user on the same screen he would have landed on through normal navigation inside the application.


With iOS 9, Apple decided to put Spotlight in the center of iOS. NSUserActivity and Core Spotlight new indexing methods allow applications to be integrated deeper inside the system. Using both of those new API helps the developer add new entry points straight inside his application and increase its visibility. Those methods truly improve user experience, and they should be used to provide better-integrated applications.