Tìm hiểu App Search (Phần 1)

Với iOS9, Apple đã thêm vào 1 tính năng thú vị, chúng ta đã có thể tạo nội dung search thông qua Spotlight.

App search APIs

App search trong iOS gồm có 3 cái chính. Mỗi cái sẽ chia thành các API riêng biệt để đạt kết quả riêng biệt, nhưng chúng cũng làm việc với nhau.

  • NSUserActivity App search sử dụng cùng 1 API NSUserActivity đã được dùng để enable Handoff ở iOS8.
    Ở iOS9, NSUserActivity có thêm vài property mới để enable search. Theo lý thuyết, nếu 1 tác vụ có thể được đại diện như một NSUserActivity được chuyển đến 1 device khác, nó có thể được lưu trữ trong search index và sau đó tiếp tục trên cùng device. Điều này cho phép ta index các activity, states và navigation points trong app, cho phép user tìm kiếm chúng sau đó với Spotlight. VD 1 travel app có thể có index hotel mà user đã xem hoặc 1 news app có thể có index của topic user tìm kiếm.
  • Core Spotlight Khía cạnh thứ 2 và có thể là hầu hết các khía cạnh thông thường của app search là Core Spotlight, đó là cái mà trong các ứng dụng Mail, Note dùng để lập index content. Mặc dù việc người dùng tìm kiếm nội dung đã truy cập trước đây là rất tốt nhưng ta có thể thực hiện nó bằng một bộ nội dung lớn có thể tìm kiếm trong một lần. Ta có thể nghĩ Core Spotlight như cơ sở dữ liệu cho thông tin tìm kiếm. Nó giúp ta kiểm soát cái gì, khi nào và bằng cách nào nội dung được thêm vào chỉ mục tìm kiếm. Ta có thể lập chỉ mục tất cả các loại nội dung, từ các file đến video sang tin nhắn và hơn thế nữa, cũng như cập nhật và xóa các chỉ mục tìm kiếm. Core Spotlight là cách tốt nhất để cung cấp khả năng tìm kiếm đầy đủ cho nội dung riêng của ứng dụng.
  • Web markup Khía cạnh thứ ba của app search là web markup, được thiết kế riêng cho các ứng dụng phản ánh public content của họ từ một trang web. Một ví dụ điển hình là Amazon, nơi ta có thể tìm kiếm hàng triệu sản phẩm mà mình bán. Sử dụng open standards để đánh dấu nội dung web, ta có thể hiển thị nó trong các kết quả tìm kiếm Spotlight và Safari và thậm chí tạo liên kết sâu trong ứng dụng.

Implement NSUserActivity

Đầu tiên ta tạo 1 list person ở home. Sau đó khi select từng person thì ta qua trang detail tương ứng. Sau đó ta add thêm setting bundle Thay đổi plist setting Tạo 1 file Setting.swift

import Foundation

enum SearchIndexingPreference: Int {
    case Disabled, ViewedRecords
}

struct Setting {
    static var searchIndexingPreference: SearchIndexingPreference {
        let preferenceRawValue = UserDefaults.standard.integer(forKey: "SearchIndexingPreference")
        if let preference = SearchIndexingPreference(rawValue: preferenceRawValue) {
            return preference
        } else {
            return .Disabled
        }
    }
}

Trong person model, ta viết các hàm xử lý cho NSUserActivity.

import CoreSpotlight

extension Person {
    public static let domainIdentifier = "com.sample.AppSearchSample.person"
    
    public var userActivityUserInfo: [NSObject: AnyObject] {
        return ["id" as NSObject: id as AnyObject]
    }
    
    public var userActivity: NSUserActivity {
        let activity = NSUserActivity(activityType: Person.domainIdentifier)
        activity.title = name
        activity.userInfo = userActivityUserInfo
        activity.keywords = [email, department]
        return activity
    }
}

Reverse-DNS formatted string dùng để xác định type của NSUserActivity được tạo cho Person.

Ngoài ra, person sẽ có 1 NSUserActivity có các property:

  • activityType: The type of activity mà nó đại diện. Ta sẽ sử dụng sau để xác định các trường hợp NSUserActivity mà iOS cung cấp. Apple đề xuất sử dụng reverse DNS formatted strings.
  • title: Tên của activity - nó cũng sẽ xuất hiện dưới dạng tên chính trong kết quả tìm kiếm.
  • userInfo: A dictionary of values để ta sử dụng khi muốn. Khi acitivity được chuyển đến ứng dụng, chẳng hạn như khi người dùng chọn kết quả tìm kiếm trong Spotlight, ta sẽ nhận được dictinary này. Ta sẽ sử dụng nó để lưu ID của Person, cho phép ta hiển thị chính xác record khi app starts.
  • keywords: Một set of localized keywords giúp người dùng tìm thấy record khi tìm kiếm.

Ở page detail, trong viewDidLoad() ta xử lý activity của Person như sau:

override func viewDidLoad() {
        super.viewDidLoad()
        
        let activity = person.userActivity
        
        switch Setting.searchIndexingPreference {
        case .Disabled:
            activity.isEligibleForSearch = false
        case .ViewedRecords:
            activity.isEligibleForSearch = true
        }
        
        userActivity = activity
    }

Cái này sẽ lấy ra UserActivity - thuộc tính ta vừa tạo trong extension Persion. Sau đó nó sẽ kiểm tra app’s search setting.

  • Nếu search bị disabled, ta đánh dấu the activity là ineligible cho search.
  • Nếu search setting được set là ViewedRecords, ta đánh dấu the activity là eligible cho search.
  • Cuối cùng, ta set view controller’s userActivity cho person’s activity.

Bước cuối là override updateUserActivityState(). Điều này đảm bảo rằng khi 1 search result được selected ta sẽ có các thông tin cần thiết.

override func updateUserActivityState(_ activity: NSUserActivity) {
        activity.addUserInfoEntries(
            from: person.userActivityUserInfo)
    }

Vào Setting -> AppSearchSample, thay đổi Indexing setting thành Viewed Records Sau đó build và Run app, select David Beckham sau đó Search: