作者:Jameson Quave,原文鏈接,原文日期:2015/09/09
譯者:ray16897188;校對(duì):numbbbbb;定稿:shanks
教程結(jié)束時(shí),我們會(huì)做出這樣一個(gè)應(yīng)用:

開(kāi)始
在我們開(kāi)始之前你需要安裝 Xcode 7.1 beta 版,可以從這里下載:下載Xcode 7.1 Beta
注意:你需要準(zhǔn)備一個(gè) Apple 開(kāi)發(fā)者賬號(hào),而且由于目前是預(yù)覽版,以后代碼也可能發(fā)生變化。
安裝的時(shí)候要注意,如果你重命名 Xcode 7.1 應(yīng)用,會(huì)遇到一個(gè)已知 bug。一定有人會(huì)這么做,所以提前說(shuō)明……別這么做,否則你的 tvOS 模擬器會(huì)崩潰。
還要注意,如果系統(tǒng)是 Yosemite,性能會(huì)有限制。推薦用 OSX 10.11 El Capitan 或更新的系統(tǒng)。El Capitan beta 可以在這里下載。
下面我們來(lái)學(xué)習(xí)一些 tvOS 的名詞。
TVMLKit
TVMLKit 是 Apple 設(shè)計(jì)的一個(gè)新框架,能在使用 Swift 或 Objective-C 實(shí)現(xiàn)應(yīng)用邏輯的同時(shí)使用 Javascript 和 XML 開(kāi)發(fā)更炫酷的用戶界面。
TVML
TVML 是"TV Markup Language"(TV 標(biāo)記語(yǔ)言)的縮寫(xiě),基本上是一些 XML 語(yǔ)句,用于實(shí)現(xiàn)基于C/S(client-server,客戶端-服務(wù)端)架構(gòu)的 tvOS 應(yīng)用布局。布局界面時(shí),我們會(huì)用到一些 Apple 提供的 TVML 模板創(chuàng)建我們的 UI,然后用 TVJS 寫(xiě)交互腳本。
TVJS
我能告訴你的是,TVJS 就是你(可能已經(jīng))熟悉的 JavaScript。
Hello World
我們從一個(gè)基本的 hello world 程序開(kāi)始。就 Apple TV 而言,我們可以只把"Hello World"輸出到主機(jī)上。這也許是個(gè)不錯(cuò)的開(kāi)始,但更好的選擇是使用 Apple TV 的一些 TVMLKit 元素在屏幕上創(chuàng)建一個(gè)模板。
首先,打開(kāi) Xcode 7.1 并創(chuàng)建一個(gè)新項(xiàng)目。你可以看到一個(gè)模板列表,我們?cè)谧髠?cè)選擇CHANGE tvOS,然后再選Single View Application模板。
這樣就會(huì)根據(jù) tvOS 模板創(chuàng)建一些默認(rèn)文件和一個(gè)簡(jiǎn)單的 Swift 入口點(diǎn),對(duì)一會(huì)兒創(chuàng)建 UI 很有幫助。
建立 TVJS 主文件
在 C/S 架構(gòu)的 tvOS 應(yīng)用中,服務(wù)端本質(zhì)上就是 TVML 和 JavaScript 文件以及和它們相關(guān)的所有數(shù)據(jù)。JavaScript 文件會(huì)裝載 TVML 并把頁(yè)面(page)放入視圖棧中。可以從另一個(gè)角度理解:JavaScript 文件就像 TVML 文件的路由器或是控制器(controller),而 TVML 文件本質(zhì)上是若干視圖(views)。
拉開(kāi)序幕
首先我們要修改應(yīng)用的AppDelegate.swift文件。第一步是讓我們的應(yīng)用遵循TVApplicationControllerDelegate協(xié)議。該協(xié)議定義在 TVMLKit 框架中,所以需要導(dǎo)入它。更新AppDelegate.swift文件,如下所示:
import TVMLKit
class AppDelegate: UIResponder,
UIApplicationDelegate,
TVApplicationControllerDelegate {
....
此協(xié)議包含四個(gè) tvOS 實(shí)現(xiàn)AppDelegate后會(huì)調(diào)用的函數(shù),用于給我們的應(yīng)用發(fā)送 tvOS 生命周期通知?,F(xiàn)在我們無(wú)需操心這些,但在后面的教程中我們會(huì)對(duì)它們進(jìn)行深入研究。目前只要像上面的代碼那樣把協(xié)議加進(jìn)去就夠了。
下一步,我們要添加一些代碼,讓 JS 文件起作用。由于是 beta 版,我們還需要自己完成這些工作。我相信在 Xcode 的后續(xù)版本中這一步會(huì)變成一個(gè)模板。
在程序里didFinishLaunchingWithOptions這個(gè)函數(shù)中我們要完成一些步驟。它們對(duì)所有應(yīng)用來(lái)說(shuō)都是一樣的,所以你可以直接復(fù)制這段代碼:
// 在一個(gè)可選屬性中保存對(duì) appController 的引用
var appController: TVApplicationController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame:UIScreen.mainScreen().bounds)
let appControllerContext = TVApplicationControllerContext()
let jsFilePath = NSURL(string: "http://localhost:8000/main.js")
let javascriptURL = jsFilePath!
appControllerContext.javaScriptApplicationURL = javascriptURL
if let options = launchOptions
{
for (kind, value) in options
{
if let kindStr = kind as? String
{
appControllerContext.launchOptions[kindStr] = value
}
}
}
self.appController = TVApplicationController(context: appControllerContext, window: self.window, delegate: self)
return true
}
簡(jiǎn)單說(shuō)說(shuō)這段代碼干了什么:它拿到了一個(gè)TVApplicationControllerContext引用,這個(gè)Context只是為我們的AppDelegate類(lèi)提供了一些啟動(dòng)數(shù)據(jù),然后給了我們一個(gè)能調(diào)整和修改啟動(dòng)過(guò)程的接口。接著把 URL 傳給待會(huì)兒要運(yùn)行的main.js文件,并將appController的路徑設(shè)置成這個(gè) URL。
現(xiàn)在就要添加我們的 JavaScript 文件了,點(diǎn)擊 File > New,然后在 iOS tab 下面選擇 Other > Empty file。將這個(gè)文件命名為main.js。
用同樣方法創(chuàng)建一個(gè)hello.tvml文件。
在main.js文件中添加一些簡(jiǎn)單的 JavaScript 代碼,用來(lái)裝載hello.tvml文件:
function getDocument(url) {
var templateXHR = new XMLHttpRequest();
templateXHR.responseType = "document";
templateXHR.addEventListener("load", function() {pushDoc(templateXHR.responseXML);}, false);
templateXHR.open("GET", url, true);
templateXHR.send();
return templateXHR;
}
function pushDoc(document) {
navigationDocument.pushDocument(document);
}
App.onLaunch = function(options) {
var templateURL = 'http://localhost:8000/hello.tvml';
getDocument(templateURL);
}
App.onExit = function() {
console.log('App finished');
}
現(xiàn)在在hello.tvml文件中添加:
<document>
<alertTemplate>
<title>Hello tvOS!</title>
</alertTemplate>
</document>
TVML 文件是 UI 的實(shí)際內(nèi)容。文檔(document)必須用模板編寫(xiě),否則現(xiàn)在的代碼運(yùn)行時(shí)會(huì)崩潰。這個(gè) TVML 文件只是包含了一個(gè)簡(jiǎn)單的模板和一個(gè)單元素的標(biāo)題。
在編寫(xiě)這些代碼時(shí)我發(fā)現(xiàn)一個(gè)問(wèn)題:本地?zé)o法引用這些文件,文件必須放在一個(gè) web 服務(wù)器上。所以最簡(jiǎn)單的解決方案是找到你剛創(chuàng)建 TVML 和 JS 文件的位置,并在命令行中敲進(jìn)如下指令:
啟動(dòng)服務(wù)端
python -m SimpleHTTPServer 8000
這條指令用 Mac OS 內(nèi)建的 python 解釋器開(kāi)啟了一個(gè)端口號(hào)為 8000 的 web 服務(wù)器,可以用它來(lái)托管本地文件。如果你直接復(fù)制了上面的代碼,按一下 Xcode 的 play 鍵就能啟動(dòng) tvOS 模擬器。還有一個(gè)要注意的事情:這是一個(gè)不夠安全的 HTTP 請(qǐng)求,在 iOS 9 中會(huì)被默認(rèn)的應(yīng)用傳輸安全機(jī)制攔截。為了能夠按之前的方法來(lái)使用本地主機(jī),我們需要在Info.plist文件中添加一個(gè)key。
允許直接加載(Allows Arbitrary Loads)
選擇Info.plist文件然后按加號(hào)(+)來(lái)創(chuàng)建一條新記錄。在列表中選擇"App Transport Security Settings"并按回車(chē)。這會(huì)在字典中創(chuàng)建一個(gè)新行,展開(kāi)它,在這行上按加號(hào)(+)添加一個(gè)子行。接著選中"Allows Arbitrary Loads"并將其設(shè)為true。都設(shè)好了之后我們就能用模擬器運(yùn)行應(yīng)用了。
添加按鈕
在本例中你看到的實(shí)際上是一個(gè)被 Apple 稱作alertTemplate的模板。你還能嵌入一些基本控件,比如在模板中添加文字和按鈕。試著添加一些按鈕吧:
<document>
<alertTemplate>
<title>Hello tvOS!</title>
<button>
<text>A Button</text>
</button>
<button>
<text>A Second Button</text>
</button>
</alertTemplate>
</document>
這里我們只加了子按鈕(child button)元素,每個(gè)子按鈕都有它自己的子文本(child text)元素。這段代碼在 tvOS 模擬器上全屏顯示alert和兩個(gè)按鈕。如果你自學(xué)能力很強(qiáng),蘋(píng)果的官方文檔中列出了你能使用的所有模板和控件。否則的話請(qǐng)跟緊我,訂閱我的博客,之后我會(huì)教你開(kāi)發(fā)一個(gè)完整的應(yīng)用。
繼續(xù)學(xué)習(xí)
學(xué)習(xí)本教程的第二部分:為應(yīng)用添加交互事件。
如果你想在新文章發(fā)布時(shí)收到通知,請(qǐng)訂閱我的 newsletter。
剛開(kāi)始學(xué)習(xí)難免會(huì)遇到問(wèn)題,如果你卡住了,別猶豫,在 twitter 上聯(lián)系我@jquave。