说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

Apple TV指南:从零开始用Swift开发个tvOS应用

HTML文档下载 WORD文档下载 PDF文档下载
这篇文章主要介绍了如何在Apple TV上开发一个名为tvOS的App,以及关于tvOS的一些相关的定义,最终呈现给用户一个非常有趣的界面。

本文出自:Jameson Quave's Blog,作者:Jameson Quave,译文出自:SwiftGG,译者:ray16897188

 

教程结束时,我们会做出这样一个应用:


你更喜欢哪个艺术家?

第一部分

开始

在我们开始之前你需要安装 Xcode 7.1 beta 版,可以从这里下载:下载 Xcode 7.1 Beta。

注意:下载 Xcode 7.1 Beta需要有一个苹果开发者账号,由于目前 Xcode 是预发行版,以后正式发布的时候可能会有变化。
安装的时候要注意,如果你重命名Xcode7.1应用,会遇到一个已知Bug。一定有人会这么做,所以提前说明……别这么做,否则你的tvOS模拟器会崩溃。

同时要注意,虽然支持优胜美地 (Yosemite),但是在该操作系统上,功能会受限。推荐用 OSX 10.11 El Capitan 或更新的系统。ElCapitan beta可以在这里下载。

下面我们来介绍一些 tvOS 相关的定义。

TVMLKit

TVMLKit 是 Apple 设计的一个新框架,能在使用 Swift 或 Objective-C 实现应用逻辑的同时使用 Javascript 和 XML 开发更炫酷的用户界面。

TVML

TVML 是“TV Markup Language”(TV 标记语言)的缩写,基本上是一些 XML 语句,用于实现基于C/S(client-server,客户端-服务端)架构的 tvOS 应用布局。布局界面时,我们会用到一些 Apple 提供的 TVML 模板创建我们的 UI,然后用 TVJS 写交互脚本。

TVJS

我能告诉你的是,TVJS 就是你(可能已经)熟悉的 JavaScript。

Hello World

我们从一个基本的 hello world 程序开始。就 Apple TV 而言,我们可以只把"Hello World"输出到控制台上。这也许是个不错的开始,但更好的选择是使用 Apple TV 的一些 TVMLKit 元素在屏幕上创建一个模板。

首先,打开 Xcode 7.1 并创建一个新项目。你可以看到一个模板列表,我们在左侧选择CHANGE tvOS,然后再选Single View Application模板。

这样就会根据 tvOS 模板创建一些默认文件和一个简单的 Swift 入口点,对一会儿创建 UI 很有帮助。

建立 TVJS 主文件

在 C/S 架构的 tvOS 应用中,服务端本质上就是 TVML 和 JavaScript 文件以及和它们相关的所有数据。JavaScript 文件会装载 TVML 并把页面(page)放入视图栈中。可以从另一个角度理解:JavaScript 文件就像 TVML 文件的路由器或是控制器(controller),而 TVML 文件本质上是若干视图(views)。

拉开序幕

首先我们要修改应用的AppDelegate.swift文件。第一步是让我们的应用遵循TVApplicationControllerDelegate协议。该协议定义在 TVMLKit 框架中,所以需要导入它。更新AppDelegate.swift文件,如下所示:

import TVMLKitclass AppDelegate: UIResponder,UIApplicationDelegate,TVApplicationControllerDelegate {....
此协议包含四个 tvOS 实现AppDelegate后会调用的函数,用于给我们的应用发送 tvOS 生命周期通知。现在我们无需操心这些,但在后面的教程中我们会对它们进行深入研究。目前只要像上面的代码那样把协议加进去就够了。

下一步,我们要添加一些代码,让 JS 文件起作用。由于是 beta 版,我们还需要自己完成这些工作。我相信在 Xcode 的后续版本中这一步会变成一个模板。

在程序里didFinishLaunchingWithOptions这个函数中我们要完成一些步骤。它们对所有应用来说都是一样的,所以你可以直接复制这段代码:


// 在一个可选属性中保存对 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}

简单说说这段代码干了什么:它拿到了一个TVApplicationControllerContext引用,这个Context只是为我们的AppDelegate类提供了一些启动数据,然后给了我们一个能调整和修改启动过程的接口。接着把URL 传给待会儿要运行的main.js文件,并将appController的路径设置成这个 URL。

现在就要添加我们的 JavaScript 文件了,点击 File > New,然后在 iOS tab 下面选择 Other >Empty file。将这个文件命名为main.js。

用同样方法创建一个hello.tvml文件。

在main.js文件中添加一些简单的 JavaScript 代码,用来装载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');}
现在在hello.tvml文件中添加:

<document>  <alertTemplate>      <title>Hello tvOS!</title>  </alertTemplate></document>

TVML 文件是 UI 的实际内容。文档(document)必须用模板编写,否则现在的代码运行时会崩溃。这个 TVML 文件只是包含了一个简单的模板和一个单元素的标题。

在编写这些代码时我发现一个问题:本地无法引用这些文件,文件必须放在一个 web 服务器上。所以最简单的解决方案是找到你刚创建 TVML 和JS 文件的位置,并在命令行中敲进如下指令:

启动服务端

python -m SimpleHTTPServer 8000

这条指令用 Mac OS 内建的 python 解释器开启了一个端口号为 8000 的 web 服务器,可以用它来托管本地文件。如果在命令行中,执行了上面给出的代码,那么现在按一下Xcode 的 play 按钮就能在 tvOS 模拟器中启动了。还有一个要注意的事情:这是一个不够安全的 HTTP 请求,在 iOS 9 中会被默认的应用传输安全机制拦截。为了能够按之前的方法来使用本地主机,我们需要在Info.plist文件中添加一个key。

允许直接加载(Allows Arbitrary Loads)

选择Info.plist文件然后按加号(+)来创建一条新记录。在列表中选择”App Transport Security Settings”并按 return 建。这将创建一个新的字典条目,展开它,在这行上按加号(+)添加一个子行。接着选中”Allows Arbitrary Loads”并将其设为true。都设好了之后我们就能用模拟器运行应用了。

添加按钮

在本例中你看到的实际上是一个被 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)元素,每个子按钮都有它自己的子文本(child text)元素。这段代码在 tvOS模拟器上全屏显示alert和两个按钮。如果你自学能力很强,苹果的官方文档中列出了你能使用的所有模板和控件。

第二部分

增加交互事件

在第一部分中我们创建了一个简单的 TVML document,里面有几个按钮。这个document看起来是这样的:

<document>	<alertTemplate>		<title>Hello tvOS!</title>		<button>			<text>A Button</text>		</button>		<button>			<text>A Second Button</text>		</button>	</alertTemplate></document>
这是一个带按钮的警告(alert)界面,目前这些按钮没有任何作用。这段代码直接硬编码了具体内容,更好的方式是使用代码生成XML,在 JS 中很容易实现。我们在main.js文件中添加一个新函数,把上面的代码封装成一个更简单的警告界面,它只包含一个 OK 按钮。

function alert(str) {	var alertXMLString = `<?xml version="1.0" encoding="UTF-8" ?>	<document>		<alertTemplate>			<title>Hey Listen!</title>			<description>${str}</description>			<button>				<text>OK</text>		</button>	</alertTemplate></document>`var parser = new DOMParser();var alertDOMElement = parser.parseFromString(alertXMLString, "application/xml");navigationDocument.presentModal(alertDOMElement);}
这里创建了一个alertXMLString字符串,它表示的是包含一个按钮的简单警告界面所对应的 TVML。description节点比较特殊,我们使用TVJS 的内嵌字符串语法${variable}来插入str的值。

接下来,创建一个新的DOMParser对象,把这个字符串转换成一个实际的 XML DOM 元素。

最后,我们用navigationDocument的presentModal方法展示一个模态框,内容就是上一步的 DOM 元素。navigationDocument是一个全局变量,它永远指向XML 文档的根节点。

