使用 YouTube API 打造影音搜尋 App

大家都知道 Google 提供了許多數位產品和服務,用來滿足各式各樣的使用者需求。不過除了使用 Google 本身所提供的服務之外,人們(開發者)也會想要透過別種方式來存取這些服務。 Google 確實針對開發者提供了許多的協助,包括允許他們建立各種跨平台的應用程式,因為 Google 提供了許多不同使用方式的應用程式協定介面( Application Protocol Interface, API ),同時也針對不同的程式設計語言準備了所需的程式庫和 SDK 。


因為 Google API 和服務也能夠運用於行動平台,所以我們當然不能放過這個好好研究一番的機會,而且事實上,我們在過去也曾處理過 Google 技術。舉例而言,這篇文章講的是 Google Maps SDK 。而在本文中,我們將首度揭露 YouTube API 這項全然不同的服務。

YouTube API 非常容易使用,不過有些事情你最好先知道一下,否則使用起來可能會感覺卡卡的。請容我給你一點提示:我們將不會使用任何 SDK 或者 iOS 本身的程式庫。相反地,我們只會送出簡單的 HTTP 要求(其實就是 GET 要求),向 Google 擷取資料。結果會是 JSON 格式,所以你最好先知道一下 JSON 格式的資料如何編碼。你不必是 JSON 專家;只需要了解其格式即可。如果需要協助的話,可以在這裡找到一些有用的資訊。

Google 關於 YouTube API 的文件數量龐大,所以本文的目標是將收集自不同網頁的資訊集合在一起,並協助你快速且容易地使用這些 API 。雖然我們只會介紹一小部分的 YouTube API ,但是你學到的知識將可以幫助你理解其餘的部分。不過在繼續往下閱讀之前,我必須先提醒你幾件事。

如前所述,我們會向 YouTube API 送出 HTTP 要求以便取得資料。這些要求會觸發執行特定的函式,實際上代表的是特定的 API 任務。舉例而言, channels.list 函式可以取得頻道( Channel )的資料。當然了,針對本文所要探討的每個函式( HTTP 要求),我都會提供相關文件的連結。每個函式都需要一些參數和篩選器。在介紹這類函式用法的小節當中,我會說明即將使用哪些參數和篩選器,至於細節的部分,可以點擊文章中的連結以便閱讀更多的資訊。在此就不贅述 Google 文件的內容了。

針對向 Google API 發出的要求,其中有些會需要使用者授權,有些則不會。針對需要授權的那些 API ,使用的是 OAuth 2.0 協定,好讓使用者能夠安全地以 Google 帳號登入。至於不需要授權的那些 API ,只需要簡單的 API 金鑰就可以用來應付不需要授權的要求了。在本文中,我們只會處理第 2 種情況,也就是說我們並不會要求使用者登入。但是請相信我,這些議題要用單篇文章講完並不容易。

我強烈建議你可以在閱讀本文的同時,搭配一些特定的 Google 文件。如果你想要先嘗鮮一下,可以參考下列這些連結:

除了上述這些連結之外,也歡迎隨意瀏覽並且閱讀任何你感興趣的內容。先說明一下,我們即將使用的是 YouTube API v3 ,這是 Google 目前建議採用的版本。最後容我再提醒一點,我們實在無法提供所有的連結(不只上述這些連結,還有接下來將會看到的那些連結),因為 Google 文件太過廣泛了。因此我有必要將本文的內容限縮在合理的範圍之內。

好的,就讓我們開始動手吧,在本文的最後,我們將會完成一支可以用來下載頻道和影片( Video )、搜尋以及播放影片的 App 。且聽我們娓娓道來。

範例 App 簡介

我將從下載 Starter 專案開始介紹我們要在本文中開發的範例 App 。在此壓縮檔中,你可以看到介面和所需的 IBOutlet 屬性以及 IBAction 函式,還有其他必要的程式碼,所以我們只需要專注於實作 App 的邏輯就可以了。

注意:你需要使用 Xcode 7 以上版本來執行此範例程式。

在開始撰寫程式碼之前,我們必須從 Google 取得 API 金鑰,好讓我們能夠向 YouTube API 發出要求。我們需要遵循一道特定的程序,不過我現在還不打算詳細介紹;在下一節中我們才會一步一步說明。

現在讓我們先來看一下範例 App 的模樣:

youtube-api-demo

此範例 App 具備多重目標:

  • 下載(並顯示) YouTube 頻道的詳情。
  • 下載(並顯示)頻道中的影片播放清單。
  • 能夠搜尋頻道和影片。
  • 播放影片。

關於使用者介面的部分,此 App 是由 2 個視圖控制器所組成。第 1 個視圖控制器擁有 3 個子視圖:表格視圖、文字欄位、分段元件。這些子視圖的用途分述如下:

  1. 在表格視圖中,將會顯示頻道或影片的資訊。這些影片可以是頻道的播放清單,或是搜尋的結果。
  2. 文字欄位是搜尋的欄位。在此輸入的關鍵字隨後會向 YouTube 發出搜尋要求。
  3. 分段元件非常重要。當選取的是第 1 個索引時,表格視圖將會顯示頻道。此外搜尋結果也只會侷限於頻道。另一方面,當選取的是第 2 個索引(影片索引)時,表格視圖將會顯示現有的影片播放清單,而搜尋結果也只會與影片有關。

第 2 個視圖控制器是我們的播放器視圖控制器;用來播放選取的影片的串流。我們會在最後一個小節介紹這個部分。此外我們將會使用 Google 的輔助程式庫來「建立」播放器並且實現串流。

我們對於範例 App 的規劃如上所述,現在就讓我們開始來實作吧。

建立 API 金鑰

探索 YouTube API 的第一步,就從這裡開始:在 Google Developers Console 中替我們的 App 建立一筆新的記錄(新的專案),以便能夠存取 YouTube API 。事實上,在 Console 中建立完新的專案之後,還需要做 2 件事:

  1. 啟用( Enable ) YouTube API ,以便在我們的 App 中使用。
  2. 建立 API 金鑰,以便向 YouTube API 發出要求。

請留意(再度提醒),我們在本文中向 YouTube API 發出的要求並未經過授權程序,這意味著我們不會要求使用者以他們的 Google 帳號來登入我們的 App 。當然了,只是透過運用 API 金鑰,的確也限制了能夠發出的要求,如果想要完整的存取權限,則需要完整的授權。不過就本文的內容而言,我們只需要使用 API 金鑰就夠了。

現在請連結到 Developers Console 並且為我們的專案建立新的記錄。假使你目前並未登入 Google 的話,請即刻登入。必須要有 Google 帳號才能夠繼續遵循本文的步驟。登入之後看到的會是如下所示的畫面:

t39_2_console_projects

點擊左上角的藍色 Create Project (建立專案)按鈕,在彈出視窗中輸入新專案的名稱。我命名為 YTDemo ,不過你可以選擇任何你喜歡的名稱。請留意,如果你覺得已經不再需要此專案的話,最後也可以從 Console 刪除這筆記錄。

t39_3_console_project_name

下一步是啟用此專案的 YouTube API 功能。記住,你可以為同一個專案啟用多組 API ,不過此刻你還不需要使用到其他的 API 。

啟用 YouTube API 的方法是,從視窗左側的功能表中點擊 APIs & auth > APIs 選項。在主視窗區域中找到 YouTube Data API ( YouTube 資料 API )並且點擊其連結。

t39_4_console_youtube_api

瀏覽器會將你帶領到新視窗,你可以(也必須)在那裡啟用 YouTube API 。只要點擊上方的 Enable API 按鈕,一切就準備就緒了。

現在我們已經啟用完 YouTube API 了,接著必須建立我們想要使用的 API 金鑰。來到 APIs & auth > Credentials 功能表,點擊 Create new Key (建立新的金鑰)按鈕之後將會出現新視窗。在彈出視窗中,必須選取我們的專案所適用的平台。這時候我打賭你會毫不猶豫地點擊 iOS key ( iOS 金鑰)按鈕。但是請別這麼做。根據 Google 的文件, iOS 金鑰無法適用於所有的 API ,而 YouTube API 正好就是其中一組。我可以證明這點,因為基於好奇我曾嘗試著建立這樣一把金鑰,並且套用於範例 App 中,但是完全無法使用。

t39_5_console_key_options

