iOS 9 每天了解多一點第1天:搜索API
在 iOS 9 之前,Spotlight 里只能搜索 app 的名字。隨著 iOS 9 新公布的搜索 API,蘋果現(xiàn)在允許開發(fā)者來定制自己 app 里能被搜到的內(nèi)容,搜索結果在 Spotlight 里顯示的方式,以及用戶點擊搜索結果的事件。
3 個搜索 API
NSUserActivity
NSUserActivity API 是 iOS 8 介紹新功能 Handoff 時引入的,不過在 iOS 9 里,Spotlight 也能搜索到 activity。你現(xiàn)在可以給 acitivity 提供 metadata,表示這個 activity 是能搜到的。實際用起來是一個歷史記錄棧,跟你平常瀏覽網(wǎng)頁類似。用戶可以從 Spotlight 里快速打開最近使用過的 activity。
Web Markup
Web Markup 的機制是,app 可以把內(nèi)容鏡像到一個網(wǎng)站上,然后 Spotlight 就會索引里面的內(nèi)容。即使用戶設備上沒裝這個 app,Spotlight 里也能顯示出搜索結果。蘋果的爬蟲會在網(wǎng)絡上持續(xù)爬取,尋找網(wǎng)站上的特定 markup。之后搜索結果在 Safari 里和 Spotlight 里都會出現(xiàn)。
即使用戶沒裝這個 app,都能搜到結果,所以這個功能至關重要,它能給你帶來很多在潛在用戶面前曝光的機會。你暴露給搜索 API 的 app 里的深度鏈接,會被存到蘋果的云索引上。想進一步了解 Web Markup,可以看看蘋果的官方文檔 Use Web Markup to Make App Content Searchable。
CoreSpotlight
CoreSpotlight 是一個 iOS 9 的新框架,能讓你索引 app 里的任何內(nèi)容。之前提到的 NSUserActivity 可以用來保存用戶的歷史信息,而這個新的 API 可以索引任何數(shù)據(jù)。它為你接觸到用戶設備上的 CoreSpotlight 索引提供了必不可少的橋梁。
使用 Core Spotlight API
NSUserActivity 和 Web Markup API 相對來說用起來比較容易,而 CoreSpotlight 就要復雜一些。為了演示新的 CoreSpotlight API 是怎么用的,我們來做一個簡單的 app 吧。它的功能就是顯示一個朋友列表,點擊朋友名字的時候顯示一張肖像。你可以在GitHub上下載到源代碼,一步一步跟著做。
App里有一個簡單的 storyboard,里面有一個FriendTableViewController,顯示簡單的朋友列表;還有一個FriendViewController,顯示每個朋友的細節(jié)。
所有朋友的信息都存在Datasource類里。我們用這個類來創(chuàng)建保存朋友信息的 model,另外,把朋友保存到 Core Spotlight 索引的邏輯也寫在這個類里。
首先,我們重寫Datasource類的init()方法,在這個方法里創(chuàng)建并保存一個Person數(shù)組。可能數(shù)據(jù)一般應該是從數(shù)據(jù)庫、服務器接口等處讀出來的,為了演示起見,我們就簡單寫一些假數(shù)據(jù)吧。
- override init () {
- let becky = Person()
- becky.name = "Becky"
- becky.id = "1"
- becky.image = UIImage(named: "becky")!
- ...
- people = [becky, ben, jane, pete, ray, tom]
- }
people數(shù)組存好數(shù)據(jù)之后,Datasource就準備就緒啦!
這邊數(shù)據(jù)已經(jīng)準備完畢,F(xiàn)riendTableViewController就可以創(chuàng)建一個Datasource的實例,在 table view 要顯示 cell 的時候使用。
- let datasource = Datasource()
在cellForRowAtIndexPath方法里,顯示 cell 內(nèi)容的代碼如下:
- let person = datasource.people[indexPath.row]
- cell?.textLabel?.text = person.name
#p#
把 person 數(shù)據(jù)保存到 Core Spotlight 上
現(xiàn)在有了假數(shù)據(jù),我們就可以用上 iOS 9 的新 API,把它存到 Core Spotlight 上了。回到Datasource類,我們在這個類里定義了一個方法savePeopleToIndex。FriendTableViewController的界面加載完畢后,就可以調(diào)用這個方法。
在這個方法里,我們循環(huán)遍歷people數(shù)組里的每一個 person,為每一個 person 分別創(chuàng)建一個 CSSearchableItem,存到一個臨時數(shù)組searchableItems里。
- let attributeSet = CSSearchableItemAttributeSet(itemContentType: "image" as String)
- attributeSet.title = person.name
- attributeSet.contentDescription = "This is an entry all about the interesting person called (person.name)"
- attributeSet.thumbnailData = UIImagePNGRepresentation(person.image)
- let item = CSSearchableItem(uniqueIdentifier: person.id, domainIdentifier:
- "com.ios9daybyday.SearchAPIs.people", attributeSet: attributeSet)
- searchableItems.append(item)
最后一步是在默認的CSSearchableIndex上調(diào)用indexSearchableItems。這一步就真正把這些 item 存到 CoreSpotlight 里了,此后用戶就可以搜索這些數(shù)據(jù),會在搜索結果里出現(xiàn)。
- CSSearchableIndex.defaultSearchableIndex().indexSearchableItems(searchableItems,
- completionHandler: { error -> Void in
- if error != nil {
- print(error?.localizedDescription)
- }
- })
完事兒了!把 app 跑起來,數(shù)據(jù)會實時加入存儲;在 spotlight 里一搜,就能搜到你的朋友啦~
響應用戶點擊
現(xiàn)在用戶能在 Spotlight 里看到你的搜索結果了,但愿他們會點上一點!但如果他們真點了,會發(fā)生什么呢?就此刻而言,點擊搜索結果只會跳轉打開你的 app。如果你想要展示出用戶剛點擊的那位朋友,還得再寫點代碼。我們可以在 app 的AppDelegate的 continueUserActivity UIApplicationDelegate 方法里指定 app 從搜索結果打開之后的行為。
以下是這整個方法的代碼:
- func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
- // Find the ID from the user info
- let friendID = userActivity.userInfo?["kCSSearchableItemActivityIdentifier"] as! String
- // Find the root table view controller and make it show the friend with this ID
- let navigationController = (window?.rootViewController as! UINavigationController)
- navigationController.popToRootViewControllerAnimated(false)
- let friendTableViewController = navigationController.viewControllers.first as! FriendTableViewController
- friendTableViewController.showFriend(friendID)
- return true
- }
如代碼所示,之前我們用indexSearchableItems方法存在 CoreSpotlight 索引里的信息,現(xiàn)在可以用userActivity.userInfo獲取到。這里我們唯一感興趣的就是朋友的 ID,這個 ID 我們保存在索引 item 的kCSSearchableItemActivityIdentifier里了。
我們從userInfo字典里提取出 ID 之后,下一步是獲取到 app 的 navigation controller,pop 到首頁(不帶動畫,這樣用戶就不會看到 pop 的過程),然后調(diào)用friendTableViewController的showFriend方法。這個方法的細節(jié)我就不多說了,總之就是根據(jù) ID 從 datasource 里找到對應的朋友,然后 push 進來一個新的 view controller。收工啦!現(xiàn)在當用戶點擊 spotlight 里的朋友時,他們會看到下面的畫面:
截圖上可以看到,app的左上角有一個“Back to Search”按鈕。點擊這個按鈕會直接回到搜索結果頁面,就是剛才點擊朋友名字的那個頁面。用戶還可以點擊標準的返回按鈕,接著在 app 里面逛。
Demo 小結
在上面這個 demo 里,我們展示了整合 app 的數(shù)據(jù)與CoreSpotlight索引如此簡單,引導用戶打開 app 的功能如此強大,以及對用戶搜索特定內(nèi)容如此有幫助。
不過,我們并沒提到怎么從索引里刪除數(shù)據(jù)。這一點還是很重要的,應該勤于更新索引的數(shù)據(jù)。想進一步了解如何從 CoreSpotlight 刪除舊數(shù)據(jù),可以看看 deleteSearchableItemsWithIdentifiers,deleteSearchableItemsWithDomainIdentifiers 以及 deleteAllSearchableItemsWithCompletionHandler 方法。
有節(jié)操的重要性
盡管讓 Spotlight 和 Safari 索引到的 app 內(nèi)容似乎越多越好,在大肆往里灌水之前還是要三思。在 iOS 生態(tài)系統(tǒng)里保持節(jié)操,不僅能讓用戶更舒服,而且蘋果也盯著呢。蘋果花了很多心思來保證搜索結果是真正相關的,他們會跟蹤搜索結果點擊率,而灌水會導致被挪到搜索結果的末尾。
了解更多
想要進一步了解新的搜索 API,推薦看一看 WWDC session 709,介紹搜索 API。你也可能會對 NSUserActivity Class Reference與CoreSpotlight 文檔感興趣。別忘了,如果想要試試本文描述的 demo,可以在GitHub上下到源碼。