iOS 9 Learn more every day Day 1: Search API

iOS 9 Learn more every day Day 1: Search API

Prior to iOS 9, Spotlight could only search for app names. With the new search API released in iOS 9, Apple now allows developers to customize the content that can be searched in their apps, the way search results are displayed in Spotlight, and the events when users click on search results.

3 search APIs

NSUserActivity

The NSUserActivity API was introduced in iOS 8 when the new Handoff feature was introduced. However, in iOS 9, Spotlight can also search for activities. You can now provide metadata to an activity to indicate that the activity is searchable. In practice, it is a history stack, similar to your normal web browsing. Users can quickly open the most recently used activity from Spotlight.

Web Markup

The mechanism of Web Markup is that the app can mirror the content to a website, and then Spotlight will index the content. Even if the user does not have the app installed on the device, the search results can be displayed in Spotlight. Apple's crawler will continue to crawl the Internet, looking for specific markup on the website. After that, the search results will appear in Safari and Spotlight.

Even if the user does not have the app installed, they can still find the search results, so this feature is crucial. It can give you many opportunities to be exposed to potential users. The deep links in the app you expose to the search API will be stored in Apple's cloud index. If you want to learn more about Web Markup, you can check out Apple's official document Use Web Markup to Make App Content Searchable.

CoreSpotlight

CoreSpotlight is a new framework in iOS 9 that allows you to index anything in your app. The previously mentioned NSUserActivity can be used to save the user's history information, and this new API can index any data. It provides an essential bridge for you to access the CoreSpotlight index on the user's device.

Using the Core Spotlight API

NSUserActivity and Web Markup APIs are relatively easy to use, but CoreSpotlight is a bit more complicated. To demonstrate how the new CoreSpotlight API is used, let's make a simple app. Its function is to display a list of friends and display a portrait when clicking on a friend's name. You can download the source code on GitHub and follow along step by step.

App Screenshots

The app has a simple storyboard with a FriendTableViewController that displays a simple list of friends and a FriendViewController that displays the details of each friend.

Storyboard

All friends’ information is stored in the Datasource class. We use this class to create a model to store friends’ information. In addition, the logic of saving friends to the Core Spotlight index is also written in this class.

First, we override the init() method of the Datasource class and create and save a Person array in this method. The data should generally be read from a database, server interface, etc. For the sake of demonstration, we will simply write some fake data.

  1. override init () {
  2. let becky = Person()
  3. becky.name = "Becky"   
  4. becky.id = "1"   
  5. becky.image = UIImage(named: "becky" )!
  6.  
  7. ...
  8.  
  9. people = [becky, ben, jane, pete, ray, tom]
  10. }

After the people array is filled with data, the Datasource is ready!

Now that the data is ready, FriendTableViewController can create an instance of the Datasource and use it when the table view displays the cell.

  1. let datasource = Datasource()

In the cellForRowAtIndexPath method, the code to display the cell content is as follows:

  1. let person = datasource.people[indexPath.row]
  2. cell?.textLabel?.text = person.name

#p#

Save person data to Core Spotlight

Now that we have fake data, we can use the new API of iOS 9 to save it to Core Spotlight. Back to the Datasource class, we defined a method savePeopleToIndex in this class. After the FriendTableViewController interface is loaded, you can call this method.

In this method, we loop through each person in the people array, create a CSSearchableItem for each person, and store it in a temporary array searchableItems.

  1. let attributeSet = CSSearchableItemAttributeSet(itemContentType: "image" as String)
  2. attributeSet.title = person.name
  3. attributeSet.contentDescription = "This is an entry all about the interesting person called (person.name)"  
  4. attributeSet.thumbnailData = UIImagePNGRepresentation(person.image)
  5. let item = CSSearchableItem(uniqueIdentifier: person.id, domainIdentifier:
  6. "com.ios9daybyday.SearchAPIs.people" , attributeSet: attributeSet)
  7. searchableItems.append(item)

The last step is to call indexSearchableItems on the default CSSearchableIndex. This step actually stores these items in CoreSpotlight, and users can then search for these data and they will appear in the search results.

  1. CSSearchableIndex.defaultSearchableIndex().indexSearchableItems(searchableItems,
  2. completionHandler: { error -> Void in
  3. if error != nil {
  4. print(error?.localizedDescription)
  5. }
  6. })

