[Swift][iOS9] Sử dụng AppSearch để làm 1 ứng dụng từ điển đơn giản

1434813906712781454.jpg

Mở đầu

Chắc hẳn mỗi người dùng iPhone đều không xa lạ gì với Spotlight. Chúng ta có thể sử dụng nó để tìm app, tìm contact của 1 người nào đó, hay thậm chí là tìm các thông tin trên internet một cách nhanh chóng. Thay vì phải thực hiện nhiều thao tác chúng ta chỉ cần trượt màn hình xuống, điền thông tin cần tìm kiếm vào là xong.

Hãy thử tưởng tượng, khi bạn học thêm 1 ngôn ngữ mới, để tra nghĩa của từ, thay vì vào app từ điển (đôi khi tôi còn chẳng nhớ nó nằm ở đâu nữa) và thực hiện các thao tác search, chúng ta có thể search ngay trên Spotlight. Điều đó thật là tiện lợi, nhưng nó ĐÃ TỪNG là bất khả thi vì Spotlight không cho phép chúng ta can thiệp sâu như vậy vào trong ứng dụng.

Khi giới thiệu iOS 9, Apple đã cho phép bên thứ ba có thể tạo các nội dung có thể search được trên Spotlight thông qua App search APIs. Và điều bất khả thi ở trên đã dần trở thành hiện thực. Với bài viết này, tôi sẽ hướng dẫn các bạn tìm hiểu qua về App search APIs thông qua 1 ứng dụng từ điển tiếng Nhật đơn giản. Let's begin

App search APIs

Trước khi bắt tay vào làm app, chúng ta sẽ tìm hiểu qua về App search APIs. App search trên iOS 9 bao gổm 3 phần chính. Mỗi phần thực hiện 1 nhiệm vụ riêng biệt, nhưng nó cũng có thể phối hợp cùng các phần khác. 3 phần đó bao gồm :

1. NSUserActivity

Trên iOS9, NSUserActivity (vốn đã có mặt từ iOS 8 để thực hiện chức năng Handoff) đã được bổ sung thêm một vài property mới để thực hiện chức năng search.

Theo lý thuyết, nếu 1 task có thể được represent như một NSUserActivity để được handoff sang 1 device khác, thì nó cũng có thể được tiếp tục "handoff" trên chính device này. Điều này có nghĩa là chúng ta có thể index activities, states và navigation points trong ứng dụng, sau đó "handoff" nó cho Spotlight, hay như chúng ta vẫn nói thì là search trên Spotlight

2. Core Spotlight

Được giới thiệu trên iOS9, đây có lẽ là phần quy chuẩn nhất trong App Search. Đơn giản là bạn không thể custom nó theo ý muốn, mà chỉ có thể thay đổi code để phù hợp với những tiêu chuẩn có sẵn của Apple. Tuy nhiên nó lại có 1 sức mạnh to lớn mà có thể cho phép người dùng có thể search nội dung bên trong ứng dụng ngay trên spotlight, đúng như tên gọi của nó Core Spotlight

Và Core Spotlight chính là chìa khóa giúp chúng ta thực hiện điều mong muốn trên. Đơn giản bạn chỉ cần index dữ liệu, việc còn lại cứ để Core Spotlight lo.

3. Web markup

Phần cuối cùng của AppSearch chính là Web markup. Công việc của Web markup chỉ đơn giản là giúp bạn có thể search được nội dung website của bạn ngay trên Spotlight. Thật là "đơn giản" 😄 nên trong phạm vi bài này, tôi sẽ k đề cập đến Web markup.

Start

Cuối cùng cũng đọc xong cái phần lý thuyết dài ngoẵng, thôi cứ thực hành cho nó nhớ lâu chứ nói suông 1 lúc lại quên mất. Cùng thực hiện cái ứng dụng ở phần mở đầu thôi.

1. Chuẩn bị

Chúng ta sẽ chuẩn bị 1 ứng dụng đơn giản, hiển thị các từ tiếng Nhật có trong file JSON

[
    {
    "furigana": "わたし",
    "kanji": "私",
    "romanji": "watashi",
    "vietnamese": "Tôi",
    "favourite": 0,
    "vocabularyID" : "1"
    },
    {
    "furigana": "わたしたち",
    "kanji": "私達",
    "romanji": "watashitachi",
    "vietnamese": "Chúng ta",
    "favourite": 0,
    "vocabularyID" : "2"
    },
    {
    "furigana": "あなた",
    "kanji": "貴方",
    "romanji": "anata",
    "vietnamese": "Bạn (ngôi thứ 2)",
    "favourite": 0,
    "vocabularyID" : "3"
    },
    {
    "furigana": "ともだち",
    "kanji": "友達",
    "romanji": "tomodachi",
    "vietnamese": "Bạn bè",
    "favourite": 0,
    "vocabularyID" : "4"
    },
    {
    "furigana": "じしょ",
    "kanji": "辞書",
    "romanji": "jisho",
    "vietnamese": "Từ điển",
    "favourite": 0,
    "vocabularyID" : "5"
    }
]

