iOS 9 App Search教程

來源:互聯網
上載者:User

iOS 9 App Search教程

 

在相當長的一段時間內,iOS 的 Spotlight 都是一個大坑。儘管使用者可以用它來搜尋你的 App,但他們卻無法看到其中的內容——他們真正關心的部分。現在,當使用者想讀取一個 App 中的內容時,他們只能回到 Home 屏一屏一屏翻,找到 App,開啟 App,搜尋他們想要的內容——假設你的App實現了搜尋功能的話。

對於比較老練的使用者,則可能會通過Siri 或者 Spotlight 來開啟你的 App,但無論哪個工具都不能讓使用者尋找“非蘋果官方App”內的內容。也就是說,蘋果在 Spotlight 中可以尋找通訊錄、備忘錄、資訊、郵件以及其它支援尋找功能的App中的內容。使用者只需要點擊搜尋結果就可以直接存取相應的內容。這真是太不公平了!

有時蘋果會將一些有趣的功能保留給自己專用,比如 Spotlight。好訊息是,每當蘋果的開發人員調教好一個功能,覺得已經可以把它放出去的時候,他們就會讓大夥也嘗嘗鮮,比如 iOS 8 中的 App 擴充。

在iOS 9 中,蘋果又放出來一個很酷的功能給我們,第三方開發人員現在可以在Spotlight 中搜尋他們的App 內容了!

在本教程中,你將領略 App Search 的威力,並學會如何將它整合到你自己的App 中。

App Search API

在iOS 9 中,App Search由三個部分組成。每一部分根據不同的目的分成獨立的 API,但它們也能和其它部分一起使用:

NSUserActivity Core Spotlight Web markupNSUserActivity

在App Search 中,使用了NSUserActivity,這是一個靈活小巧功能,在iOS 8 Handoff 中就使用到了NSUserActivity 。

在iOS 9 中,NSUserActiviy增加一些新的屬性以支援 App Search。從理論上講,如果一個任務能夠轉變成一個 NSUserActivity 並轉交給其它裝置,它也能轉換為一個搜尋項並在同一個裝置上繼續處理。這就有可能對App 上的活動、狀態和導航點進行索引,這樣使用者才能在 Spotlight 中對其進行搜尋。

例如,一個旅遊類App 可能會將使用者查看過的酒店進行索引,而一個新聞類App 會將使用者瀏覽過的文章進行索引。

注意:本教程不涉及 Handoff,我們只會討論當一個內容被瀏覽後如何建立可搜尋的內容。如果你想熟悉瞭解 Handoff 的內容,請閱讀 Getting Started with Handoff 教程。

Core Spotlight

第二個同時也是App Search 中最“常用到的”概念就是 Core Spotlight,它是儲存類 App 諸如郵件、備忘錄用於索引內容的東西。它既可以允許使用者搜尋之前訪問過的內容,也可以用它來一次性構建一個巨大的可搜尋內容的集合。

你可以將Core Spotlight 看成是一個專門用於搜尋的資料庫。它提供了對添加搜尋索引中的內容的細粒度的控制,例如這些內容是什麼、什麼時候添加的以及如何添加到搜尋索引中的。你可以檢索任何類型的內容,包括檔案、視頻、訊息等等,還可以更新和移除搜尋索引中的條目。

Core Spotlight 為全面搜尋 App 內部內容提供了一種最好的方式。

本教程關注於使用前面提及的 NSUserActivity 對象擷取 Spotlight 搜尋結果。本教程的完整版位於《iOS 9 Tutorials》中,其中介紹了如何通過Core Spotlight 全面檢索你的內容。

Web markup

App Search的第三個方面是 Web Markup,這個功能允許App 將它們的內容鏡像到一個Web網站上。比較好的例子如 Amazon,你可以搜尋它上面成千上萬的在售產品,甚至是raywenderlich.com上的產品。在web 內容上使用了標準的標籤進行標記,你可以將App 內容顯示在 Spotlight 和 Safari的搜尋結果中,甚至可以直接連結到你的App。

本教程不涉及 Web Markup,你可以在《iOS 9 by Tutorials》第三章“Your App On The Web”中學習這部分內容。

開始

