Ios9-by-tutorials-study Note Ii: App-search

Source: Internet
Author: User
iOS 9 introduced search technology, which enables users to search for content inside the app in Spotlight. Apple provides three APP Search APIs:
* NSUserActivity
* Core Spotlight
* Web markup

Let me briefly explain my understanding of these three APIs:
1. NSUserActivity:
NSUserActivity has been proposed in iOS8, but it was proposed at that time as HandOff. In iOS9 it can be used to search for content in the App. We can put something that we want to be searched in Spotlight into NSUserActivity, and then we can search in Spotlight, but there is a limitation of this, that is, we can only search for the content that users have accessed. Because UIViewController's userActivity property is inherited from UIResponser, only when UIViewcontroller accesses, will you have the opportunity to set the userActivity property.
2. Core Spotlight:
This is a new technology introduced in iOS9, which can search APP content in Spotlight. I understand this technology: Apple provides developers with a global index database. We can put what we want to be able to search in Spotlight into the database according to Apple's requirements, and then Apple does other things, so that It can be searched. We can also delete what we have stored in the database.
3. Web markup:
Web Markup displays the content of the App on the webpage and is indexed into the Spotlight. In this way, even if an App is not installed, Apple's indexer can search for special markups on the webpage and display the search results on Safari or Spotlight . The details will be introduced in the next article.

Getting started
Let's start experimenting with related technologies. Here we still use the star project in the book. Now that the project is running, there are two interfaces:
Here's what worked for this:
The following are explanations of the key classes marked in the figure:
1. AppDelegate
Click on the search results to jump to the program, you will first do some processing in this class
2. EmployeeViewController
Detailed interface of the personnel, which mainly sets NSUserActivity
3. EmployeeService
This is mainly to write index-related things in CoreSpotlight
4. EmployeeSearch
Mainly extends the Employee class, adding search-related attributes
In addition, some operations related to employees in the project are encapsulated in an EmployeeKit target. Since it is not in a module with the main target, import is required in the main target.

There are three options in Settings / Colleagues / Indexing of Iphone:
* Disabled does not use the Search API, that is, the content in the APP cannot be searched in Spotlight
* ViewedRecords can only be searched if opened
* AllRecords all employee information can be searched

Search for what we have opened
Using NSUserActivity to achieve this is relatively simple, as long as two steps are sufficient:
1. Create an instance of NSUserActivity and set related properties
2. Assign to the userActivity property of UIViewController

Below we add the following code to EmployeeSearch:

If there is no such file, you need to create one manually, and then select EmployeeKit as the target

import Foundation
import CoreSpotlight

extension Employee {
  // This is used to distinguish Activities, which will be used when clicking the search result to enter the APP, and related processing can also be used in CoreSpotlight. It will be used when adding and deleting index data.
  public static let domainIdentifier = "com.mengxiangyue.colleagues.employee"
  // dictionary When processing clicks, we can get the data we want according to the dictionary
  public var userActivityUserInfo: [NSObject: AnyObject] {
    return ["id": objectId]
  }

  // Add userActivity attribute to Employee, mainly to facilitate us to get userActivity
  public var userActivity: NSUserActivity {
    let activity = NSUserActivity (activityType: Employee.domainIdentifier)
    activity.title = name // display name
    activity.userInfo = userActivityUserInfo // data related to this Activity
    activity.keywords = [email, department] // Keyword indicates what keywords to search for and can search for this record. Of course, this is only a supplement. There is no name added here, and you can search by name
    return activity
  }
}
This extends Employee and then adds several attributes. See the comments for the meaning of attributes.
At this time we need to recompile EmployeeKit (because it is not the same target as the main target).

Now open EmployeeViewController.swift and add the following code to viewDidLoad ():

let activity = employee.userActivity
switch Setting.searchIndexingPreference {
case .Disabled:
  activity.eligibleForSearch = false
case .ViewedRecords:
  activity.eligibleForSearch = true
  // relatedUniqueIdentifier defines an id to prevent NSUserActivity and Core Spotlight from repeating the index. Here it is set to nil, which will be repeated when displayed.
  activity.contentAttributeSet? .relatedUniqueIdentifier = nil
case .AllRecords:
  activity.eligibleForSearch = true
}

userActivity = activity
The following method is added to this class to update the Activity at the appropriate time:

// Update the information associated with NSUserActivity
  override func updateUserActivityState (activity: NSUserActivity) {
    activity.addUserInfoEntriesFromDictionary (employee.userActivityUserInfo)
  }
Now select ViewedRecords in Settings / Colleagues / Indexing of Iphone. Then start the app, click Brent Reid in the list to enter the detailed page, and then use Command + shift + H to count into the Home page, pull down the search box, and then enter brent to appear the following interface:
Seeing this search result interface is too ugly. Let ’s enrich this search result. The search results provided by Apple can be set as follows:
Below we add the following properties to EmployeeSearch.swift:

public var attributeSet: CSSearchableItemAttributeSet {
  let attributeSet = CSSearchableItemAttributeSet (itemContentType: kUTTypeContact as String)
  attributeSet.title = name // not sure what it is doing
  attributeSet.contentDescription = "\ (department), \ (title) \ n \ (phone)"
  attributeSet.thumbnailData = UIImageJPEGRepresentation (loadPicture (), 0.9)
  attributeSet.supportsPhoneCall = true
  attributeSet.phoneNumbers = [phone]
  attributeSet.emailAddresses = [email]
  attributeSet.keywords = skills
  attributeSet.relatedUniqueIdentifier = objectId

  return attributeSet
}
Then add the following properties to userActivity:

public var userActivity: NSUserActivity {
  let activity = NSUserActivity (activityType: Employee.domainIdentifier)
  activity.title = name
  activity.userInfo = userActivityUserInfo
  activity.keywords = [email, department]
  activity.contentAttributeSet = attributeSet // this new line
  return activity
}
Then run the program, the search results are as follows:
But now we notice that when we click on the search result, opening the app does not jump to the detailed interface of the employee as we expected. This is because we did not do the corresponding processing in the program, let's add the following method to AppDelete:

func application (application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?)-> Void)-> Bool {
  let objectId: String
  // first determine if a type is defined by us and then obtain the corresponding EmployeeId
  if userActivity.activityType == Employee.domainIdentifier, let activityObjectId = userActivity.userInfo? ["id"] as? String {
    objectId = activityObjectId
  }
  // Get the corresponding Employee instance and jump to the corresponding interface
  if let nav = window? .rootViewController as? UINavigationController, listVC = nav.viewControllers.first as? EmployeeListViewController, employee = EmployeeService (). employeeWithObjectId (objectId) {
    nav.popToRootViewControllerAnimated (false)
    let employeeViewController = listVC.storyboard? .instantiateViewControllerWithIdentifier ("EmployeeView") as! EmployeeViewController
    Employe
eViewController.employee = employee
    nav.pushViewController (employeeViewController, animated: false)
    return true
  }
  return false
}
At this time, we can click the search result to jump to the corresponding detailed interface.

CoreSpotlight
Let's start adding these searches using CoreSpotlight. First set the following attributes in the attributeSet of EmployeeSearch.swift:

// already set in the previous code
attributeSet.relatedUniqueIdentifier = objectId
This attribute is mainly used to associate NSUserActivity with Core Spotlight indexed object to prevent duplicate content (if duplicate content appears, it is because the id was not set when testing NSUserActivity at the beginning, just restore the simulator)

Then add the following code in EmployeeSearch.swift:

// CoreSpotlight needs to put items one by one into its index database, and create one here for convenience
var searchableItem: CSSearchableItem {
  let item = CSSearchableItem (uniqueIdentifier: objectId, domainIdentifier: Employee.domainIdentifier, attributeSet: attributeSet)
  return item
}
Then add the following code in EmployeeService.swift:

import CoreSpotlight

.............. <omitting part of the code>

public func indexAllEmployees () {
  let employees = fetchEmployees ()
  let searchableItems = employees.map {$ 0.searchableItem}
  // Put the items we need to be indexed into defaultSearchableIndex
  CSSearchableIndex.defaultSearchableIndex (). IndexSearchableItems (searchableItems) {(error)-> Void in
    if let error = error {
      print ("Error indexing employees: \ (error)")
    } else {
      print ("Employees indexed.")
    }
  }
}
Then select AllRecords in the settings. At this time, start the APP and search. The search results you see are as follows:
But at this time we clicked on the search result and it didn't respond. If we think about it, we can also guess that we need to add code to AppDelete. The final code is as follows:

func application (application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?)-> Void)-> Bool {
    let objectId: String
    if userActivity.activityType == Employee.domainIdentifier, let activityObjectId = userActivity.userInfo? ["id"] as? String {
      objectId = activityObjectId
    }
    // This part of the else is newly added Use different types to distinguish NSUserActivity and CoreSpotlight, and then get the corresponding objectId, other processing is the same
    // CSSearchableItemActivityIdentifier This is a key value provided by CoreSpotlight
    else if userActivity.activityType == CSSearchableItemActionType, let activityObjectId = userActivity.userInfo? [CSSearchableItemActivityIdentifier] as? String {
      objectId = activityObjectId
    } else {
      return false
    }
    if let nav = window? .rootViewController as? UINavigationController, listVC = nav.viewControllers.first as? EmployeeListViewController, employee = EmployeeService (). employeeWithObjectId (objectId) {
      nav.popToRootViewControllerAnimated (false)
      let employeeViewController = listVC.storyboard? .instantiateViewControllerWithIdentifier ("EmployeeView") as! EmployeeViewController
      employeeViewController.employee = employee
      nav.pushViewController (employeeViewController, animated: false)
      return true
    }
    return false
  }
At this time, we should be able to jump into the corresponding personnel details by clicking on the search results.

Delete Item
Finally, in simple terms, delete the indexed Item and modify the corresponding method of EmployeeService.swift as follows:

public func destroyEmployeeIndexing () {
  CSSearchableIndex.defaultSearchableIndex (). DeleteAllSearchableItemsWithCompletionHandler {(error)-> Void in
    if let error = error {
      print ("Error deleting searching employee items: \ (error)")
    } else {
      print ("Employees indexing deleted.")
    }
  }
}
This method will be called when the app is started and Indxing is set to Disabled.

In addition, there are many ways to operate Item in CoreSpotlight. I wo n’t write them one by one here. If you are interested, you can look at the API comments I translated. Of course, the article may be a bit old, but the basic idea should not change. Address: CoreSpotlight.framework annotation translation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.