Vì mục đích của chúng ta là có thể search được nó ở trên Spotlight, nên bạn có thể sử dụng luôn code ở trong thư mục Startsource để thực hiện.

2. Index dữ liệu

Để dữ liệu có thể được search thông qua Spotlight, chúng ta phải thực hiện việc index dữ liệu với CSSearchableIndex. Do đó, việc quan trọng nhất và cũng là việc mà bạn phải thực hiện đầu tiên là

import CoreSpotlight

you-don-t-say-foto.jpg

Sử dụng hàm có sẵn trong CoreSpotlight để thực hiện việc index, việc gọi hàm index ở đâu sẽ tùy thuộc vào yêu cầu của ứng dụng, ở đây, tôi sẽ gọi luôn nó ở AppDelegate

        let searchableItems : [CSSearchableItem] = // TODO:
        CSSearchableIndex.defaultSearchableIndex().indexSearchableItems(searchableItems) { error in
            if let error = error {
                print("Error = \(error)")
            }
        }

Câu lệnh trên chỉ thiếu duy nhất 1 biến là 1 array chứa các CSSearchableItem. Như vậy, với mỗi 1 Vocabulary đã có, chúng ta sẽ phải tạo ra 1 CSSearchableItem tương ứng.

Screen Shot 2016-04-07 at 9.38.31 AM.png

import CoreSpotlight
import MobileCoreServices

extension Vocabulary {
    static let domainIdentifier = "com.quocnb.appsearchdemo.vocabulary"
    var attributeSet: CSSearchableItemAttributeSet {
        let attributeSet = CSSearchableItemAttributeSet(
            itemContentType: kUTTypeMessage as String)
        attributeSet.title = self.kanji
        attributeSet.contentDescription = "\(self.furigana)\n\(self.vietnamese)"
        return attributeSet
    }
    var searchableItem: CSSearchableItem {
        let item = CSSearchableItem(uniqueIdentifier: self.vocabularyID,
                                    domainIdentifier: Vocabulary.domainIdentifier,
                                    attributeSet: attributeSet)
        return item
    }
}

Quá đơn giản, bây giờ bạn chỉ cần run app và tận hưởng kết quả thôi

Screen Shot 2016-04-07 at 10.23.43 AM.png

Với kết quả ở trên, rõ ràng bạn có thể thấy chúng ta có thể search được kết quả không chỉ ở title (Kanji) mà còn có thể search được cả kết quả từ description của nó (Furigana + Vietnamese)

3. Xử lý action khi bấm vào kết quả trên Spotlight

OK, với các bước đơn giản trên, chúng ta đã có thể search được kết quả trong app ở ngay trên spotlight. Khi bấm vào kết quả trên spotlight, ứng dụng của chúng ta sẽ được tự động mở ra. Tuy nhiên, nếu nó nhảy thẳng vào phần detail thì sẽ ứng dụng sẽ ngon hơn nhiều

Nhớ lại 1 chút phần lý thuyết ở trên nào, Core Spotlight không cho phép chúng ta custom nhiều, trong đó có việc handle action xem khi bấm vào kết quả search trên Spotlight. Tuy nhiên, trong App Search ngoài Core Spotlight còn có NSUserActivity, thứ sẽ giúp chúng ta thực hiện việc còn thiếu

Trong AppDelegate đã có sẵn function hỗ trợ việc bắt action của NSUserActivity, overwrite nó

func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
        guard userActivity.activityType == CSSearchableItemActionType,
            let uniqueIdentifier = userActivity.userInfo? [CSSearchableItemActivityIdentifier] as? String else {
                return false
        }
        guard let nav = self.window?.rootViewController as? UINavigationController,
            listVC = nav.viewControllers.first as? VocabularyListTableViewController,
            let vocabulary = VocabularyService().vocabularyWithID(uniqueIdentifier) else {
            return false
        }
        nav.popToRootViewControllerAnimated(false)
        let vocabularyDetailVC = listVC.storyboard?.instantiateViewControllerWithIdentifier("VocabularyDetailViewController") as! VocabularyDetailViewController
        vocabularyDetailVC.vocabulary = vocabulary
        nav.pushViewController(vocabularyDetailVC, animated: true)
        return true
    }

Check nếu Activity được gửi từ Spotlight và xử lý nó theo yêu cầu của ứng dụng, hiển thị từ tiếng Nhật đã được chọn trên Spotlight. Thế là xong

Kết

Qua ví dụ nhỏ trên, tôi đã hướng dẫn các bạn tìm hiểu qua về App search APIs. Tuy App search APIs chỉ hỗ trợ trên iOS 9 trở đi nhưng hi vọng nó sẽ có ích trong các ứng dụng mà bạn sắp thực hiện. Nếu bạn cần demo, nó ở ngay đây, feel free to using it