Swift 程式語言

tvOS 簡介:打造你的第一支 tvOS App

tvOS 簡介:打造你的第一支 tvOS App
tvOS 簡介:打造你的第一支 tvOS App
In: Swift 程式語言, tvOS

這類的發佈通常會振奮開發者社群。隨著新版 Apple TV 的到來, Apple 也發佈了一個全新的、基於 iOS 的作業系統,叫做 tvOS 。 tvOS 基本上就是 iOS 的改進版。使用的是相同的框架,以及我們所熟悉的程式語言(沒錯,就是 Swift !),我們將透過撰寫幾個簡單的 App 來探索 tvOS 。

深入淺出 tvOS

tvOS 乃基於 iOS 。事實上,許多你使用過的框架,可能也都適用於 tvOS 。不過 Apple 也刪除了一些框架(最明顯的就是 WebKit ),所以 tvOS 仍然有別於 iOS 。

Apple 支援 2 種類型的 tvOS App 。第 1 種是傳統的 App ── 這類的 App 是由程式碼與圖片等資產所組成。基本上就跟 iOS 或 OS X App 相當。 tvOS 支援第 2 種稱為用戶端-伺服器( Client-Server )的 App 。所謂的用戶端-伺服器 App ,指的是會向伺服器發送要求,並且極度需要運用網路的 App 。換句話說,這些 App 會與自訂的資料庫或伺服器互動。舉例而言,假設你用 node.js (基於 Chrome v8 引擎的主流 JavaScript 框架)撰寫了一套後端,那麼可以考慮使用用戶端-伺服器技術來簡化 App (亦即用戶端)以及後端(亦即伺服器)的管理。用戶端-伺服器 App 可以直接透過 JavaScript 互動。不過因為這些用戶端-伺服器 App 比較複雜,本文基於簡介之目的,並不會討論用戶端-伺服器 App ,而只會強調傳統型 App 。

請記住這點,現在就讓我們開始吧。

準備工作

針對本文,我假設你對於一般的 iOS 框架、術語和網路技術已經相當嫻熟了。在本文中,我將會使用 Storyboard ,並且預期你具備使用這些技能的知識。因此,我不會花太多的篇幅來講解如何操作 Storyboard 的日常任務(例如更換背景顏色、改變元件尺寸等)。如果你不熟悉 Storyboard 或者需要重新複習 iOS 的話,那麼先去瀏覽 AppCoda 的教學文章然後再回過頭來閱讀本文會是個不錯的選擇。

你必須使用 Xcode 7.1 (稍後會說明理由)。最好能夠在 Apple TV 實機上進行測試,不過其實模擬器也很夠用了。

建立新的 tvOS 專案

為了開發 tvOS ,你必須在 Mac 上安裝 Xcode 7.1 。 Xcode 7.1 包含了 tvOS SDK ,以及 iOS 9.1 和 Swift 2.1 的支援。

開啟 Xcode ,建立新的專案,選取新的 tvOS App 。當提示視窗出現時,點擊 Single View Application 並點擊 Next 。

New Xcode Project

幫 App 取個名字。因為是第一支 App ,所以我們打算以此作為本文的 Hello World App 。將專案命名為 HelloWorld ,並在準備就緒時點擊 Create 。幫此 App 選擇一個目的地。

哈囉, tvOS !

因為 tvOS 繼承自 iOS ,許多你所熟悉的 iOS 開發基礎概念也都適用於 tvOS 。

在 Main.storyboard 檔案中,加入一顆按鈕,標題命名為「 Click Me! 」,並在下方加入一個標籤,如下圖所示。

tvOS Storyboard

請留意, tvOS 的按鈕看起來跟 iOS 的不太一樣。此外,當你新增多個按鈕時, Apple 可以讓使用者在按鈕之間無縫地上下左右切換。開發者只需要在 Storyboard 上排列按鈕,即可使用這項功能(稍後將會介紹)。

就跟在操作 iOS 時一樣,我們按住 Control 鍵拖曳標籤和按鈕以便建立 IBOutlet 和 IBAction ,並且分別命名為 myLabel 和 buttonPressed 。