That’s it! Run the app and the data will be added to the storage in real time. Search in spotlight and you will be able to find your friends.

Search Results

Responding to user clicks

Now that users can see your search results in Spotlight, hopefully they’ll click on them! But if they do, what happens? At this point, clicking on a search result will just open your app. If you want to show the friend the user just clicked on, you’ll have to write a little more code. We can specify the behavior of the app after it’s opened from the search results in the continueUserActivity UIApplicationDelegate method of the app’s AppDelegate.

Here is the code for the entire method:

  1. func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
  2. // Find the ID from the user info  
  3. let friendID = userActivity.userInfo?[ "kCSSearchableItemActivityIdentifier" ] as! String
  4.  
  5. // Find the root table view controller and make it show the friend with this ID  
  6. let navigationController = (window?.rootViewController as! UINavigationController)
  7. navigationController.popToRootViewControllerAnimated( false )
  8. let friendTableViewController = navigationController.viewControllers.first as! FriendTableViewController
  9. friendTableViewController.showFriend(friendID)
  10.  
  11. return   true  
  12. }

As shown in the code, the information we previously stored in the CoreSpotlight index using the indexSearchableItems method can now be retrieved using userActivity.userInfo. The only thing we are interested in here is the friend's ID, which we store in the kCSSearchableItemActivityIdentifier of the index item.

After we extract the ID from the userInfo dictionary, the next step is to get the app's navigation controller, pop to the home page (without animation so the user doesn't see the pop), and then call the showFriend method of friendTableViewController. I won't go into the details of this method, but it finds the corresponding friend from the datasource based on the ID and pushes a new view controller in. That's it! Now when the user clicks on a friend in the spotlight, they will see the following screen:

Click on the search results

As you can see in the screenshot, there is a "Back to Search" button in the upper left corner of the app. Clicking this button will take you directly back to the search results page where you clicked on your friend's name. Users can also click the standard back button to continue browsing the app.

Demo Summary

In the demo above, we showed how easy it is to integrate app data with the CoreSpotlight index, how powerful it is to guide users to open the app, and how helpful it is for users to search for specific content.

However, we haven't mentioned how to delete data from the index. This is still very important, and you should be diligent in updating the indexed data. To learn more about how to delete old data from CoreSpotlight, you can look at the deleteSearchableItemsWithIdentifiers, deleteSearchableItemsWithDomainIdentifiers and deleteAllSearchableItemsWithCompletionHandler methods.

The importance of having integrity

Although it seems that the more app content indexed by Spotlight and Safari, the better, you should think twice before flooding them with content. Not only will it make users more comfortable if you maintain a clean slate in the iOS ecosystem, but Apple is also watching. Apple spends a lot of time to ensure that search results are truly relevant. They track the click-through rate of search results, and flooding them with content will result in them being moved to the end of the search results.

learn more

To learn more about the new search API, I recommend watching WWDC session 709, which introduces the search API. You may also be interested in the NSUserActivity Class Reference and CoreSpotlight documentation. Don't forget that if you want to try the demo described in this article, you can download the source code on GitHub.

<<:  Top sliding menu FDSlideBar

>>:  Apple releases first public beta of OS X Yosemite 10.10.5

Recommend

Heytea’s private domain operation method

A few days ago, when I was browsing the news, I f...

How to understand user growth? Here are 4 cases for you!

During the Spring Festival, I finished reading Hu...

UBS: Apple's dominance in China is over

Recently, UBS released a report saying that the p...

The most popular way of Internet promotion nowadays!

We have sorted out seventeen popular Internet pro...

Super complete! All the advertising strategies for 2018 are here!

According to the data from the "2018 China O...

Baidu cloud of all Jet Li's movies, top ten Jet Li movies!

From a naturally gifted martial arts genius to an...

How does information flow advertising accurately target users?

In this article, we will learn about people with ...

Bullying us secretly? This WeChat update is very unethical

Not long ago, WeChat finally updated its own emot...

Cook recalls Steve Jobs in a long interview: He was my best teacher

[[130357]] On March 19, Fast Company published an...