你將學習的樣本程式叫做 Colleagues,它類比一個公司通訊錄。它可以將你的同時添加到你的連絡人中,而不是直接給你一個同事的目錄。為了簡單起見,它使用的是本機資料庫,由一個檔案夾(存放頭像圖片)和一個 JSON檔案(包含了所有公司職員資訊)組成。在生產環境中,你應該使用一個網路組件從 Web 上抓取這些資料。作為教程,JSON 檔案就足夠了。下載並開啟初始項目,不需要做任何事情,直接編譯運行。

你會看到一張職員列表。這是一個小型創業公司,只有25個職員的規模。選擇 Brent Reid,可以查看這個職員的資訊。你同時還可以看到 Brent Reid 所在的部門的其他人的列表。那是 App 的一個擴充功能——其實非常簡單!

搜尋功能將讓 App 增色不少。但是現在,你甚至無法在 App 搜尋。你不用在 App 中增加搜尋功能,相反,你可以用 Spotlight 從 App 外部增加一個搜尋功能。

樣本項目

花點時間來熟悉一下樣本項目的代碼。項目中存在兩個 Target,一個是 Colleagues,即 App 自身;一個是 EmployeeKit,負責和職員資料庫進行互動。

在 Xcode 中,展開 EmployeeKit 檔案夾,開啟 Employee.swift。這是職員資訊的模型類,定義了一系列相關屬性。Employee 對象使用一個 JSON 對象進行執行個體化,後者來自於 Database 檔案夾下的 employees.json 檔案。

然後開啟 EmployeeService.swift。在檔案頭部聲明了一個擴充,擴充中有一個 destroyEmployeeIndexing()方法,這個方法用TODO標記進行註明。你將在稍後實現這個方法。這個方法負責銷毀所有顯示過的索引。

在 EmployeeKit 這個 Target 中有許多內容,但都和 App Search 毫無關聯,因此我們就不多說了。當然,你可以花時間看一看。

開啟Colleagues 檔案夾下的 AppDelegate.swift。注意只有一個方法在裡邊:
application(_:didFinishLaunchingWithOptions:)。這個方法判斷Setting.searchIndexingPreference 是否設定為 .Disabled,如果是,則將所有存在的搜尋索引刪除。

除了知道有這麼一個設定項存在外,你並不需要做任何事情。你可以通過 iOS 的設定程式中的 Colleagues 來修改這個設定。

參觀到此結束。接下來你需要修改 View Controller 中的代碼。

搜尋曾經瀏覽過的記錄

實現App Search時,NSUserActivity 總是第一個要實現的,因為:

它最簡單。建立一個 NSUserActivity 執行個體就如同設定幾個屬性那麼簡單。

當你用 NSUserActivity 表示使用者活動時,iOS 會對內容進行排序,以便搜尋結果對經常被訪問的內容進行優先處理。

它和實現 Handoff 很像。

現在,讓我們來看看實現 NSUserActivity 到底有多簡單!

實現 NSUserActivity

選中 EmployeeKit 檔案夾,依次選擇 File \ New \ File…,然後選擇 iOS\ Source \ Swift File 模板,再點擊 Next。將檔案命名為 EmployeeSearch.swift,並確保其 Target 為 EmployeeKit。

在這個檔案中,首先匯入 CoreSpotlight:

import CoreSpotlight

然後定義一個 Employee 的擴充:

extension Employee {  public static let domainIdentifier = "com.raywenderlich.colleagues.employee"}

反網域名稱字串將用於唯一標識 NSUserActivity 所屬的一類活動類型。接著,在domainIdentifier 之後增加一個計算屬性:

public var userActivityUserInfo: [NSObject: AnyObject] {  return ["id": objectId]}

這個字典用於 NSUserAcitivity 唯一標識某個活動(Activity)。然後再添加一個計算屬性,名為 userActivity:

public var userActivity: NSUserActivity {  let activity = NSUserActivity(activityType: Employee.domainIdentifier)  activity.title = name  activity.userInfo = userActivityUserInfo  activity.keywords = [email, department]  return activity}

這個屬性用於很方便地根據一個 Employee 建立一個 NSUserActivity 執行個體。它建立了一個 NSUserActivity 對象,並用對以下屬性進行了賦值:

activityType:活動所屬的類型。你會在後面用它來識別 iOS 傳遞給你的NSUserActivity執行個體。蘋果建議該值採用反網域名稱命名規則。

title:活動的名字——這將用於在搜尋結果中作為主要名顯示。

userInfo:一個字典,用於存放你想傳遞的任意資料。當你的App 收到一個活動時——比如使用者從 Spotlight 點擊了一個搜尋結果,你就可以擷取這個字典。你將在這個字典中存放同事的唯一 ID,這樣 App 開啟後就能顯示正確的同事資料。

keywords:一個本地化的關鍵字列表,用於作為搜尋索引鍵。

然後,我們將使用剛才定義的 userActivity 屬性去搜尋同事記錄。因為這些代碼位於 EmployeeKit 架構中,我們需要編譯架構才能在 Colleagues App 中使用它們。

按 Command+B,編譯項目。

開啟 EmployeeViewController.swift,在viewDidLoad()方法最後加入代碼:

let activity = employee.userActivityswitch Setting.searchIndexingPreference {case .Disabled:  activity.eligibleForSearch = falsecase .ViewedRecords:  activity.eligibleForSearch = true}userActivity = activity

上述代碼讀取 userActivity 屬性——這個屬性是我們剛才通過定義 Employee 擴充時添加的。然後檢查 App 的搜尋設定。

如果搜尋被禁用,將 activty 標記為不可用於搜尋。如果該設定為 ViewedRecords,則將 activity 標記為能夠用於搜尋。

最後,將 View Controller 的 userActivity 屬性設定為 employee 的 userActivity。

注意:View Controller 的 userActivity 屬性繼承自 UIResponder 。這個屬性是蘋果為了支援 Handoff 而增加到 iOS 8 中的。

最後還應該覆蓋 updateUserActivityState() 方法。這樣,當某個搜尋結果被選擇時,你才可以獲得所需要的資料。

在 viewDidLoad() 方法後增加這個方法:

override func updateUserActivityState(activity: NSUserActivity) {  activity.addUserInfoEntriesFromDictionary(    employee.userActivityUserInfo)}

在 UIResponder 的生命週期中,系統會多次調用這個方法,你應該在這個方法中保持更新 activity。在我們的例子裡,你只需要將包含有 employee的 objectId 的 userActivityUserInfo 字典傳遞給 activity。

好了!現在,在搜尋設定被開啟的情況下,每當你瀏覽了一個同事,瀏覽曆史將被記下並可用於搜尋。

在模擬器或裝置上,開啟設定程式,找到 Colleagues。將 Indexing 設定改成 Viewed Records。

現在,編譯運行程式,然後選擇 Brent Reid。

OK,看起來沒有什麼新奇的事情發生,但在你不知不覺中,Brent 的活動已經被加到搜尋索引中了。回到 Home 螢幕(shift+command+H),通過下拉螢幕或者向右划動螢幕,開啟 Spotlight。在搜尋欄輸入 brent reid 。

“Brent Reid”顯示出來了!如果你沒看見,可能需要向下滾動列表。如果你點擊這個Brend Reid,它將移動到列表上部,以便下次你可以搜尋同一個關鍵字。

雖然到現在為止結果還蠻不錯,但這個搜尋結果卻是有點索然無味了。

除了顯示一個名字外,我們還能幹什嗎?現在就讓我們徹底進入 Core Spotlight 的殿堂探索一番。

在搜尋結果中顯示更多資訊

NSUserActivity 有一個 contentAttributeSet 屬性。這個屬性的類型是 CSSearchableItemAttributeSet,它允許你用一系列屬性來描述你的內容。查看 CSSearchableItemAttributeSet 類參考,你可以發現很多利用這些屬性來描述內容的方法。

是我們需要的搜尋結果,每個部分都分別標出了所用的屬性名稱:

前面已經設定過 NSUserActivity 的 title 屬性,這個屬性正如你所看到的。其它3個屬性,thumbnailData、supportsPhoneCall 和 contentDescription 全部都是通過 CSSearchableItemAttributeSet 來設定的。

開啟 EmployeeSearch.swift,在檔案頭部,匯入 MobileCoreServices:

import MobileCoreServices