connecting the iboutlet

在 buttonPressed 動作中,輸入下列的程式碼:

self.myLabel.text = "Hello, World"

這行程式碼應該不必多做解釋,你應該非常熟悉了。如果不熟悉的話,容我解釋一下,上述的程式碼會在點擊時將字串「 Hello, World 」指派給標籤的 text 屬性。

在模擬器中執行此 App 。

你可能會想要使用滑鼠來點擊按鈕,但是與模擬器中的 iOS App 不同的是, Apple TV 沒有觸控螢幕,而且使用的是遙控器( Remote )。因此,點擊 Hardware > Show Apple TV Remote 或是 Command Shift R  將會出現遙控器。用用看遙控器,點擊按鈕然後等著看效果吧 ── 你的首支 tvOS App 正式誕生!

tvOS Hello World

問答測驗遊戲 App

接下來,就讓我們使用剛學會的 tvOS 知識來建構簡單的問答測驗 App 吧。形式將會非常單純(只有一個問題);此微型專案的目標是要讓你認識按鈕,以及知道如何使用遙控器來進行互動。在下一個專案中,我們將會探索更多的 tvOS 元件。

再次開啟 Xcode 並且依照前述的步驟完成設定程序。不過這次請挑選不同的專案名稱。

複製前一個專案的 Storyboard 版面。

tvOS-quiz-app-storyboard

假使不知道怎麼做的話,下列是所有使用到的元件:

  • 4 個 UIButton 元件,尺寸皆為 960 x 325
  • 1 個 UILabel 元件,尺寸為 1,400 x 120

接著透過 Storyboard (就像在設計 iOS App 時一樣)來為按鈕加入文字,並且變更其底色。

quiz-app-colored-storyboard

跟前面一樣,我們將為這些按鈕連結一些程式碼。為了簡化說明與方便理解,我們將會製作 4 個 IBAction (儘管這不算是最優雅的解決方案,不過卻是最簡單的作法)。

將這些按鈕連接到 ViewController.swift 檔案,並且分別取不同的名稱。我的作法是命名為 button0Tappedbutton1Tappedbutton2Tappedbutton3Tapped ,但是你也可以自行選擇喜好的名稱。

上圖看到的標籤將會提問美國加州的首府。提供幾個選項(以及關於美國加州首府的知識),答案是 Sacramento 。 Sacramento 的按鈕對應到 button1Pressed 動作。

根據點擊了哪顆按鈕,我們會向使用者顯示不同的訊息,讓他們知道自己是否答對了。現在讓我們來建立名為 showAlert 的顯示通知函式,專門處理這件事,同時也讓我們的程式碼保持 DRY ( DRY 是 Don’t Repeat Yourself 的縮寫,是軟體工程中常見的實務;讓程式碼保持 DRY ,可以確保程式碼能夠被重複使用而且容易維護)。

 func showAlert(status: String, title:String) { // 1
        let alertController = UIAlertController(title: status, message: title, preferredStyle: .Alert) // 2
        let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in //3 
        }
        alertController.addAction(cancelAction)
        
        let ok = UIAlertAction(title: "OK", style: .Default) { (action) in
        } // 4
        alertController.addAction(ok)
        
        self.presentViewController(alertController, animated: true) { // 5
        }
    }

上述的函式接受 2 個參數,一個是使用者輸入的狀態(答對或答錯),另一個則是要填入顯示訊息中的內容或標題。

第 2 行會建立並初始化新的 UIAlertController 物件。第 3 行與第 4 行分別加入了取消( Cancel )與確定( Ok )按鈕,第 5 行才會把通知的訊息顯示出來。

假使不清楚這段程式碼是如何運作的,我強烈建議可以閱讀UIAlertController 教學文章,裡頭介紹了許多有關此類別的細節。

現在,在不同的 IBAction 底下,都可以呼叫此函式。

    @IBAction func button0Tapped(sender: AnyObject) {
        showAlert("Wrong!", title: "Bummer, you got it wrong!")
    }
    @IBAction func button1Tapped(sender: AnyObject) {
        showAlert("Correct!", title: "Whoo! That is the correct response")
    }
    @IBAction func button2Tapped(sender: AnyObject) {
        showAlert("Wrong!", title: "Bummer, you got it wrong!")
    }
    @IBAction func button3Tapped(sender: AnyObject) {
        showAlert("Wrong!", title: "Bummer, you got it wrong!")
    }

如你所見,正確的標題只會傳入 button1Tapped 函式當中,而其他的函式都會指出答錯了。

你可以對照看看,程式碼應該如下所示。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func button0Tapped(sender: AnyObject) {
        showAlert("Wrong!", title: "Bummer, you got it wrong!")
    }
    @IBAction func button1Tapped(sender: AnyObject) {
        showAlert("Correct!", title: "Whoo! That is the correct response")
    }
    @IBAction func button2Tapped(sender: AnyObject) {
        showAlert("Wrong!", title: "Bummer, you got it wrong!")
    }
    @IBAction func button3Tapped(sender: AnyObject) {
        showAlert("Wrong!", title: "Bummer, you got it wrong!")
    }
    
    func showAlert(status: String, title:String) {
        let alertController = UIAlertController(title: status, message: title, preferredStyle: .Alert)
        
        let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
        
        }
        alertController.addAction(cancelAction)
        
        let ok = UIAlertAction(title: "OK", style: .Default) { (action) in
        }
        alertController.addAction(ok)
        
        self.presentViewController(alertController, animated: true) {
        }
    }
}

在模擬器中執行此 App 。假使一切順利的話,應該可以看到如下所示的截圖畫面。

點擊遙控器,選取 Cupertino 。

Screen Shot 2015-11-01 at 12.49.37 AM

應該會看到有個 UIAlertController 通知彈跳出來。

Screen Shot 2015-11-01 at 12.49.27 AM

可惜的是,模擬器無法妥善地支援焦點的切換,所以你可能需要在實機上測試,才能夠看見成功通知。不過你也可以在模擬器中透過按住 option 鈕來進行切換。在 Apple TV 實機上,你可以在所有按鈕之間無縫地進行切換。

success-title

恭喜!你剛才已經完成了第 2 個專案。

在 tvOS 中使用表格視圖

如同你對於 iOS 的認知,表格視圖是 Apple 作業系統中很常見的元件。事實上, Apple 在本身的 App 當中也經常使用(包括訊息和聯絡人等)。在發表 watchOS SDK 時,同樣可以在 Apple Watch 當中看到表格視圖的蹤跡。於是新的 Apple TV 和 tvOS 自然也會加入一些 API 來支援這項主流的元件。

現在讓我們來建立另一個 Xcode 專案,請完成設定的部分,並且將專案命名為 TableViewPractice 。

跟前面的那 2 個專案一樣, Xcode 會自動產生 ViewController.swift 檔案。在第 11 行加入下列的程式碼,就在 UIViewController 之後、大括號之前。

UITableViewDataSource, UITableViewDelegate

第 11 行應該如下所示。

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

因為 Swift 是安全語言,所以你會收到錯誤指出此 App 並未指派 UITableView 資料來源與委派。我們稍後就會修正這個部分。

接著在 Storyboard 中加入一個表格視圖並且按住 Control 將之拖曳到類別。命名為 tableView 。在 tableView IBOutlet 的下方,加入下列的陣列。

var dataArray = ["San Francisco", "San Diego", "Los Angeles", "San Jose", "Mountain View", "Sacramento"]

此陣列包含了要在表格視圖中顯示的所有元素。

現在在 viewDidLoad 函式中加入下列的程式碼。

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.dataArray.count
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .Subtitle, reuseIdentifier: nil)
        
        cell.textLabel?.text = "\(self.dataArray[indexPath.row])"
        cell.detailTextLabel?.text = "Hello from sub title \(indexPath.row + 1)"
        
        return cell
    }

如你所見, tvOS 中的表格視圖跟 iOS 版本的非常類似。在上述的程式碼片段當中,我們告訴表格視圖有多少列、多少段,以及如何呈現儲存格。

在 viewDidLoad 函式中,將委派和資料來源設定為 self 。

self.tableView.dataSource = self
self.tableView.delegate = self

在模擬器中執行此 App 。

你應該可以見到熟悉的表格視圖。

tvOS-tableView

現在讓我們在表格視圖的右邊加入一顆 UIButton 。在模擬器或實機上建置並執行。哇!現在我們已經完成按鈕和表格視圖了,可以在兩者之間切換。

建立天氣 App

在接下來的微型專案中,我們將開發簡單的天氣 App ,用來顯示目前的氣象預報。針對此專案,我們將會使用 forecast.io 這套超好用的天氣 API ,包括 Dark Sky 在內的許多流行的 iOS App 都有介接這套 API 。

到 developer.forecast.io 建立開發者帳號。因為我們只是想要測試而已,所以免費版的 API 呼叫(每天最多 1,000 次)應該已經足夠。

請注意看下列的網址:
https://api.forecast.io/forecast/d3250bf407f0579c8355cd39cdd4f9e1/37.7833,122.4167

緊接在 forecast 斜線後面的是 API 金鑰(除了你自己的專案使用之外,請不要提供給其他人使用,以免超過每日的 API 呼叫次數限額)。在 API 金鑰後面的是想要得知其天氣資料的位置的緯度和經度座標。我選擇的是 San Francisco (舊金山),不過你也可以將這些座標修改成其他位置。

假使你瀏覽上述的網址,會發現其格式為 JSON 。這種形式稱為 GET 要求。在 HTTP 的世界中, GET 會擷取並下載資料。

為了消化這些 JSON 資料並且顯示在 App 中,我們需要剖析其內容。剖析 JSON 在 Swift 中是個經常被討論的議題。現存已有許多不同的 JSON 剖析程式庫,諸如 SwiftyJSON 、 Alamofire 等。每套都很好用,我建議你稍後可以嘗試使用看看。不過就本文而言,我們將會使用 NSJSONSerialization 這套 iOS 內建的類別。讓我們從開啟 ViewController.swift 開始。由於在此專案中並不需要使用到 didRecieveMemory 警告函式,因此予以刪除。

現在,在 ViewDidLoad 底下輸入下列程式碼

if let url = NSURL(string: "https://api.forecast.io/forecast/d3250bf407f0579c8355cd39cdd4f9e1/37.7833,122.4167") { }

在此我們使用 optional 來宣告 url 變數,並指派了氣象預報的網址。

NSJSONSerialization 能夠剖析的是 NSData 資料。

if let data = NSData(contentsOfURL: url){ }

接著,在資料變數的大括號內輸入下列的程式碼。

do {
      let parsed = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) // 1
                    
     let newDict = parsed as? NSDictionary // 2
     print(newDict!["currently"]!["summary"])
   }
catch let error as NSError {
     print("A JSON parsing error occurred, here are the details:\n \(error)") // 3
}

我們在 do catch 陳述式中封裝此 NSJSONSerialization 物件。假使你並不熟悉 do 陳述式,容我告訴你,這是 Swift 2 的新功能。 do catch 陳述式乃是改良過的錯誤處理新方法。 do catch 陳述式的一般使用情境如下所示。

do {
    try expression // 非必要
    statements
} catch pattern 1 {
    statements
} catch pattern 2 where condition {
    statements
}

在上述程式碼的第 1 行中,我們設定了 NSJSONSerialization 物件並且傳入 data 物件。不過此物件必須轉換成 NSDictionary 才能夠加以剖析。

因此,在第 2 行中,我們指派了名為 newDict 的新變數,並且使用 as 關鍵字將之轉換成 NSDictionary 。

最後,在第 3 行中,我們使用 catch 捕捉任何可能的錯誤,並將錯誤訊息列印在主控台中。

完整的 ViewController 檔案看起來應該會跟我的版本很類似,示範如下。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let url = NSURL(string: "https://api.forecast.io/forecast/d3250bf407f0579c8355cd39cdd4f9e1/37.7833,122.4167") {
            if let data = NSData(contentsOfURL: url){
                do {
                    let parsed = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
                    
                    let newDict = parsed as? NSDictionary
                    print(newDict!["currently"]!["summary"])
                }
                catch let error as NSError {
                    print("A JSON parsithng error occurred, here are the details:\n \(error)")
                }
            }
        }
    }
}

