With the release of iOS 9, Apple has enabled apps to become fully indexed and searchable. In this article we will provide insight into how the new search works and how to implement the search API.
We've seen inklings of the new search capabilities in Handoff, a technology that Apple introduced in iOS 8 as part of its continuity platform--with the ability to search within spotlight not just superficially for apps (by app names) but actual app content. Think of Apple’s Calendar, where within Spotlight you can search for terms like "doctor's appointment." The search results will include the calendar listing, as well as Apple Mail listing, containing those search terms.
(source: Apple WWDC 2015)
Or take a hotel booking app, like Kayak: You could allow users to search through Spotlight for their future reservations. On Instagram, you could search by keywords such as "Lake Tahoe," and you would get thumbnail photos next to a description of the photos you took at a particular location. This is Apple’s "deep linking" at work.
(source: Apple WWDC 2015)
The benefits to developers lie in their apps, but, more specifically, to content being more discoverable. This flips the paradigm of searching for an app to find content to searching for content--and finding the apps that contain the content.
How Apple's Search API works
To be able to protect the privacy and security of apps, developers have the ability to choose what content they want to have indexed, while providing the best searching experience. Here are the two forms of indexing developers can choose from:
- Private On-Device Indexes: Each device contains a privately indexed database that remains private and is never searched externally from the device. Further, only the owner of the device is able to view the item in the search results.
- Public On-Sever Indexes: Apple’s server-hosted indexes store only explicitly publicly available data, marked as such.
Apple has also introduced App Mark Up Web Content, for deep-linking of Web content.
If some or all of your app’s content is also available on your website, you can use web markup to give users access to your content in search results. Using web markup lets the Applebot web crawler index your content in Apple’s server-side index, which makes it available to all iOS users in Spotlight and Safari search results. (source: Apple)
Adding such metadata allows you to provide a universal link, such as http://programmableweb.com/user/register, which will direct you when browsing on OS X to the Web registration page. However, when browsing on Safari for iOS, you will deep link to the registration screen within the hypothetical ProgrammableWeb app. This is all thanks to Universal Links. For more information on WebMarkup, consult Apple’s documentation on the subject.
How to implement Search APIs
There are three types of Search APIs for supporting iOS 9 searching:
NSUserActivity was introduced back in iOS 8 for Handoff and Continuity, but it has been extended as of iOS 9 with indexing and searchability. You get a lot of power from NSUserActivity through its metadata, such as being able to test whether handoff is available, whether it’s searchable/index-able and whether the item is publicly searchable.
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. (source: Apple)
To use NSUserActivity in your app, in the appropriate section, such as in a detail view controller of your reciples content, you would write something like this:
... let activity = NSUserActivity(activityType: "com.programmableweb.recipeDisplay") activity.userInfo = ["title": item.title, "prepTime": item.prepTime, "manIngredient": item.mainIngredient] activity.title = item.title var keywords = item.keywords activity.keywords = Set(keywords) activity.eligibleForHandoff = true activity.eligibleForSearch = true activity.becomeCurrent() ...
In our example, we are creating a mythical recipes app, so we aren’t all that concerned with privacy. In fact, we'd like as many people as possible to access the recipes. So, to make this content available for public indexing, we simply added the following property: activity.eligibleForPublicIndexing = true
Apple illustrates the decomposition of the elements of an activity using the iMovie app:
You can also set an expiration time for the content item, after which it will cease to be indexed: activity.expirationDate = NSDate()
You would want to do this if, say, you have an appointment that you are indexing, such as a baseball game that you bought tickets to. After the day of the game has passed, searching for that item is no longer relevant.