你應該做的,其實是點擊 Browser key (瀏覽器金鑰)按鈕。在彈出視窗中,只要點擊 Create 即可,不要在欄位中輸入任何文字。接著回到帳號密碼的憑證視窗,你將會發現新的金鑰已經建立完成。如你所見,你可以套用各種動作,甚至可以刪除,但是我們現在當然還不會這麼做。花了一些時間,我們在 Developers Console 中的設定工作總算大功告成,但是還不要登出。讓瀏覽器繼續開著,因為你很快就會需要將產生的金鑰複製到 iOS App 當中。

擷取資料的機制

在產生完 API 金鑰之後,我們便可以返回 Xcode 開始處理 Starter 專案。如果仔細回想我們想要實作的目標和功能(取得頻道和影片、實現搜尋),將會意識到存在著一個共同的元素。亦即我們都必須向 Google 的伺服器發出要求( HTTP 要求),接著傳回 JSON 格式的資料。牢記這項事實,如果我們可以撰寫通用的函式來實現實際的要求以及取回資料,一定會相當方便。

沒錯,你猜對了,本節我們要做的正是這件事。更精確地說,在我們的 ViewController 類別中將會實作一個可以用來進行簡單的 GET 要求的函式。在我們的範例 App 中,我們使用的是 NSURLSessionNSURLSessionDataTask 類別。請留意,這些動作都是非同步的,因此只要一收到任何結果(或錯誤訊息),我們就必須使用主執行緒來加以剖析然後更新 UI 。相關步驟詳述如下。

首先,定義此函式:

如你所見,此函式預期我們將會提供要求的 URL 網址( NSURL 物件)。第 2 個參數是閉包( Closure ),或稱完成處理常式區塊( Completion Handler Block )。我在前面提過,實際的資料擷取動作是非同步的,當資料擷取的動作做完時,此完成處理常式便會在主執行緒中被喚起,以便執行剖析的任務。請留意,此完成處理常式需要 3 個參數:

  1. data:擷取到的資料,格式為 JSON 。
  2. HTTPStatusCode: HTTP 狀態代碼。我們希望收到的代碼是 200 (代表一切正常)。
  3. error:發生錯誤時,則會傳回錯誤訊息。

現在,讓我們進入到實作的部分:

讓我們來探討一下上述的程式碼。首先,我們利用參數裡的 URL 物件來建立 NSMutableURLRequest 物件。我們必須設定 GET 作為偏好的 HTTP 方法。這樣就組成了稍後要送出的要求。接著,初始化 NSURLSessionConfiguration 物件,並將之傳入作為初始化 NSURLSession 的參數。然後利用此 session (工作階段)實體來建立資料任務物件,此時我們提供 request (要求)作為參數。在資料任務的完成處理常式中,我們呼叫了 dispatch_async() 函式,好讓我們能夠在主執行緒中執行我們的完成處理常式。請留意我們如何從這些參數當中取得回應( NSURLResponse )的 HTTP 狀態代碼。最後,我們使用資料任務的 resume() 函式來開始擷取作業。

現在,就只差資料的剖析了,不過這件事我們稍後才會做。現在可以確定的是我們不需要擔心資料的擷取了,因為每當我們需要的時候,都可以利用上述函式來達成任務。

取得頻道資訊

我們「要求」 YouTube API 做的第一件事,就是提供一份頻道清單。說得更清楚些,我們會要求標題( Title )、簡介( Description ),以及 Apple 、 Google 和 Microsoft 的 YouTube 頻道的縮圖( Thumbnail )資料。除了這些資料之外,我們還需要一個額外的數值,也就是每個頻道上傳的影片的播放清單 ID ,好讓我們在稍後能夠向這些影片發出要求。

所有這些任務都會寫在同一個新函式裡。在此函式中,我們不只會取得單一頻道的詳情,我們的實作會按照此邏輯以遞迴方式取得所有頻道的詳情。在開始撰寫函式之前,讓我們先來宣告一些將會使用到的變數。請來到 ViewController 類別的開頭,並且加入下列這幾行:

請確定在 apiKey 變數中設定了你自己的 API 金鑰數值。在複製和貼上的時候請務必留意,因為如果有誤的話,稍後送出的要求將會失敗。

除了 API 金鑰變數之外,我們還需要另外 3 個變數:

  • desiredChannelsArray:此陣列包含了我們想要取得其資訊的頻道的名稱。
  • channelIndex:此變數用來指向 App 應該在稍後即將實作的函式中向哪個頻道發出要求。
  • channelsDataArray:此陣列將會擁有取得的頻道的資料。更精確地說,就是我們從 JSON 回應中擷取出來的資料,每個元素都是一筆頻道字典記錄。