MobileCoreServices 是必須的,因為在我們建立 CSSearchableItemAttributeSet 對象時需要用到其中定義的一個常量。你已經匯入過 CoreSpotlight了,這個架構也是必須的,它的所有 API 都使用了 CS 作為首碼。

仍然在 EmployeeSearch.swift中,在 Employee 擴充中添加新的計算屬性:

public var attributeSet: CSSearchableItemAttributeSet {  let attributeSet = CSSearchableItemAttributeSet(    itemContentType: kUTTypeContact as String)  attributeSet.title = name  attributeSet.contentDescription = "\(department), \(title)\n\(phone)"  attributeSet.thumbnailData = UIImageJPEGRepresentation(    loadPicture(), 0.9)  attributeSet.supportsPhoneCall = true  attributeSet.phoneNumbers = [phone]  attributeSet.emailAddresses = [email]  attributeSet.keywords = skills  return attributeSet}

初始化 CSSearchableItemAttributeSet 時,需要提供一個 itemContentType 參數,我們傳遞了一個 kUTTypeContact 進去(該常量在 MobileCoreServices 架構中定義,關於該常量,請閱讀蘋果的 UTType 參考)。

attributeSet 中包含了一些與當前 employee 搜尋時用到的相關資料:title 來自於 NSUserActivity 的 title,contentDescription 包括了這個同事的部門、稱謂和電話號碼等資訊,而 thumbnailData 則調用 loadPicture() 方法結果並轉換為 NSData。

要顯示”打電話“按鈕,我們必須將 supportsPhoneCall 設定為true,並給 phoneNumbers 屬性賦一個數組。最後,我們設定了 email 地址,並將同事的 skills (技能)作為 keyword 關鍵字。

現在所有的資料都準備好了,Core Spotlight 在搜尋時會檢索這些資料並添加到搜尋結果中。這樣,使用者就可以搜尋同事的姓名、部門、稱謂、電話號碼、email甚至是技能。

仍然是 EmployeeSearch.swift,在返回 userActivity 前面添加以下語句:

activity.contentAttributeSet = attributeSet

這句代碼告訴 NSUserActivity 使用這些資訊作為 contentAttributeSet屬性的值。

編譯運行。查看 Brent Reid 的個人資訊以便索引生效。回到 Home 螢幕,拉出 Spotlight,搜尋 brent reid。如果你先前的搜尋結果仍然存在,你只需要清除並重新搜尋。

噢,你是不是很奇怪實現的代碼太少了?

好了!現在 Spotlight 能夠如我們所想的一樣搜尋同事了。不過,似乎我們還是遺漏了點什麼…當你嘗試通過搜尋結果開啟 App 時,什麼也不會發生。

開啟搜尋結果

理想的使用者體驗是直接開啟 App 並顯示相關的內容。事實上——這個是一個要求——蘋果會將能夠啟動並顯示有用的資訊的App的排在搜尋結果的前列。

通過將一個 activityType 和一個 userInfo 對象賦給 NSUserActivity 對象,你已經在上一節中為後續的工作做了鋪墊。

開啟 AppDelegate.swift,在application(_:didFinishLaunchingWithOptions:) 方法下面,添加
一個application(_:continueUserActivity:restorationHandler:) 方法:

func application(application: UIApplication,  continueUserActivity userActivity: NSUserActivity,  restorationHandler: ([AnyObject]?) -> Void) -> Bool {  return true}

當使用者選擇了一個搜尋結果時,這個方法會被調用——這個方法也會被Handoff 用來接收其他裝置傳來的活動。

在這個方法返回 true 之前,加入以下語句:

guard userActivity.activityType == Employee.domainIdentifier,  let objectId = userActivity.userInfo?["id"] as? String else {    return false}

guard 語句檢查 activityType 是否是我們希望的類型(用於處理 Employee 的活動),然後從 userInfo 中擷取 objectId。如果這兩個條件中有一個不滿足則返回 false,通知系統該活動不會被處理。

接著,在 guard 語句後,將 return true 語句替換為:

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

獲得 id 之後,你的目標就是用EmployeeViewController 顯示匹配的同事資訊。