檢查主控台。應該會在 optional 內看到一個數值(你的數值可能會因為位置與天氣而稍有不同)。

Screen Shot 2015-11-01 at 11.21.02 AM

現在,讓我們來為此 App 連結一些 UILabel 。請製作 2 個 UILabel ,一個叫做 currentTemp ,另外一個叫做 currentSummary 。檢視氣象預報 API ,你會發現傳回的是目前天氣的溫度以及概況(當然還有其他的資料)。

tvOS-weather-label

在 newDict 底下,插入下列的程式碼。

self.currentTemp.text = "\(newDict!["currently"]!["temperature"]!!)"
self.currentSummary.text = "\(newDict!["currently"]!["summary"]!!)"

這麼做將會擷取天氣資料,並且適當地顯示出來。每一行結尾的 2 個驚嘆號( !! )會強制展開已剖析的 JSON (否則的話,將會被 optional 字樣封裝起來)。

在模擬器上建置並執行此 App (你的數值可能會因為當日天氣而稍有不同)。

tvOS Weather Forecast final

太棒了!你已經完成天氣專案了!

其他 tvOS 功能

我們已經初探了 tvOS 的面紗。現在你已經知道, tvOS 是建構在不同的 iOS API 基礎之上。不過 tvOS 也刪除了其中一些框架。如果想要了解完整的清單,可以參閱這篇文章

除此之外, tvOS 採用的是焦點事件的架構(按鈕、儲存格、標籤等都會因為獲得焦點而反白)。幸運的是,系統會自動處理大部分的焦點事件。只要使用 Storyboard ,應該就會自動處理焦點。不過在 Google 上也可以找到一些焦點 API 。

如同本文開頭時曾經提到過的, Apple 支援用戶端-伺服器 App 。這類型的 App 使用的是基於主流網頁技術( HTML 和 JavaScript 等)的 TVML 、 TVJS 和 TVMLKit 。

在建構 tvOS App 時,必須考慮的頭號挑戰就是其 SDK 並不支援永久儲存( Persistent Storage )。這點截然不同於 iOS ,因為圖片等資產的大小就沒有辦法超過 1MB 了。因此必須利用諸如 CloudKit 、 Parse 和 iCloud 等後端服務。同時我們也建議你可以研究 tvOS 的隨選資源( On Demand Resources ,請參閱我之前的App 瘦身文章)。此外, App 的大小被限制在 200MB 以內。

很顯然地, tvOS App 存在了許多現實的限制,在設計時必須詳加考慮。

結語

在本文中,我們初步體驗了 tvOS 及其功能。透過 4 個範例專案,我們探索了 tvOS 的威力及其限制。 tvOS 與 iOS 有許多相似之處,但是也刪除了不少 iOS 框架。

完整的專案檔案可以從這裡下載。

在第 1 號專案中,我們撰寫了 Hello World App ,接著在第 2 號專案中實作了簡單的問答測驗 App (讓讀者們知道焦點引擎的存在)。第 3 號專案展示了如何在 tvOS 中使用表格視圖。最後,我們在第 4 號專案中融合了所有的知識,建構出能夠從網際網路下載氣象資料的簡單天氣 App 。

Apple tvOS 的 App Store 甫於不久前開張,允許全球的開發者分享自己的作品。

同樣需要審核通過才能夠上架,不過我感受到 tvOS 以及新的 Apple TV 具備了永遠改變電視生態的潛力!

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

原文Introduction to tvOS: Building Your First tvOS App

作者
Gregg Mojica
軟體工程師及Gradology公司的資訊科技總監。在繁忙的工作以外,他享受於寫作、攝影和分享所見所聞。Gregg熱衷程式開發,曾在app store發佈數個apps,客戶包括美國康奈爾大學、各式地方企業和初創公司。可以在推特或LinkedIn聯絡Gregg。
評論
更多來自 AppCoda 中文版
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。