關於我們要使用的 YouTube API 函式,說明如下。此函式是 channels.list ,相關資訊可以在 這裡找到。此要求的 URL 網址如下:

此 URL 還需要一些參數,以便指定或篩選要傳回的資料。在介紹這些參數之前,容我先說明一下,針對頻道詳情的取得,總共有 3 種呼叫 API 的方式:

  1. 指出你是頻道的擁有者。
  2. 指定擁有者的使用者名稱。
  3. 提供頻道 ID (每個頻道有各自的唯一數值)。

在上述這 3 種方法當中,我們將會使用到後面 2 種。針對這 2 種方法,我們都會使用 part 作為必要參數,用來指定要求的結果要包含哪些部分。在本例中,我們針對此參數的設定是 snippet, contentDetails (以逗號分隔數值),其中 snippet 可以為我們提供頻道的詳情(我們會在稍後加以顯示),而 contentDetails 則會傳回該頻道所擁有的上傳影片的播放清單 ID 。在基於使用者名稱來擷取頻道的情況當中,我們還會使用到 forUsername 參數,並且使用 id 參數來取得該 ID 所代表的頻道的資訊。

此刻請容我提醒一點,雖然就目前而言我們並不需要使用該 ID 來取得頻道詳情,不過稍後在搜尋頻道時還是會需要用到。此刻我只是先將這項資訊讓你知道而已。

除了要指定的參數之外,我們每次都需要使用 API 金鑰,否則要求將會失敗。

請牢記上述的說明,現在就讓我們開始來實作新函式吧。你將會看到,參數的數值指出了發出要求的偏好作法:

請留意,上述程式碼中的 else 區塊是空白的。我們稍後才會補上,此處的示範可以看到根據頻道 ID 數值所組合出來的 URL 網址:

另外也請留意,在組合完最終的 URL 字串之後,必須將之轉換成 NSURL 物件。此物件會緊接著在稍早實作過的 performGetRequest(...) 函式之後被呼叫到。

在繼續往下進行之前,請容我先為你展示使用 username 參數從 Apple 頻道傳回的 JSON 資料(若要實際測試此 API 呼叫,可以按這裡,你也可以試試看其他的要求類型):

針對上述的結果,我們關心的只有 titledescriptionsnippet 字典中的 default thumbnail ,而針對 uploads 數值,我們感興趣的只有 contentDetails > relatedPlaylists 字典。

根據上述的結果,我們可以「解碼」出每個我們想要的資料的路徑,以便完成後續的實作。為了簡化起見,我針對上述的每一行結果都在程式碼中加入了註解,方便你理解每個步驟的用途:

讓我們來看幾個重點。首先,我們檢查 HTTP 狀態代碼的數值和錯誤物件,以便確認真的有 JSON 資料存在。如果一切正常的話,我們會開始將擷取到的資料( NSData 物件)轉換成字典。接著,我們使用此字典來存取傳回來的所有項目(與頻道資料有關的字典)。通常在要求頻道的詳情資料時,只會傳回一個項目。在本例中,此項目是以 firstItemDict 表示的物件。這樣就可以很方便地取得 snippet 字典。

在存取完 snippet 字典之後,為了保存目的,我們建立了一個新的字典,因為我們需要保留那些數值。在 desiredValuesDict 字典中,我們保存了頻道的標題、簡介和縮圖網址。請留意,我選擇使用預設的縮圖(尺寸最小的那個)。必須稍微「挖掘」一下,才能夠找到此數值。

在處理完頻道的詳情(包括標題等)之後,我們存取 uploads 數值以便取得包含所有頻道影片的播放清單 ID 。如你所見,此數值也是存放在 desiredValuesDict 字典當中。

最後,將我們自訂的字典附加到 channelsDataArray 陣列中,以便稍後能夠顯示和管理這些頻道。

上述的函式尚未實作完成,不過在繼續往下討論之前,容我先介紹即將用來擷取所需數值的結構順序(我們稱之為「路徑」):

要存取 snippet 字典,使用:
從 JSON 轉換而來的字典 > “items” 陣列 > 第一個項目字典 > “snippet” 字典