上述代碼稍微有點亂,但你可以想象一下 App 的設計。App 中有兩個 View Controller,一個是同事的列表,另一個是則顯示同事的詳細資料。上述代碼先將導航控制器的視圖控制器堆棧彈回到列表介面,然後push 一個該同事細節視窗。

如果因為某種原因視圖無法呈現,方法會返回一個false。

OK,編譯和運行!從同時列表中選擇 Cary Iowa,然後回到 Home 屏。調出 Spotlight 搜尋 Brent Reid。找到結果後,點擊它。App 會開啟,並且可以看到 Cary 的詳情介面迅速地過渡到了 Bent 的詳情介面。幹得不錯!

從搜尋索引中刪除條目

回到 App 的話題上來。想象一下,在某個狂風暴雨的一天,一個同事因為將老闆用膠帶綁在牆上而被解僱。顯然,你是無論如何都不想和這個人有任何關係了,因此你必須將他和其他離開公司的人一起從 Colleagues 的搜尋索引中刪除。

由於只是一個樣本App,你可以在 App 的索引設定關閉的前提下將整個索引刪除。

開啟EmployeeService.swift 在檔案頭部添加匯入語句:

import CoreSpotlight

找到 destoryEmployeeIndexing(),將 TODO 注釋替換為:

CSSearchableIndex  .defaultSearchableIndex()  .deleteAllSearchableItemsWithCompletionHandler { error in  if let error = error {    print("Error deleting searching employee items: \(error)")  } else {    print("Employees indexing deleted.")  }}

這個無參的方法將刪除整個App的索引資料庫。Good!

現在可以來測試一下。通過下列步驟來測試是否索引一如我們希望的那樣已被刪除:

編譯運行程式。

用 Xcode 終止程式。

在模擬器或者裝置中,開啟 設定 \ Colleagues,將 Indexing 設定為 Viewed Records。

再次開啟 App,選擇一個新的同事,讓索引生效。

回到 Home 屏,調出 Spotlight。

搜尋瀏覽過的同事,等待索引項目出現。

回到 設定 \ Colleagues,將 Indexing 設定為關。

退出 App。

重新開啟 App。這將清除搜尋索引。

回到 Home 屏,調出 Spotlight。

搜尋瀏覽過的同事,你會發現沒有和 Colleagues App 有關的搜尋結果。

呵呵,刪除整個搜尋索引實在太容易了。但如果你想只刪除某個單獨的記錄呢?幸運的是——有兩個 API 能夠讓你更精確地刪除想刪的記錄:

deleteSearchableItemsWithDomainIdentifiers(_:completionHandler:) 方法允許你刪除整個 domain ID 相同的一組索引。

deleteSearchableItemsWithIdentifiers(_:completionHandler:) 方法允許你通過唯一ID 指定要刪除哪條記錄。

也就是說,如果你所索引的記錄具有多種類型的話,全域識別碼 (在同一個 App 組中)必須唯一。

注意:如果你不能保證跨類型ID 是唯一的,比如你的 ID 是通過資料庫中的自增長類型獲得的,則你可以採取一種簡單辦法,即在記錄 ID 前面加上一個類型首碼。例如,如果你有一個連絡人記錄的 ID 為 123,一個訂單記錄的 ID 也是 123,則可以將它們的唯一 ID 設定為 contact.123 和 order.123。

如果你在運行過程中遇到任何問題,你可以從這裡下載到最終完成的項目。

接下來做什嗎?

這篇 iOS 9 App Search 教程介紹了在 iOS 9 中使用 User Activity 搜尋 App 內部內容的簡單但強大的方法。搜尋的內容從來不會受到限制——你可以用這種方法搜尋 App 中的導航點。

想象一下,一個 CRM App,它擁有許多視窗,比如連絡人、訂單和任務。通過 User Activity,使用者隨時可以到達這些視窗,使用者可以搜尋訂單,然後直接跳到 App 的某個訂單介面。這個功能太有用了,尤其是你的 App 有很多層級的導航時。

有許多獨特的方法將內容推給你的使用者。想突破沙箱的限制,就要教會使用者使用這個強大的功能。

這個教程是《iOS 9 by Tutorials》第2章的精簡版。如果你想學慣用 Core Spotlight 檢索大資料集,或者學習 iOS 9 的 Web Content,請閱讀這本書!


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.