现在,删除onLaunch函数中之前的代码,直接调用刚才创建的函数……

App.onLaunch = function(options) {	alert("Hello!");}


Hello警告

运行应用,你会看到一个炫酷的”Hello!” tvOS 警告。但是点击 OK 没有任何反应。我们该怎么处理像触摸之类的事件呢?

通常来说,在 JavaScript 和 TVML 的世界中,你需要给 DOM 元素添加一个事件监听器(event listener)。举个例子,我们可以给alert函数添加第二个参数,把 OK 按钮触发select事件时需要调用的函数作为参数传入。下面我们就加入这个名为doneCallback的参数:

alertDOMElement.addEventListener("select", function() { doneCallback }, false);
更新后的完整函数如下:

function alert(str, doneCallback) {	var alertXMLString = `<?xml version="1.0" encoding="UTF-8" ?>	<document>		<alertTemplate>			<title>Hey Listen!</title>			<description>${str}</description>			<button>				<text>OK</text>			</button>		</alertTemplate></document>`var parser = new DOMParser();var alertDOMElement = parser.parseFromString(alertXMLString, "application/xml");alertDOMElement.addEventListener("select", doneCallback, false);navigationDocument.presentModal(alertDOMElement);}

现在我们可以修改之前的onLaunch函数,添加一个回调函数来显示一个 TVML 页面。在此之前,我们需要再添加一个getDocumentContents函数,它会在页面加载完毕之后调用回调函数。这个回调函数只有一个参数,用来接收 XMLHttpRequest 对象的响应内容。这样我们就可以轻松地加载多种 TVML 文件。 

function getDocumentContents(url, loadCallback) {	var templateXHR = new XMLHttpRequest();	templateXHR.responseType = "document";	templateXHR.addEventListener("load", function() { loadCallback(templateXHR) }, false);	templateXHR.open("GET", url, true);	templateXHR.send();	return templateXHR;}
代码和之前定义的getDocument方法几乎一样,区别是这里是异步操作,而且不会在界面上显示任何内容。 

有个这个函数,我们就能执行下面的调用,当 OK 按钮被点击时替换屏幕上的警告内容。 

App.onLaunch = function(options) {    alert("Hello!", function() {      var helloDocument = getDocumentContents("http://localhost:8000/hello.tvml", function(xhr) {        navigationDocument.dismissModal();        navigationDocument.pushDocument(xhr.responseXML);      });    });}
我们使用stackTemplate模板来改写hello.tvml文件,这样界面会更有趣。stackTemplate非常适合用来展示一组包含标题和图片的列表内容。下面是本例用到的内容:

<document>    <stackTemplate>        <banner>            <title>Which Artist Do You Prefer?</title>        </banner>        <collectionList>            <shelf>                <section>                    <lockup>                        <img src="http://localhost:8000/nina.png" width="256" height="256" />                        <title>Nina Simone</title>                    </lockup>                    <lockup>                        <img src="http://localhost:8000/coltrane.png" width="256" height="256" />                        <title>John Coltrane</title>                    </lockup>                </section>            </shelf>        </collectionList>    </stackTemplate></document>

这基本上就是stackTemplate的布局方式,banner是顶部的横幅内容,collectionList包含许多shelf对象,而shelf对象则包含许多section对象,section对象又包含许多lockup对象,最后这个才真正包含我们的图片和标题。在本例中我向目录中添加了一些图片,它们是nina.png和coltrane.png。


预告:  2015中国移动开发者大会(MDCC 2015)将于10月14日-16日在北京新云南皇冠假日酒店召开。大会特设九大技术专场:平台与技术(iOS)、平台与技术(Android)、平台与技术(跨平台)、产品与设计、游戏开发、企业移动化、虚拟现实专场、硬件开发与技术、嵌入式开发。大会将聚集国内最具实力的产品技术团队,与开发者一道进行最前沿的探讨与交流。 

第一时间掌握最新移动开发相关信息和技术,请关注mobilehub公众微信号(ID: mobilehub)。