要存取頻道的縮圖網址,使用:
從 JSON 轉換而來的字典 > “items” 陣列 > 第一個項目字典 > “snippet” 字典 > “thumbnails” 字典 > “default” 字典 > “url” 數值

要存取播放清單 ID ,使用:
從 JSON 轉換而來的字典 > “items” 陣列 > 第一個項目字典 > “contentDetails” 字典 > “relatedPlaylists” 字典 > “uploads” 數值

如你所見,必須深入到 JSON 結果底層的字典和陣列當中,不過這一點也不困難,而且 Google 提供的範例結果也很清楚易懂,對於學習非常有幫助。

現在讓我們開始來實作缺漏的部分吧。接下來要做的,是在頻道資料新增到 channelsDataArray 陣列之後,重新載入表格視圖(雖然我們要到下一節才會實作顯示資料的功能),並且繼續擷取下一個頻道(當然是指如果還有的話)。

self.viewWait.hidden = true 可以確保在擷取完所有的頻道之後,活動指示器和透明視圖會從螢幕上消失。

最後,我們要處理的是 HTTP 狀態代碼不是 200 或是遭遇錯誤的情況。無論是哪一種情況,我們都只會在主控台上顯示一段訊息,不會再做進一步的處理:

我們的新函式已經準備就緒了。只需要加以呼叫即可,我們打算在 viewDidLoad 函式中這麼做:

透過檢視 getChannelDetails(...) 函式,最終你將發現,我們做的事情其實一點也不複雜。我們只是處理傳回的資料,並且將我們感興趣的部分儲存起來。在接下來的小節中,我們還會實作幾個也很類似的函式;當我們要取得頻道的影片,以及當我們在實作搜尋功能的時候。不過那一點也不麻煩,因為你已經受過剛剛那陣呼叫 YouTube API 的「洗禮」了。

顯示頻道

如同前面說明過的,在 ViewController 類別中的分段元件扮演了很重要的角色,實際上我們就是透過它來決定要在表格視圖中顯示哪種資料。當選取的是名為 Channels (頻道)的第 1 個索引時,顯示的應該會是對應的頻道詳情,相反地,如果選取的是影片索引,則會在表格視圖中顯示影片的詳情。此刻就應該考慮這個部分,因為我們現在就必須依照條件在表格視圖中顯示擷取的頻道資料。

好了,首先我們要指定的是表格視圖的資料列數目:

如你所見,要決定搭配的資料來源非常簡單,只需要根據 segDisplayedContent 分段元件的 selectedSegmentIndex 屬性。我們便可以據此在表格視圖中顯示對應的儲存格資料:

如果檢視 Interface Builder 中的 View Controller 場景,將會注意到頻道的原型儲存格包含了 3 個子視圖,並且分別被指派了特定的 tag (標記)數值:

  1. 頻道標題是 UILabel ,其 tag 數值為 10
  2. 頻道簡介是 UILabel ,其 tag 數值為 11
  3. 頻道縮圖是 UIImageView ,其 tag 數值為 12

t39_6_channel_prototype_cell

我們首先要做的是從每個儲存格中將這些子視圖「抽取」出來,以便將擷取到的資料填進去。示範如下:

接著,我們取得每個頻道的詳情,並且指派給這些子視圖:

現在你可以嘗試首次執行此 App 。如果你有遵循剛才所介紹的每個步驟,也設定了自己的 API 金鑰,那麼應該可以在表格視圖中看到 3 個頻道。

t39_1_channel_sample

擷取影片

範例 App 的第一項功能現在運作正常,接下來繼續實作第二項。這次我們想要擷取所選頻道的影片,並且條列在表格視圖中(我們將在下一個小節中實作此部分)。整個程序顯然會在頻道被點擊時才展開,這也正是我們實作的起點。

一如往常,我們需要在類別的開頭宣告新的變數:

如同你所猜測的,我們會在剖析之後,在 videosArray 陣列中存放影片的詳情。請留意,陣列在宣告的同時也一併進行了初始化。

現在,讓我們來處理頻道儲存格的點擊事件:

上述的註解可以幫助你理解整個流程。因為我們要顯示的是影片,所以首先將選取的分段元件索引變更為適當的數值。接著,我們顯示包含活動指示器的 viewWait 視圖。不容忽視的一個重要步驟就是要將 videosArray 陣列中的舊內容清除乾淨。當然了,此 App 首次執行時此陣列一定是空白的,但是後續的影片要求就不能夠缺少這行程式碼了。最後,我們呼叫了 getVideosForChannelAtIndex(...) 函式,也就是我們在此想要實現的功能。但是此函式尚不存在,所以我們稍後將會實作。請留意,我們會將選取的儲存格的索引以參數形式傳遞進去。

這回我們將會使用到 YouTube API 的 playlistItem.list 函式,相關的文件可以參考這裡。我們會在此 GET 要求中輸入 3 個參數;其中一個顯然就是 API 金鑰。除此之外,我們還需要設定必要的 part 參數搭配 snippet 數值,以便取得所需的影片詳情,以及包含這些影片的播放清單的 ID 。此參數叫做 playlistID 。針對所擷取的頻道,我們已經取得其播放清單的 ID 數值,接著便可以加以使用。假使你想要觀看實際使用該要求的範例,可以造訪這個網頁(確定 part 參數只有設定 snippet 數值)。

我們將開始實作此新函式,首先我們會取得所選頻道的播放清單 ID 。接著我們會指定剛才提過的參數,以便產生正確的 URL 字串,接著我們會建立 NSURL 物件,以便發出要求:

跟你想像的一樣,頻道的播放清單應該會包含許多部影片,不過在本文中,我們並不需要取得所有的影片。我們只需要取得一部影片就夠了。不過在本例中,我們並不需要明確地限制結果,因為 YouTube API 預設一次只會傳回 5 筆結果。

下列是傳回的 JSON 結果的範例。跟之前看過的一樣,這份結果有助於明確地指引我們應該存取哪些數值:

針對影片項目,在傳回的所有數值中,我們只需要保留 titledefault thumbnailvideoID 數值。我們稍後將會使用 videoID 來播放影片串流。

程式碼如下所示:

我們用來「抽取」所需數值的邏輯,跟之前剖析頻道時的很類似,所以在此就不贅述了。背後的概念非常簡單;我們根據的是範例結果,並據此修改我們的程式碼。

請留意,一旦關於影片的資料被新增到陣列之後,我們便必須重新載入表格視圖以便更新 UI 。

最後,讓我們幫此函式收尾:

我們只會顯示 HTTP 狀態代碼,以及任何遭遇的錯誤(例如沒有可以剖析的資料),並再次隱藏 viewWait 視圖。

顯示影片

現在要做是將擷取到的影片清單顯示出來,動作同樣非常簡單,就跟我們在顯示頻道時做過的一樣,只要把對應的項目呈現出來就可以了。那麼,首先我們必須指定表格視圖的資料列數目:

資料列數目顯然必須與 videosArray 陣列中存在的影片字典數目相符。

接著,讓我們來處理儲存格的部分,我們將首次使用 tag 數值來存取儲存格的個別子視圖,然後替它們設定影片的標題和縮圖。相較之下,頻道只有一個用來顯示影片標題的標籤物件,而沒有簡介標籤。此外還有用來顯示影片縮圖的影像視圖;同樣地,我們會使用剖析出來的 URL 數值從網際網路即時取得縮圖。

現在範例 App 已經能夠下載和顯示所選頻道的影片清單,如果有興趣的話,你也可以實際嘗試看看。不過現在最應該做的,是再幫 App 完成另外一項功能:可以透過分段元件來切換頻道和影片。在 ViewController 類別中,原本就定義了一個名為 changeContent(...) 的 IBAction 函式。每次當你選取不同的區段時都會觸發此函式,其程式碼如下所示:

上述這行將會以淡入淡出的方式來重新載入表格視圖的資料。當分段元件的索引改變時,將會自動選取正確的資料來源,並將正確的內容顯示到表格視圖中。

下圖是 Apple 頻道的影片清單截圖:

youtube-api-videos

搜尋頻道與影片

使用者最常使用到的關鍵功能,就是內容的搜尋,無論是 Google 的哪一款產品或 API ,皆致力於實現搜尋的功能。基於這項事實,我深深感覺到如果不能夠加入利用 YouTube API 來進行搜尋的功能,我們的範例 App 似乎就少了點什麼,所以接下來就讓我們來補齊這個部分吧。一般而言,在 YouTube 中,使用者可以搜尋影片、頻道和播放清單。在本文中,我們只會啟用前 2 項的搜尋功能。

說得更明白一些,我們不會同時搜尋頻道與影片。搜尋的類型( Type )將視所選的分段元件索引而定。也就是說,如果選取的是頻道,那麼我們的「搜尋引擎」將會預設傳回頻道結果。相反地,如果選取的是影片,則會傳回影片結果。

在下載的 Starter 專案中,我已經將 ViewController 類別設定為文字欄位(我們的搜尋欄位)的委派,並且定義了 textFieldShouldReturn(...) 委派函式。此刻我們將著手實作此函式,並從 2 件事情開始:隱藏鍵盤,以及根據分段元件的選取索引來決定搜尋類型。程式碼示範如下:

我們要使用的 YouTube API 函式是 search.list ,相關文件在這裡。在我們送出的 GET 要求中,除了 API 金鑰之外,還有 3 個額外參數。第 1 個必要的參數是 part ,其值必須指派為 snippet (以便取得結果項目的詳情)。第 2 個參數是 type ,我們將指派為前面所指定的頻道或影片數值,以便傳回正確的結果。第3 個、同時也是最重要的參數是 q ,也就是實際的搜尋字串(換言之,也就是文字欄位的內容)。缺少了第 3 個參數,便無法實現搜尋功能。

現在讓我們來準備要求的 URL 網址。這回我們增加了一些新的東西,也是我們頭一次實際將要求進行 URL 編碼。這麼做是必要的,好讓所有的特殊字元或空格都被正確置換成百分比逸出字元(例如以 %20 來取代空格字元)。

下一步便是發出要求。初始的步驟都非常簡單,亦即取得 JSON 資料並且轉換成字典。接著取得所有的搜尋結果項目,最後建立迴圈逐一處理。

上述程式碼並無特別困難之處,所以我們只要先關注頻道結果即可。在本例中,對於結果的處理非常單純,因為我們只需要取得個別頻道的 ID 並將之附加到 desiredChannelsArray 陣列當中。如果你還有印象的話,我們一開始便在此陣列中加入過 Apple 、 Google 和 Microsoft 等頻道名稱了。此外,我們建立了 getChannelDetails(...) 函式,負責存取 API 並且擷取關於頻道的詳細資料。在實作的時候,我們曾經提到,要求可以基於頻道擁有者的使用者名稱,或是頻道本身的 ID ;除此之外,我們也會加上實現此功能的邏輯,並且留待稍後(也就是現在)在使用頻道 ID 來建立要求 URL 字串時再做說明。

所以現在就讓我們將 getChannelDetails(...) 函式缺漏的部分補齊吧。只需要加入下列的 else 分支:

現在讓我們來探討搜尋結果的剖析,並且在 desiredChannelsArray 陣列中加入擷取到的頻道 ID 。請留意,除了這些動作之外,在 for 迴圈之後立即呼叫了 getChannelDetails(...) 函式,並且傳入 true 數值作為參數,指示必須根據頻道 ID 來產生該要求:

在完成上述的步驟之後,便準備好可以搜尋頻道了。搜尋所傳回的任何新頻道,都將被新增到表格視圖中既有的項目之後。請留意,在預設的情況下,每次要求只會傳回 5 筆結果,這樣對我們而言就夠了,我們也省得設定任何限制或篩選器。

t39_8_search_channels_sample

現在讓我們來處理影片搜尋的結果。在本例中,我們將會建立新的字典,用來存放標題、縮圖 URL 和影片的 ID 。接著,此字典會被附加到 videosArray 陣列當中,並且重新整理表格視圖:

現在,我們只差還沒有加入錯誤處理以及隱藏 viewWait 視圖的程式碼而已了。

讓我們再度嘗試執行此 App ,這回要測試的是影片搜尋的功能。

t39_9_search_videos_sample

播放影片

在 iOS App 中播放 YouTube 影片非常容易,因為 Google 提供了能夠用來嵌入播放器並且接收影片內容串流的輔助( Helper )程式庫。此輔助類別會建立內嵌 iframe 的特殊網頁視圖,使得整合變得非常容易。你可以在這裡找到對應的文件。