开源工具链“大牛”的经验分享:HelloGCC 2013精彩演讲回顾 20个超实用的JavaScript技巧及最佳实践 【开源专访】Linux Deepin:做更好用的Linux桌面系统 访Andy Jassy:感受亚马逊AWS生态观,思考国内外云计算差异 站到风口,最先飞起来的能将服务做到极致的IDC 苹果Siri再获一专利:可使用自然语音输入来搜索和标记图片 研发周报:Google抛弃C语言,采用Go语言重写Go编译器 取其精华 IE11里移除和新增的功能 大胆预测亚马逊即将推出的五大产品或服务 移动周报:GitHub章鱼猫中国之行 三星与LG的新动向:同样的物联网 ,不同的玩法 从Twitter到Tinder,看社交媒体在2013年的沉浮 一周消息树:有道周枫和他的“放养”团队、太极助手惹“非议” Netflix:使用大数据驱动商业决策 “中国杯”游戏极限开发大赛报道 回顾2013软件开发:JavaScript领风骚 京东“宙斯杯”创新应用大赛,百万奖金为“你”而等待 12306上的分布式内存数据技术GemFire Canalys:苹果、三星2014年仍统治平板市场 微软压力山大 Google和苹果的下一个战场 回顾2013科技界大事件:Mayer登Vouge杂志、Ballmer离职 《近匠》第03期:移动开发工具访谈,AVOS Cloud——后端的金刚钻 次世代视觉:Avegant Glyph智能眼镜技术解析 技术栈的选择:从Groupon转向Node.js、淘宝去IOE谈起 首席数据官:一个属于你的时代已经来临 盘点2013年Facebook七大最受欢迎的hack 见证中国开源的力量:“开源力量”2013年度庆典活动亮点汇总 专访APU13讲师、西电朱虎明:概念难以理解成异构编程最大阻力 盘点2013:21款最优秀的开源数据库 苹果三星再次谈判,欲和解所有侵权案 应对iOS in the Car,Google将携手奥迪推Android车载系统 哪位能给个简单的dll例子吗?我不知怎样写。 简单问题:谁知道改变屏幕的一块区域的颜色的函数是什末? 有关数字视频监控系统的问题!!! 改错误 打算用PB做个Oracle管理器,请给点意见参考参考 如何在APPLET中读入 HTTP中将其他网页的内容 小女子求教!对您可能非常easy的问题! pb6.5做b/s!求救!送分! 这个问题,我都不好意思问,pb70如何编译成exe文件啊? 集成主板的声、显、网卡的问题。(内详) 怎么连sybase 数据库! 怎样用vb实现ctrl + alt + delete键的功能 求超级兔子魔法设置4.2的注册码,一定高分相送 如何调用数据库中带输入、输出参数的存储过程 ASP页面里用下拉框控制日期显示时,没有31号的月份怎么控制不显示31号呢? 寻EPOC高手。 刚学VC要注意点什么哈 如何将BMP图形转成JPEG后,存入数据呢?请教! 脸红请教! 先装好了linux还能加装windows吗? 请问高手:怎样在interDev6.0中调试ASP?? 高手请教,在线等待 一段代码整体一定的快捷方式 MSHFlexGrid的数据显示问题!(40) 使用ADO时,说interface not supported是怎么回事? 请教! 谁知哪儿有flash控制影片的源文件? 怎样把SQL Server中的数据库导出成*.sql文件? 2000SERVER 奇怪:0x80004005 错误,但是在以前的帖子里没有提到 建议:加入精华区的帖子可以改名。有的帖子内容很好,但标题说得不清楚。这样也方便于分类。 有谁知道那里有漂亮的图标下载? 请问如何注册 关于文章“上一篇”“下一篇”的问题 如何在程序中打开一个对话框让用户选择一个目录(别的程序中非常的普遍使用,谢谢) 在同一个系统里,可以同时装2个office吗,一个英文版的和一个中文版的可以吗,? 请问怎样在PB应用程序中的工具栏使用大于16×16的在图标? 如何设置单元格 一个关于高位低位的问题。谢谢。 怎么能知道自己的主板的性能、好坏?比如.... 不知道有谁对ISDN比较了解有这方面的资料吗? 这样的爱是维持多久? 我尝试通过网络免费提供关于如下方面的技术支持服务,并欢迎有兴趣者一起进行讨论。各类问题可以发mail: stevewh@ynmail.com 数据访问ADO与DAO、RDO各用在什么场合下? 在存储过程中的问题,看大家能者见能,智者见智,帮帮手! 如何在在桌面上单击右键弹出的快捷菜单中加入一个项目"启动我的电脑"? 想买一款显示器,不知道是三星好还是PHILIPS好!请大家帮我选择选择!(低档纯屏,<1600元(50分) 在win98下配置tomcat的问题? 什么样的主板需要安VIA 4 IN 1?? gicq玩家的间题 请taglis2002来借分。 如果导体中产生了电流,则(导体两端电压为零,导体内部场强为零)对么,为什么 谁来给我解释一下魔方的公式RUR'U'MUMUMU2M'UM'UM'U2URU'R' 城市化的定义我们的一个辩论题,城市化是否有利于人类发展,我们辨反方,不利于人类发展,我是一辨,第一次参加辩论,不太会写立论稿,谁能帮我?后天就要辨了. 为什么说稳恒电流条件下导体内部可以带电,导体内部的场强也可以不为零? 谁帮我解释一下这个魔方公式R'U'R'U'R'URURFRUR'U'F'FUFUFU'F'U'F' 新型城市化的定义什么是新型城市化?它的准确定义是什么?我国为什么要推行新型城市化? 求平行板电容器受的电场力已经平行板电容器面积为s,间距d,电势差u,求每块板受的力 魔方公式解读R2 y(R U R'U')y'(R'U R') 这公式里的括号是什么意识呀?还有y'魔方要怎么转呀~请详细点呵呵 还有这样的;如:R2 y(R U R'U')2y'(R'U R') 这里的2y'是什么意识呀? 再城市化的定义 有一个电量为-3*10^-6C的点电荷,从某电场中的A点移动到B点,电荷克服电场力做了6*10^-4J的功,从B点运动到C点.电场力对电荷做了9*10^-4J的功,设B点为零电势,求A,C两点的电势各为多少? 将带电荷量为1×10-8 C的电荷,从无限远处移到电场中的A点,要克服静电力做功1×10-将带电荷量为1×10-8 C的电荷,从无限远处移到电场中的A点,要克服静电力做功1×10-6 J,问:(1)电荷的电势能是 城市化是什么意思 断开电容器后两极板之间还有电场力吗要说明为什么 什么是朦胧诗?怎样写朦胧诗? 城市化的概念? 英语翻译摘要:结合对三个明清建筑明显陵,石牌古戏楼和湘西吊脚楼的空间、形态、结构、材料进行的认识,分析三个古老建筑与环境的关系并分析其设计得失.同时在建筑特定的文化背景下 朦胧诗、「一代人」的含义含义及其意象是什么? 什么是晶格取代 求助公式解释下图为“test”表下图为“打卡记录”表在“打卡记录”表中的E3单元格输入公式:=IFERROR(VLOOKUP(E$1,OFFSET(test!$F$2:$H$51,MATCH(打卡记录!$B3&$D3,test!$F$2:$F$51,0)-1,1,COUNTIF(test!$F$2:$F$51,$B 谈谈对朦胧诗的理解 化9.金属的下列性质中,不能用金属的电子气理论加以解释的是 求公式以及详解 两条互相平行的直导线,通有相同方向的电流两条互相平行的直导线,通有相同方向(向上)的电流,有导体a.b,求他们的安培力方向I I a b图形大概就是这样,方向都是向上谁给出“超级详细”的 关于一元一次方程的追及问题“甲、乙两车站相距400千米,慢车每小时行驶100千米,快车每小时行驶140千米.两成同时开出,同向而行,慢车在前,两车出发多少小时后,快车于慢车相距40千米?”类似 请问,“人”的含义是什么? 求详解.用了什么公式.什么的. 导线中若有恒定电流,场强方向平行于导线,各处大小是否相等?导线的若不是柱体,其场强分布又会怎样? “轩辕”原意及引申意义是什么?如题 这个公式的解析. 其中sin(π/n)代表什么.我知道n代表边数,那么 2r代表直径, 2rsin(π/n)根据题意应该等于边长.是圆的内接正方形的边长 做奥斯特实验时,导线为什么要沿南北方向平行地放在小磁针的上方? gb/14732-2006涂料中的甲醛是如何检测的 英语翻译Rather than building yet another Minneapolis sky bridge to join the two,the Walker commissioned artist Siah Armajani to design a pedestrian crossing. 置换固溶体,间隙固溶体以及金属化合物的形成条件有什么差别? 八年级下册物理《密度与浮力》练习及答案 人教版要半期考以前的练习题,复习用.. 英语翻译A joint project of the Walker Art Center and the Minneapolis Park and Recreation Board ,it will also feature year- round horticultural displays in the new Sage and John Cowles Conservatory,located on the grounds and designed by Barnes’s 根据合金相的晶体结构特点可以将其分为( ).A、间隙相 B、固溶体 C、非金属 D、金属化合物 E、金属 进程与程序的区别是什么急 英语翻译With a span of 20 meters like one of the inferior arches of the lower level of the ancient bridge that is classified as a World.Heritage site by Unesco(应该全是大写的联合国教科文组织),added the architect.哪位大虾帮 什么是晶格 心理过程 名词解释 一个圆柱体的高是10cm,若把高增加十分之一,那么侧面积就会增加6.28平方厘米,这个圆柱体原来的体积是多 晶格能是什么 处于静电平衡的导体,内部场强处处为零.其中“内部”指的是导体内部还是其空腔部分? 名词解释技能人才(拓展概念) “拟作者”的含义是什么 由于本人出门在外,不方便查字典, 只身到某地的含义?如:在天津市、上海市有常住户口,“只身到该市安置的”是指一个人到该市还是说此人可以到该市? 麻疹暴发定义(名词解释) 空腔导体静电平衡是哪两个场强平衡了比如一个空腔导体内部中间放一个正电荷,然后内表面感应出负电荷,外表面正电荷,然后我是这样理解的:中间那个正电荷和内表面的负电荷形成的电场, 将一个电荷量为1.0×10-8C的负电荷,从无穷远处移到电场中的A点,克服电场力做功2.0×10-8J,现将该电荷从A移到B点,电场力做功7.0×10-8J.试求A、B两点的电势能(取无穷远处电势为零) 实际金属中的晶体缺陷有哪些?对金属性能有何影响? 名词解释过程模式 物体在两个互相垂直的力作用下运动,力F1对物体做功6J,物体克服力F2做功8J,则F1、F2的合力对物体做功为 何为晶体的线缺陷和面缺陷,它们对金属力学性能有何影响 什么的进程?进程和程序的区别是什么?有助于回答者给出准确的答案 金属在加热过程中会产生哪些缺陷?它们对金属有何影响? 【化学】晶格能的计算问题Li的升华焓为540kJ/mol,LiF固体的生成热为-612kJ/mol,求LiF的晶格能为多少?--------------------------------------------------------------这道题是不是缺少数据?应该怎么算? 一点电荷从电场中的A点移动到B点,静电力做功为零,则以下说法中正确的是( )一点电荷从电场中的A点移动到B点,静电力做功为零,则以下说法中正确的是( )A. A、B两点的电势一定相等 B. 4) 实际的金属当中存在哪些缺陷,它们的特点是什么?这些特点对钢的性能产生了什么样的影响?人们怎样利用材料科学导论的习题~ 是不是所有化学键都有晶格?
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