針對 iOS ,此程式庫是以 Objective-C 撰寫而成,所以要在 Swift App 中使用的話,必須建立所需的表頭橋接檔案。為了方便說明並且節省時間起見,我已經在下載的 Starter 專案建立好此檔案,同時也加入了程式庫的必要檔案。說得更清楚一些,針對專案中的影片輔助程式庫,你會看到有下列這些東西:

  1. 名為 Assets 的群組
  2. YTPlayerView.h 檔案
  3. YTPlayerView.m 檔案

除此之外,在 Interface Builder 的 Player View Controller 場景中,我加入了一個視圖物件作為子視圖。此視圖的類別已設定為 YTPlayerView ,至此所有的初始步驟便大功告成。現在,我們只需要撰寫少許的程式碼,讓播放器能夠顯示 YouTube 影片的串流即可。

假使你還記得的話,在擷取和剖析影片資料期間,我們只儲存了特定的數值。其中之一便是 video ID ,而現在正是拿來使用的時刻。我們會將此數值提供給 YTPlayerView ,然後我們的專案也就差不多完成了。就讓我們從在 ViewController 類別中點擊影片儲存格開始。當此動作發生時,將會完成 2 項任務:首先,從 videosArray 陣列中取得正確的影片 ID ,接著載入 PlayerViewController 視圖控制器。與此同時,其 Segue 也蓄勢待發,我們會將影片 ID 傳遞給下一個視圖控制器。

再度回到動作函式,首先來到 ViewController 類別的開頭,並且宣告如下的變數(最後一個了):

接著,更新下列的表格視圖委派函式:

看吧,一點都不難,我們只需要記住點擊資料列的索引,然後執行 Segue 。現在讓我們來檢視 Segue 的準備程式碼,實際上我們是存取影片 ID 並將之傳遞給 PlayerViewController 類別。

如果 Xcode 顯示錯誤的話請勿驚慌。那是因為 videoID 屬性尚未存在於 PlayerViewController 類別當中,不過我們現在就會立刻來修正此問題。

開啟 PlayerViewController 類別,並且加入下列的宣告:

最後,在 viewDidLoad 中呼叫 YTPlayerView 類別的函式:

我們準備好了。現在可以執行此 App ,選擇並觀賞任何你喜歡的影片。你應該也注意到了,播放器允許全螢幕,此外也可以執行一些其他動作。

結語

要使用 YouTube API 一點也不難,只需要找到 Google 所提供的正確資源和文件。針對每個要求,都有詳細的文件和範例能夠引導你完成實作,讓你能夠按照最正確的方式來取得和處理資料。如同我在引言當中所說的,在本文中我們所發出的要求只會需要用到簡單的 API 金鑰,無須執行使用者授權程序。但是有很多情況是需要使用者在執行特定動作(例如上傳影片)之前先完成登入。如你所知,我們無法只用單篇文章來涵蓋所有這些主題,不過你在本文的所學已經足以讓你開始使用 YouTube API 了。你當然也可以運用類似於前面幾個小節所介紹的方法來使用其他的 API ,所以請你挑一組喜歡的 API 盡情嘗試吧!

供你參考,請從 Github 下載本文的完整 Xcode 專案。

譯者簡介:陳佳新 – 奇步應用共同創辦人,開發自有 App 和網站之外,也承包各式案件。譯有多本電腦書籍,包括 O’Reilly 出版的 iOS 、 Android 、 Agile 和 Google Cloud 等主題,也在報紙上寫過小說。現與妻兒居住在故鄉彰化。歡迎造訪 https://chibuapp.com ,來信請寄到 jarsing@chibuapp.com 。

原文Building a Video Search App with YouTube API


資深軟體開發員,從事相關工作超過二十年,專門在不同的平台和各種程式語言去解決軟體開發問題。自2010年中,Gabriel專注在iOS程式的開發,利用教程與世界上每個角落的人分享知識。可以在Google+或推特關注 Gabriel。

blog comments powered by Disqus
訂閲電子報

訂閲電子報

AppCoda致力於發佈優質iOS程式教學,你不必每天上站,輸入你的電子郵件地址訂閱網站的最新教學文章。每當有新文章發佈,我們會使用電子郵件通知你。

已收你的指示。請你檢查你的電郵,我們已寄出一封認證信,點擊信中鏈結才算完成訂閱。

Shares
Share This