安卓-Web-应用开发入门指南-三-

105 阅读52分钟

安卓 Web 应用开发入门指南(三)

原文:Beginning Android Web Apps Development

协议:CC BY-NC-SA 4.0

十一、使用音频和视频挑战极限

音频和视频是移动网络中最难涉及的两个话题。虽然每一种技术都可以增强网站或应用的视觉和听觉吸引力,但通常这两种技术都会被移动内容创作者滥用。例如,我注意到在移动世界越来越普遍的一种滥用形式是针对移动浏览器的基于音频的广告。虽然音频和视频技术都可能被不正确地使用,或者只是以一种普通的令人讨厌的方式使用,但如果使用正确,它们确实可以达到很好的目的。

比方说,我们正在开发一个手机游戏应用,我们想添加一些轻松的背景音乐来增强用户体验。当使用audio标签时,我们可以使用 Android 操作系统浏览器的内置 HTML5 功能相当容易地做到这一点,只需要几行代码。除此之外,我们甚至可以使用一点 JavaScript 来操作音频元素。我们可以通过按键来播放、停止或暂停音频。

通过 Android 的浏览器程序,我们还能够利用 HTML5 video标签来增强我们的 Web 应用,包括 h.264、MPEG-4 和 WebM 格式的视频。这两个标签——audiovideo标签——如果使用得当,可以创造出一些顶级的用户体验来增强它们所在的应用,使它们散发出卓越的魅力。

在这一章中,我们将看一看这些元素,它们的 API,以及在我们的应用中使用这些新的HTML5标签的优缺点。

面向移动 Web 应用的音频

直到几年前,作为一名开发人员,如果您想在 web 应用中包含音频,您的选择是微乎其微的。几乎所有的解决方案都涉及到使用 Adobe Flash,并使用 Flash 作为中间人将音频传输到用户的音频输入设备。虽然可以通过embedobject标签给你的用户体验添加音频,但更多的时候你会得到一个非常有限且不可接受的用户体验,这让你的最终用户和开发者希望得到更多。

HTML5 采用率的上升使得在 HTML5 audio标签的 Android 实现中处理音频(尽管在一些罕见的情况下仍然很痛苦)变得普遍顺畅。有大量的例子表明,移动 Web 应用和游戏利用音频元素将背景音乐和声音效果带到他们的项目中,这有助于为用户创造更多引人入胜的场景。

不幸的是,像 Web 开发世界中的大多数事情一样,并不是所有的音频编解码器都是一样的。在关注移动世界时尤其如此。自 2010 年年中 Android 2.0 首次问世以来,谷歌的 Android 操作系统一直在使用 HTML5 音频标签,但它只使用了两种更受欢迎的音频编解码器选择——MP3 和 AAC 音频格式。

利用 HTML5 音频标签

使用 HTML5 audio标签非常简单。看看清单 11–1 中的例子,我们在用户页面中添加了一个重复的音频循环。

**清单 11–1。**html 5 音频元素的基本使用

<audio autoplay="autoplay" controls="controls">     <source src="audio/stairwell.ogg" type="audio/ogg" />     <source src="audio/stairwell.mp3" type="audio/mpeg" />     "Sorry, your browser does not support the audio element." </audio>

音频标签的基本用法与 HTML 空间中的其他标签非常相似。当声明 HTML 音频元素时,我们可以在文档中调用几个属性。让我们看看下面的一些属性:

  • autoplay—如果被调用,该属性将在音频元素准备就绪并可用时播放它
  • controls—确定是否向用户显示该音频元素的控件。
  • loop—如果设置,该属性告诉音频无限循环。就像那首永远不会结束的歌!
  • preload—这决定在文档加载时是否将音频元素预加载到页面中。
  • src—音频文件的 URL。

查看清单 11–1,我们还可以注意到audio标签也包含另外两个源标签。这些source标签都有src属性,指向服务器上文件的 URL。

使用多个标签的原因实际上是编写一个可以在多种浏览器上工作的 HTML 文档的巧妙方法。如果你的浏览器支持 HTML5 audio标签,它会检查每一个源编解码器,直到找到一个适合你的浏览器。如果它成功地找到了一个合适的文件(即,您提供了一个可以在用户系统上播放的文件版本),它将播放该文件。如果没有,它将什么都不做。如果出于某种原因,你正在从一个没有显示音频标签的旧 Android 设备上查看这个页面,那么浏览器将会忽略这个元素,并显示预设的错误消息“对不起,??”。您的浏览器不支持如图 Figure 11–1 所示的音频图像。

images

**图 11–1。**Android Gingerbread 2.3 设备上的 HTML5 音频元素,带有“控件”属性集

将音频整合到“那是谁的推文”?

在我们在本书中使用的第一个应用中,我们要求人们猜测哪一个 Twitter 帐户产生了一条给定的 tweet。现在想象一下,我们想要放一点音频来抚慰那些玩我们游戏的人的野蛮的心灵。我们可以很容易地用音频标签做到这一点,使用下面的清单 11–2 中的代码。

清单 11–2。 HTML 代码那是谁的推文?带音频

`

Who’s That Tweet? ****     ****

  

    
Score:0
    

Player 1

          
      
      
    
    
      

    `

    在本例中,我们已经开始播放我们的主题曲,并且我们已经设置了 loop 属性,这样它将简单地重复循环,直到时间结束。我们没有指定控件,如果音频无法加载,我们也不会显示任何消息。现在我们只需要找到一首好的主题曲,不会让我们的用户太烦!

    使用音频编解码器

    如果您正在为 Android 设备构建您的应用,您将希望坚持使用整个平台上可用的以下三种编解码器之一:MPEG-2 音频层 III (MP3)、高级音频编码(AAC)和开源粉丝最喜欢的 Ogg。虽然每一个都有自己的好处,但大多数开发者通常只坚持 MP3 和 Ogg,因为有很多免费的开源工具可以将你的音频转换成这些格式。

    MP3 文件

    MP3 音频格式被称为有损压缩音频格式。有损压缩格式在多媒体中非常流行,如果你以前曾经使用过 Adobe Fireworks、Gimp 或 Adobe Photoshop 等图形设计程序,那么当你试图从图像中挤出几个额外的字节时,你可能对有损压缩比较熟悉(没有双关语)。在不损害图像完整性的情况下,删除数字图像的一部分以减小图像大小的方法同样适用于音频。

    在 MP3 的例子中,压缩算法在数字音频中运行,并去除普通人耳通常不能拾取的部分音轨。MP3 文件的比特率越低,表示从录音中删除的数据越多。

    虽然有些人声称由于丢失了音频信息,从 MP3 中听到了微弱的声音,但大多数人似乎无法说出与无损数字拷贝相比的区别。这使得 MP3 成为一个非常棒的音频编解码器,可以用于 HTML5 音频,因为你可以获得非常小的文件,可以下载并快速传输到用户的浏览器。也就是说,你应该小心为 MP3 文件选择合适的比特率——比如 128 kbps。任何较低的声音在高质量的音频设备上可能会有微弱的声音(例如,HTC Rezound)。如果不使文件太大的话,移动到 192、256 或 320 kbps 可能是有用的;然而,考虑到相对较小的好处,您可能会发现这是不必要的。超过 320 kbps 很可能是一种浪费,除非你的应用是为发烧友打造的!

    在很大程度上,MP3 是互联网上事实上的音频格式,这就是为什么几乎每个主流浏览器都支持 MP3 音频和 HTML5,无需额外的插件。

    加气混凝土

    高级音频编码,也称为 AAC,是另一种即将出现的音频格式。如果你曾经从苹果 iTunes 上购买过音乐,那么你很可能购买了这种音频格式的音乐。AAC 是由几家公司开发的,包括索尼、诺基亚、杜比和 AT&T。这种格式确实比它的前身 MP3 获得了更好的音频质量,并于 1997 年春天被宣布为国际音频标准。

    这种音频格式受开发人员欢迎的原因之一,除了与其竞争对手相比声音更好这一明显事实之外,是因为分发或传输 AAC 编码内容不需要许可证或专利费用。注意,这种许可只适用于实际编码——你不能拿着不属于你的有版权的材料,用 AAC 编码,在你把它分发给全世界后嘲笑律师。好吧,我想你可以笑,但这对你的案子没有帮助!

    Ogg

    在我们探索征服 Android 设备上的 HTML5 音频的过程中,另一个崭露头角的是我个人最喜欢的编解码器之一:Ogg。Ogg 的创建者在过去声明过,他们创建 Ogg 是为了成为一种不受限制和软件专利束缚的格式。这促进了 Ogg 在大多数浏览器中作为默认 HTML5 音频编解码器的采用。如果你将你的音频编码成 Ogg 格式,它很有可能不仅能在 Android 设备上运行,也能在当今市场上的许多其他设备和浏览器上运行。

    虽然 Ogg 是一种像 MP3 和 AAC 一样的有损压缩格式,但 Ogg 背后的框架可以在市场上的几种无损音频格式中找到,如 OggPCM 和 FLAC。有了 Ogg,你可以随心所欲:微小的文件或巨大的无损文件。天空是无限的。

    使用 Audacity 音频编辑器

    我最喜欢的开源音频软件之一是 Audacity ( [audacity.sourceforge.net/](http://audacity.sourceforge.net/))。这个免费的跨平台应用可以让您轻松地从许多不同的格式导入各种各样的音频。使用 Audacity,您可以轻松地将音频拼接在一起,剪切音频文件,录制现场音频,改变音频文件的音高和速度,给音频轨道添加噪音,降低过高的音频轨道的音量,以及许多其他非常酷和有用的功能(参见图 11–2)。

    images

    图 11–2。 Audacity 1.3 Beta 编辑一个知识共享音频文件

    每当我处理来自客户的音频时,当我看到一个大的 512 MB–1024 MB 的 WAV 音频文件时,Audacity 总是我的第一选择,它可以删除音频文件中我不需要的部分,或者将音频文件转换成更小、更易于管理的格式。

    因为这本书只是打算涵盖 Android 移动设备设计的初学者方面,所以我不会对 Audacity 的所有特性进行过多的深入探讨。相反,我将介绍一些基础知识,比如将一种音频格式导出到另一种格式。

    如果你想把你的文件转换成 MP3 格式,那么你需要下载蹩脚的 MP3 库。您可以通过 Audacity 中的首选项轻松地做到这一点。

    1. 转到编辑菜单并选择属性。

    2. Choose the Libraries option in the left hand section of the Properties window as shown in Figure 11–3. images

      图 11–3。 查看 Audacity 1.3 测试版首选项对话框。

    3. 一旦到了那里,您可以选择将 Audacity 指向您的蹩脚库(如果您已经在计算机上安装了它的话)。如果您还没有安装 LAME 库,请继续执行步骤 4。

    4. Click the Download button, which will take you a site where can download the latest and greatest copy of the LAME MP3 Library, as shown in Figure 11–4. images

      图 11–4。 瘸腿 MP3 库下载页面。

    5. 一旦你下载了这个库并解压到你的硬盘上,你就可以录制音频并导出为 MP3 格式了。

    如果你看一下本节前面的图 11–2,你会发现我们已经在使用一个名为楼梯间. ogg 的创作共用音频文件。我们要做的是将这个 Ogg 文件立即转换成 MP3 文件。为此:

    1. Click File in the menu bar, and then select the Export item as seen in Figure 11–5. images

      图 11–5。 在 Audacity 1.3 Beta 中从 Audacity 文件菜单中选择导出。

    2. 在下拉框中,确保将文件格式更改为 MP3,而不是音频文件的当前格式。

    3. 选择您想要保存文件的位置,单击保存按钮,您就完成了!

    你看,我不是答应过你不会痛的吗?现在,您已经知道如何快速将音频从一种格式转换为另一种格式,是时候通过非常方便的 HTML5 音频数据 API 来处理音频了。

    音频数据 API

    使用音频数据 API,开发人员可以用几年前不可能的方式与音频数据进行交互。使用 JavaScript 和一些 HTML,您可以轻松地创建自己的控件来与您的音频数据交互,正如我们在清单 11–3 中看到的。

    看一下下面的例子,你可以看到我们在清单 11–1 上进行扩展,并添加了一些新的定制控件来播放和停止音频。

    清单 11–3。 更高级的 HTML5 音频数据 API

    `               "Sorry, your browser does not support the audio element."

    Play Pause

    `

    当您在浏览器中运行这段代码时,您可能注意到的第一件事就是页面上根本没有任何音频控件,除了我们添加到页面上的两个按钮,它们的 id 分别是playpause。这些按钮虽然不像在图 11–6 中看到的那么漂亮,但将是我们操纵页面上音频的唯一手段。

    images

    图 11–6。 在 Android 2.3.4 姜饼设备上加载我们的演示 HTML5 音频文档

    现在,如果你在 JavaScript 中查看清单 11–3 的底部,我们可以检查真正的奇迹发生在哪里。在这里,我们为audioplayButtonpauseButton声明变量。接下来,我们向每个按钮添加一个事件监听器,这样当用户单击这些按钮时,我们就可以发出一些代码来播放或停止音频流。如果我们愿意,我们可以包含额外的音量按钮,这将采取与上述代码类似的形式,但调用audio.volume=X,其中 X 将是一个 0 到 1 之间的数字,表示音量级别百分比(因此,如果您想将音量增加 10%,您的代码将读取audio.volume = audio.volume + .1)。

    你也不仅仅局限于随意暂停你的音频文件。使用 HTML5 音频数据 API,您可以轻松控制在页面中播放或欣赏音频的许多方面,例如操纵音频文件的音量,分析一个轨道中每分钟的节拍数,将canvas的强大功能与音频数据 API 结合起来,创建您自己的可听音调,等等。

    向移动应用添加视频

    既然我们已经讲述了美妙的音频世界,现在是时候通过 HTML5 视频了解互联网多媒体的视觉吸引力了。视频标签是未来几年出现的 HTML5 新元素之一。它的创建是为了让开发人员的工作更容易,并让我们摆脱对 Adobe Flash 的依赖。对我们来说,不幸的是,没有人能真正就视频标准达成一致,而且有这么多的障碍、编解码器、许可协议和专利挡在我们的路上,我们不太可能很快就推出一种基于浏览器的通用视频格式。

    好消息是,由于我们只专注于基于 Android 的设备,我们不必处理在桌面计算世界中使用 HTML5 视频带来的许多挫折。在这里,很简单。有一些视频编解码器可以在 Android 浏览器上工作,只要你坚持使用其中的一种或全部,你就能为你的移动用户提供更丰富的多媒体体验。

    使用 HTML5 视频标签

    调用 HTML5 video标签就像调用我们在本章前面讨论的audio标签一样简单。看一下清单 11–3,看看我们如何使用几行代码轻松地向用户显示视频。

    **清单 11–3。**html 5 视频元素的基本使用

    <video width="320" height="240" controls="controls" poster="video/big_buck_bunny.jpg">     <source src="video/big_buck_bunny.mov" type="video/mp4" />     <source src="video/big_buck_bunny.ogg" type="video/ogg" />     <source src="video/big_buck_bunny.webm" type="video/webm" />     Sorry! Unfortunately your browser does not support the video tag </video>

    在这个例子中,我们只是调用一个视频文件,并将视频容器的width设置为 320 像素,将height设置为 240 像素。我们还告诉视频显示它的控制,这样用户可以播放,暂停,停止,并操纵视频的音量。你可以在图 11–7 中的移动设备上看到这个样子。

    images

    图 11–7。 在 Android 2.3.4 姜饼设备上观看 HTML5 视频

    您还会注意到,video标签与audio标签的不同之处在于具有不同的属性。最突出的一个是poster属性,它让我们添加一个截图(或任何其他图像)来表示将要播放的视频。这对于移动设备来说非常好,因为当你在 Android 设备上播放视频时,Android 设备会将视频流传递给内置的视频播放器,后者会为你播放视频,而不是像人们在使用台式电脑多年后所期望的那样在浏览器中播放视频。

    虽然这个功能有趣且方便,但它完全消除了人们使用视频数据 API 的许多理由,因为它在我们的页面之外播放视频——在一个专用的视频应用中。这破坏了用户体验,使我们无法控制用户在观看我们的视频时会看到什么。

    一会儿,我们将给出一个视频例子,类似于我们在上面使用的音频 API。然而,我们应该注意到,虽然你可以用视频数据 API 做一些很酷的事情,但是很多事情都超出了大多数人的需求。以下是基本情况;然而,完整的 API 可在[www.w3.org/2010/05/video/mediaevents.html](http://www.w3.org/2010/05/video/mediaevents.html).获得参考。现在让我们来看看在开发下一个使用视频的移动 web 应用时可以使用的最有用的属性!

    • height—控制播放视频的高度
    • width—控制正在播放的视频宽度
    • preload—如果设置,将在页面加载时预加载视频
    • autoplay—如果设置,将在视频准备就绪时自动播放
    • loop—如果设置,将无限循环播放视频
    • controls—如果设置,将向用户显示控件以控制视频
    • src—指向视频文件来源的 URL
    编解码器

    就像我们对音频所做的那样,视频必须被编码成原生 Android web 浏览器支持的几种格式之一(后面会提到)。对视频进行编码可能比对音频进行编码要稍微复杂一些,因为你要对两种东西进行编码——即音频和视频!我们将介绍您可以使用的格式,并讨论如何轻松地在它们之间移动音频和视频。

    h.264/MPEG-4

    多年来,MPEG-4 已经成为互联网和我们日常消费生活中视频编码的首要标准之一,尤其是在高清视频方面。最近,随着 YouTube 和 Vimeo 等社交视频共享网站的兴起,MPEG-4 进入了公众的视野,这些网站允许用户上传这种格式的视频。MPEG-4 的当前版本被称为 h.264/MPEG-4 AVC,是高质量视频压缩的标准,如蓝光光盘上的标准。

    Ogg Theora

    Theora 是一种免费的开源有损视频压缩格式,由负责维护 Ogg 音频编解码器的同一个基金会 Xiph 创建。Org 基金会。虽然 Theora 本身是基于一个名为 VP3 的专有视频编解码器,但它后来被发布到公共领域,从 2002 年 3 月起任何人都可以免费使用。

    Ogg Theora 在设计上类似于 MPEG-4,并且在过去几年中作为一项技术得到了快速发展。虽然它在质量上仍然比不上 MPEG-4 视频,但它非常接近,以至于许多以前喜欢广泛接受 MPEG-4 的开发人员现在选择走 HTML5 视频路线,开始加入 Theora 的行列。

    WebM

    视频世界的一个新竞争者是谷歌自己的 WebM 视频编解码器。WebM 是在 2010 年的谷歌 I/O 大会上宣布的,是一种免版税的视频编解码器,谷歌将其投入使用,试图规避 HTML5 音频和视频中出现的许多问题。虽然每个人都很高兴在他们的 web 应用和网站中使用这些新技术,但是如果没有所有的浏览器制造商都同意一个标准,就很难做到这一点。

    WebM 是完全免费的,这意味着任何人都可以获得这项技术,并将其包含在他们的网络浏览器中,而不用担心谷歌将来会敲他们的门要求支付费用。但是,请记住,这里指的是技术,而不是实际的内容。分发有版权的电影会让其他人来敲你的门要求支付!

    即使有了这个免版税的安全网,与 Ogg Theora 等其他视频编解码器相比,WebM 的采用率仍然相当低。

    使用手刹转码视频

    现在,您已经对一些视频编解码器有了更好的了解,我敢打赌,您会问自己如何创建视频内容,以便在应用中使用它们。最简单、最省事的方法之一是一个叫做手刹([handbrake.fr/](http://handbrake.fr/))的小应用。手刹是另一个令人难以置信的开源应用,旨在使视频爱好者和普通视频转码消费者的日常生活更加轻松。

    看看图 11–8。这是我们打开手刹应用时看到的默认视图。正如你所看到的,这里的一切都非常用户友好,易于使用。在应用的顶部,如果您单击电影隔板图标,您可以设置您想要转码的视频源,或者从一种格式转换为另一种格式。在该图标下面,有一个区域,您可以在其中设置新创建的视频的目的地,以及更改您想要存放视频的容器。手刹提供的两个容器是MKVM4V视频容器。容器是一种简单的文件格式,用于保存视频的两个独立部分(图片和音频)。

    images

    图 11–8。 在 Windows 7 操作系统上打开手刹后的视图

    该应用的下半部分是一个选项卡式视图,您可以使用它来定制您的视频,甚至更喜欢。这里最重要的选项卡是视频选项卡。在这里,您可以设置您想要将视频转换为哪种编解码器。根据您选择的视频容器,手刹为您提供了三种视频转换选择——MPEG-4 或 Ogg Theora。

    应用的右边将会为你带来很多奇迹。在这里,您可以从各种预配置的视频设置中进行选择,因此您所要做的就是输入一个视频源,决定您要将视频保存到哪里,选择一个您喜欢的设置,然后开始编码。

    如果你看一下图 11–9,你也会注意到视频容器选项旁边的两个小复选框。这些复选框Web OptimizediPod 5G Support,是您在对视频进行编码时可能想要尝试的两个选项。在某些情况下,我发现这些设置帮助我创建了质量更好的视频文件,以便在浏览器中使用。然而,在其他时候,它们只会让我心痛。这一切都归结到你作为你的源材料使用的视频文件。视频可能很棘手,尤其是将它从一种格式转换成另一种格式时。最后,人们通常必须“玩”一点设置,以获得最好的结果。如果您的视频文件很大(因此需要更多时间进行转码),您可以考虑将它分割成一小部分进行试验。一旦你找到了设置和选项的正确组合,你就可以转换视频的长版本,为自己节省一些时间。

    images

    图 11–9。 设置 Windows 7 手刹内的视频源、目的地和视频容器设置

    images

    图 11–10。 选择 iPhone & iPod Touch 为我们的视频预设配置设置

    最后,手刹的选择可能有点多。如果你在寻找更简单的东西,你可能想看看更方便消费者的(即,为非开发人员或高级用户制作的)解决方案,如 DoubleTwist ( [www.doubletwist.com](http://www.doubletwist.com))和 Videora ( [www.videora.com](http://www.videora.com))。两者都可以将视频转换成在移动设备上可以观看的格式,只需很少的努力或需要定制。

    现在我们已经了解了一些关于创建、显示和使用您自己的音频和视频的基本信息,我们将介绍一些您可以通过与程序员可用的不同 API 接口来扩展您的应用的领域。

    自己探索:音乐服务应用编程接口

    许多 web 服务通过 API(应用编程接口)向程序员提供对其平台的访问。在这一节中,我们将讨论两个流行的应用,以及它们提供的 API。您可能会发现,通过将您的应用绑定到这些服务中的之一,您不仅可以使用一些很酷的工具——您还可以增加应用对该服务用户的吸引力。

    “滚动”曲目至 Last.fm

    Last.fm 是一项服务,它不仅可以将音乐传输到你的电脑或手机上,还可以智能地了解你的偏好。一种方法是允许多个设备(即安装了 Last.fm 客户端的 iOS 设备和 android 手机)将收听的曲目信息发送到 Last.fm,Last.fm 将这一过程称为“scrobbling”。例如,我用谷歌音乐通过浏览器收听我的音乐收藏。通过使用 Chrome 的一个扩展将我的曲目滚动到 Last.fm,我可以在以后查看我的收听行为,Last.fm 知道我喜欢听什么类型的音乐(图 11–11)。

    images

    图 11–11。 我的 Last.fm 最近听的曲目

    一旦录制了一首曲目,它就会告知 Last.fm 我的收听习惯。这有助于告诉 Last.fm 向我推荐什么,并允许我找到我可能喜欢的新音乐。

    想象一下,我们想在我们的新应用 MusicDiscovery 中向用户展示音乐片段。假设 MusicDiscovery 为用户播放 45 秒的歌曲片段。用户评价他们有多喜欢这首歌,如果他们评价足够高,我们就把它滚动到 Last.fm,这样它就可以记录他们的偏好。我们将如何着手做这件事?

    首先,我们需要了解 Last.fm API。大多数提供 API 访问的 web 服务会在他们网站的“面向开发者”或“API 访问”部分清楚地展示如何使用它。Last.fm 在其主页底部包含一个“API”链接,通过该链接可以进入 API 主页(图 11–12)。

    images

    **图 11–12。**last . FM 网络服务页面

    翻看 Last.fm API 信息,好像是两步走的过程。首先,你必须申请成为一名开发者(这包括告诉 Last.fm 你打算将他们的数据用于什么目的,即商业或非商业用途),并填写一些关于你的应用的基本信息。一旦解决了这个问题,您就可以探索他们的 API 的使用了。

    API Intro 页面列出了一些基本信息,包括 API 根 URL。这是我们将向其发送信息的网址。大多数请求将利用 AJAX,这是一种我们将在下一章详细讨论的技术。浏览文档,我们可以找到如何将数据发送到 Last.fm 的示例。

    正如我们在 Figure 11–13 中看到的,我们对 Last.fm API 的请求采用特殊格式的 URL 或 HTTP POST 请求的形式。然后,Last.fm API 使用 XML 返回响应。

    images

    **图 11–13。**last . FM API 请求文档

    现在我们已经大致了解了信息将如何在我们的应用和 Last.fm 之间来回传递,我们可以开始探索 scrobbling 特性了。Last.fm 的 scrobble 文档([www.last.fm/api/scrobbling](http://www.last.fm/api/scrobbling),图 11–14)详细地展示了整个过程,包括使用哪些 API 调用(或函数),以及发送 scrobble 请求时使用什么标准。

    images

    图 11–14。 捡破烂过程

    现在我们已经得到了所有的片段,我们需要做的就是编写适当的 JavaScript 代码来获取用户已经评级的当前音乐片段,在 Last.fm 的目录中查找它,并发送 scrobble 请求。在这里你可以发挥你的编程能力并解决它。一路上,一定要看看 Last.fm 的其他广泛的查找和录制功能。不仅可以为 Last.fm 用户提升用户体验,还可以利用 Last.fm 数据为自己不使用 Last.fm 的用户提升体验!

    挖掘亚马逊产品广告 API 的力量

    大约 15 年前,Amazon.com 以书店起家。现在,他们已经发展成为一个巨大的零售巨头,提供从书籍到云计算服务器等等的一切。最近,他们已经扩大了他们的音乐产品,在应用中提供音乐或视频的开发者可能希望通过亚马逊提供购买这些资源的链接。

    亚马逊产品广告 API ( [affiliate-program.amazon.com/gp/advertising/api/detail/main.html](https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html),图 11–15)是一个庞大的网站,所以我们只能在这里强调它的主要特性。你可以花上几天时间来探索你可以用亚马逊的数据做的一切,所有这些都是为了通过你的应用提供亚马逊产品来增加收入。

    images

    图 11–15。 亚马逊产品广告 API

    Amazon 不仅提供关于他们的 API 的文档,还提供开发者论坛,在那里你可以向其他开发者寻求帮助,甚至提供代码示例,这可以让你快速上手并运行。

    对代码数据库进行一些快速搜索,就会发现一段非常有趣的代码,对于任何希望构建一个展示特定艺术家的应用的人来说都是如此。假设你在一个乐队,想为你的乐队开发一个应用。你决定开发一个 web 应用,因为它可以在每个人的智能手机上轻松运行,而且你正在亚马逊的 S3 云存储中存储你的音乐会录音、演示和专辑。我们该如何向粉丝们推销呢?它有一个演示,叫做 io objects([j.mp/iobjects](http://j.mp/iobjects),图 11–16)。

    images

    **图 11–16。**io objects 代码示例

    虽然这比我们在上一节中讨论的 Last.fm API 要复杂得多,但它确实展示了在应用中使用 API 的强大功能。现在你不需要担心支付你的材料(因为亚马逊灵活支付系统(FPS)可以照顾这一点),你可以很容易地通过你的应用,通过亚马逊提供产品,这是你的粉丝熟悉并经常使用的机会!

    正如我们所见,使用来自 Amazon 或 Last.fm 等服务的 API 不仅可以增加应用的交互性,还可以带来新的收入流和创新方式。当你的乐队(或你客户的乐队)的用户还在音乐会上就可以下载歌曲时,他们肯定会脱颖而出,而你将成为实现这一切的开发者英雄!

    总结

    在移动 HTML5 前端处理音频和视频可能会非常轻松,因为您必须支持的手机和操作系统数量有限。然而,正如本章开始时提到的,如果使用不当,它们都是很容易被滥用的技术,或者很快就会对你不利。在这一章中,我希望我已经向你展示了使用这些技术对你有益的工具。

    当谈到音频和视频转换和操作时,我们甚至还没有开始触及到您可以使用哪些工具来完成这项工作。有太多高质量的音频和视频工具了——我们大概可以写一整本书来谈论它们。你不必使用我在本章中建议的工具,我鼓励你做一些研究,找到最适合你的解决方案。

    十二、使用 AJAX 提升用户体验

    我们已经阅读了这本书的大部分内容,但是我们还没有明确地触及一个长期困扰网络用户,尤其是移动用户的问题:可怕的刷新!

    为什么可怕?正如我们所知,在移动世界中,速度就是一切。移动用户最不想做的事情就是重新加载整个网页。即使页面“较重”的方面缓存在用户手机上(比如图形、字体等。)手机的浏览器仍然必须将它们重新加载到浏览器中。这需要大量的时间、处理能力、电池电量和用户的耐心。谢天谢地,有一系列技术可以帮助我们,这就是 AJAX。

    什么是 AJAX?

    AJAX 代表异步 JavaScript 和 XML。我们来分解一下这个名字。第一个词,Asynchronous,乍听起来可能有点吓人,但是它是 AJAX 与众不同的关键。

    异步?

    大多数网页被编程为需要在发送/接收/显示系列中进行通信。用户按下 web 应用上的一个按钮,页面向服务器发送所需的信息,服务器发回一些响应,应用显示一个新页面,上面有该响应。如此往复,直到用户完成应用。每次用户与应用交互时,页面都会完全刷新。对某些人来说,这就是讨厌的定义。

    异步传输是指我们可以将这个链简单地分解为发送/接收/显示/发送/接收/发送/接收等等,而不是在每个连续的循环中包含显示部分。换句话说,我们可以在不加载新页面的情况下发送和接收数据。异步调用就是我们通过这种替代方法向 web 服务器发出的请求。举个例子,我们只需要在手机上访问谷歌的搜索引擎。我们从一个空白的搜索页面开始,如图 12–1 所示。

    images

    图 12–1。 谷歌搜索主页

    现在,假设是一大早,我想听一首很棒的歌曲开始我的一天,这首歌的背景是歌曲所讨论的一系列事件的图片。我可能会开始输入歌曲的名称,如图 12–2 中的所示,当我这样做的时候,谷歌正在使用异步调用来试图找出我在寻找什么。当我打字时,它会对照中央数据库检查每个字母,而不需要我刷新页面。然后在搜索栏下面显示这些建议。

    images

    图 12–2。 开始我的搜索

    在某个时候,在图 12–3 附近,建议与我正在寻找的整个短语相匹配,我可以简单地点击它。

    images

    图 12–3。随着我输入的越来越多,网页试图填写可能的查询。有趣的是,Android 操作系统也在试图弄清楚我在写什么——就好像它们都在试图读取我的想法!

    基本上,谷歌已经能够预测我在寻找什么,并给我一个直接访问这些搜索列表的捷径。当我点击符合我想要的建议时,它会将我带到我在 Figure 12–4 中看到的搜索结果。

    images

    图 12–4。 啊,我的结果——现在我可以听我一直在搜索的 flash 视频了

    在谷歌在搜索页面上推出这些异步调用之前,人们在搜索框中输入完整的查询,按下“搜索”,然后等待屏幕重新加载。如果查询中有错误,用户并不知道,直到新页面加载,谷歌指出来。这占用了用户的时间(加载不必要的页面)和谷歌的带宽。最近,谷歌通过异步运行整个搜索,将这种“帮助之手”又向前推进了一步——你可以输入你的查询,然后在同一个浏览器窗口中一个字母一个字母地更新搜索结果。

    那么 JavaScript 和 XML 呢?

    从技术上讲,AJAX 可以与任何客户端编程语言一起工作(客户端语言,如 JavaScript,在用户的浏览器中处理。服务器端语言,如 PHP,在 web 服务器上处理)。然而,由于 JavaScript 已经成为客户端语言的通用语言,所以它被广泛使用。XML 参与进来是因为它已经成为一种简单且易于理解的移动数据的方式。虽然您可以将其他技术混合到 AJAX 宴会中,但是在我们的示例中,我们将坚持使用 JavaScript 和 XML。

    既然我们已经确定了 AJAX 是什么,那么让我们来讨论一些将它整合到一些非常简单的应用中的巧妙方法。我们将从一个每日一词的例子开始,然后进入一个稍微复杂一点的例子,引用一个 web 服务和我们自己的本地数据库。

    今日 AJAX

    最近有报道称,2011 年的“年度词汇”是“务实”。这是因为一个词典服务网站发现它是那一年被查询次数最多的单词,因此它成为了冠军。也许你会说,“我一直想知道‘实用主义’是什么意思”(或者,“哪个白痴不知道‘实用主义’是什么意思?!?"),并想知道为什么我们没有更多的 Web 应用给我们带来这样的内容。好吧,今天是你的幸运日,因为你将要写一个。

    对于今日单词应用,我们将创建一个相当简单的机制来提供该单词。在本章的后面,我们将讨论如何使用 AJAX 从数据库或 web 服务中获取信息,但是现在我们将使用一个好的、老式的平面文本文件。恰如其分地命名为:

    清单 12–1。 word.txt

    <em>Pragmatic</em>: relating to matters of fact or practical affairs. <i>-<A HREF=http://www.merriam-webster.com/dictionary/pragmatic>Merriam-Webster.com</A></i>

    文件word.txt中有一些 HTML(在这种情况下,我们使用简单的样式标签,但是我们可以使用 CSS 主题的 div 语句),如果我们在 web 浏览器中加载它(图 12–5,我们会看到它显示为简单的文本:

    images

    图 12–5。 当日 word.txt 文件

    接下来,我将构建一个 HTML 页面,当用户按下按钮时,该页面将加载当日单词。从代码角度来看,它将类似于清单 12–2。我们会一步一步来。

    清单 12–2。word.html 的 ,第一部分:加载单词的初始 JavaScript 函数

    `

    Word of the Day 的新 JavaScript 函数,它将完成页面的大部分繁重工作。在这个函数中,我们首先需要弄清楚我们使用的是现代浏览器(即最近五年发布的浏览器,如 Firefox、Safari、Opera、Chrome 或更新版本的 Internet Explorer)还是旧的 Microsoft 浏览器(Internet Explorer 5 或 6)。原因很简单:旧的微软浏览器不知道什么是XMLHttpRequest()对象!对于他们,我们将要求创建一个 ActiveX 对象,这将为我们提供相同的功能。这只是对微软过去编写浏览器代码的一种有趣的妥协。让我们继续使用清单 12–3 中该页面的 JavaScript。

    **清单 12–3。**word.html,第二部分:JavaScript onreadystatechange 函数,以及 JavaScript 块的结尾

    `     request.onreadystatechange=function() { if ( request.readyState == 4 &&request.status == 200){ document.getElementById("theword").innerHTML = request.responseText; } }

              request.open("GET","word.txt",true);           request.send(); } `

    现在我们有了请求对象,恰当地命名为“request”,我们可以要求它做一些事情。代码的下一部分稍微“向后”写,因为写在顶部的代码将在写在底部的代码之后执行。这是因为 AJAX 的核心 XMLHttpRequest 对象有一个名为onreadystatechange的特殊函数。每当我们在后台处理请求时,无论是预期的还是意外的,它都会触发这个函数。本质上,这个函数是我们放置“我用我得到的东西做什么”代码的地方。你可以把这里的代码想象成“代课老师的指令”的编程等价物作为一个聪明的学生,你可能记得,当你的老师不在时,他或她会留下替换的说明,也许在一个特殊的文件夹里。您的onreadystatechange函数充当这些指令,告诉计算机(在这种情况下,JavaScript 引擎)当您不在身边但有事发生时该做什么。大多数情况下,这些指令与我们前面的指令相似(在本例中,“如果请求被正确处理,则在屏幕上显示它”)。我们还可以包括针对“最坏情况”的说明,比如当请求无法实现或者抛出错误时。

    在这个函数中,我们首先测试一下readyStatestatus是我们的请求。前者可以返回五个不同的数字,它们对应于请求的处理阶段。返回的代码

    • 0 表示请求尚未开始。这是发送新请求之前的状态。
    • 1 表示与服务器的连接已经初始化。本质上,管道是开放的,数据是移动的。
    • 2 或 3 分别表示请求已经发送并且正在处理。此时,您的代码所能做的就是坐着等待(或者显示一个“正在加载”的图形,如果您愿意的话)。
    • 4 表示请求完成并准备好代码。现在,您可以对这些信息做任何您想做的事情。我们只想在达到 4 的readyState时改变页面上的文本。

    我们还关心status,它可以报告 200(表示“OK”)或 404(表示“未找到”)。因此,清单 12–3 的第二行解释为:“只有当请求准备好并且成功完成时才这样做!”从这里开始,只需一行代码就可以将省略号或文本占位符(参见清单 12–4)更改为请求返回的文本。

    完成清单 12–3,我们正在创建并发送我们的请求。以request.open开头的行调用指定我们试图检索什么以及我们想要如何检索的函数。在这种情况下,这是一个非常简单的请求——我们只是获取数据,而不是发送任何我们希望服务器解析的数据。我们将使用“GET”方法而不是“POST”方法,因为这样更快,我们将请求“word.txt”,并且我们将 asynchronous 设置为“true”,因为我们希望在后台得到响应,从而允许脚本继续运行。关于我们为什么把它设置为 false 的讨论,以及 GET 和 POST 方法的更多细节,请参阅本章末尾的“AJAX 注意事项”一节。

    最后,我们简单地调用request.send(),它触发我们的请求。一旦我们得到请求,XMLHttpRequest 对象将触发我们的onreadystatechange并更改网页中的行。

    最后,我们通过创建基本的 HTML 结构来完成清单 12–4 中的页面。我们有一个特殊的div id叫做“theword ”,它以省略号(…)开始。这将被我们在顶部编写的 JavaScript 代码所取代。我们还有一个按钮,启动我们的功能loadword()

    **清单 12–4。**word.html,第三部分:页面的其余部分,由一个简单的正文部分和文本组成,以及“单词”部分

    `

    Get Today’s Word Of The Day

    ...

    Get The Word!` `
    `

    在 Android 网络浏览器上查看时,页面加载并显示默认状态(参见图 12–6)。

    images

    图 12–6。 当日单词示例第一页

    现在,当用户点击“获取单词!”按钮,省略号被替换为从word.txt中提取的当天的实际单词(参见图 12–7)。您还会注意到文本似乎缩小了一点——这是因为 AJAX 请求占据了整个‘theword’ <div>部分,包括通常会提供更多间距的<h2>标签。我特意这样做是为了指出,在考虑 AJAX 请求时,标记的嵌套很重要。将<h2>放在<div>外面可以保留空间。

    images

    图 12–7。 这个词现在已经放入页面,无需重新加载页面!

    成功!我们通过调用服务器改变了页面的内容,而没有真正重新加载页面。更好的是,如果用户点击浏览器上的“reload ”,我们将避免类似于 Figure 12–8 中的难看错误,因为我们实际上没有向服务器发送任何“POST”数据(传统意义上)。有关 POST 数据的更多信息,请参见本章末尾的“AJAX 注意事项”一节。

    images

    图 12–8。??【安卓确认重装】对话框

    现在,单词的基础已经完成,我们可以继续让它更漂亮一点(例如,使用前面提到的 CSS 方案)。不过,出于我们的目的,您现在应该对如何不仅通过 PHP(如前几章所示)而且通过 AJAX 包含平面文本文件有了很好的了解。我们的下一站?web 服务、XML 和 JSON 的奇妙世界。

    我的消息!

    我们的下一个例子调用了几个 web 服务来为我们提供不会存储在我们自己的设备上的内容。我们还必须对这个世界采取一种稍微以自我为中心的观点,但是,嘿,这是作为一名程序员的职责所在!

    假设我们有许多喜欢访问的网站,我们希望我们的应用显示这些网站的最新消息。为此,我们需要将这些网站的 RSS 提要集合在一起,合并它们,然后显示它们。我们希望列表在我们的页面上实时更新,无需用户干预。听起来很复杂?不尽然——如果你知道一些窍门的话!

    首先:创建管道

    雅虎!Pipes 是我最喜欢的网络服务之一(图 12–9,[pipes.yahoo.com](http://pipes.yahoo.com)),它没有被大多数博客或网站过多报道。但是它提供的服务非常棒——它可以将 RSS 源和其他数据缝合在一起,并以你选择的易于使用的格式提供它们。

    images

    图 12–9。 雅虎!管道主页

    而其他网站允许你把东西连接在一起(Dapper,另一个雅虎!属性和 ifttt (If This Then That)提供了更加可定制的“输出”,因此我们将在本例中使用它。首先,点击“创建管道”来加载管道编辑器,如图图 12–10 所示。管道编辑器允许您将一系列模块(在左侧)组织成一个逻辑规则结构。每个管道从一个或多个输入开始,然后使用模块对它们进行操作(例如,更改数据或合并数据),然后以各种形式输出结果。

    images

    图 12–10。 雅虎!管道编辑

    在左侧,您会发现一系列模块,您可以将它们拖入 Pipes UI。可以连接这些模块来执行您想要的操作。我要用三个模块——获取站点 Feed、Union、Truncate——把三个网站的 Feed 集合在一起,合并在一起,然后截掉五项之后的输出(图 12–11)。

    1. 获取网站提要获取网站的 RSS 提要的 URL。在这个例子中,我将为三个不同的网站获取三个 RSS 提要,并将它们链接在一起。你会注意到在图 12–11 中,我有三个“获取站点馈送”模块。
    2. Union 只是将最多五个输入组合成一个提要。这里,工会正在合并我输入的三个提要。如果需要的话,我可以有多个联合,通过“联合——连接”到一个联合来供给五个以上的管道,等等。
    3. Truncate 告诉 Pipes 我只想输出五个项目。这有助于加快响应时间,因为 Pipes 只需要导出几个项目,而不是多个提要可能提供的几十或几百个项目。这是我在管道输出模块之前连接的最后一个东西。

    images

    图 12–11。 完工的管道

    在调试器窗口中(Figure 12–12),我可以看到整个管道或沿途各个部分的输出。当我点击“管道输出”时,显示如下输出(在图 12–12)如果我点击了 Union,我会看到所有的提要条目,而不仅仅是 Truncate 命令后显示的五个条目。当调试管道以查看哪个组件可能导致问题时,这种中间级别的调试非常有用。

    images

    图 12–12。 我的管道的全部输出,假设我们已经在五个项目后截断了

    完成后,点击“保存”并给你的管道命名。然后点击“运行管道”查看输出(图 12–13)。

    images

    图 12–13。 我创作的书管

    你会注意到雅虎!管道为我提供了如何访问管道的选项。我可以将它作为 RSS 提要本身来访问,或者作为 JSON 结果输出来获取。在“更多选项”下,我还可以配置通过电子邮件或 PHP 获取结果。在这个例子中,我想得到 JSON 格式的结果。你应该还记得,在本书的前面,在第二章和第三章的应用中,我们已经使用了 JSON。这里,我们再次使用它来获取管道的输出。点击 JSON 按钮会给我一个相当难看的屏幕,里面全是内容,但这确实是我想要记住的 URL。它看起来有点像[pipes.yahoo.com/pipes/pipe.run?_id=0a1f972788e5ee484b335cb892fc85be&_render=json](http://pipes.yahoo.com/pipes/pipe.run?_id=0a1f972788e5ee484b335cb892fc85be&_render=json),可以通过我的 AJAX 网页调用它。

    第二:获取输出并显示!

    我们将修改我们的每日一词示例来提取 JSON 输出并显示它。虽然有更简单的方法可以做到这一点(最明显的是使用 JSON 的 getJSON 函数,并循环列表项),但是清单 12–5 中的代码更长一些,这使得更容易看到我们正在做什么来解析每个项。稍后,作为 JavaScript 技能的一种灵活运用,如果您愿意,可以使用 getJSON 重写这段代码。

    清单 12–5。mynews.html??

    `

    My News **** var lister = "";**              document.getElementById("thenews").innerHTML = lister;                }           }

    request.open("GET","pipes.yahoo.com/pipes/pipe.…);           request.send();  }

    Get the News!

    ...

    Get The News!
    `

    你会注意到,这段代码的大部分与我们在《今日一词》中使用的代码相同。值得注意的是,我们改变了一些东西,这些东西在我们的代码中是加粗的。

    • 我们已经将请求从word.txt更改为 Yahoo!管道 JSON 输出。
    • 我们现在使用 jQuery,这是一个我们以前使用过的库,它包含一些读取和解码 JSON 输出的有用函数。使用 jQuery 意味着我们必须在顶部添加对jquery-1.7.1.min.js文件的引用。
    • 我们现在使用jQuery.parseJSON来解析从 XMLHttpRequest 返回的文本。
    • 我们得到了一个 HTML 格式的列表,一旦检索到 JSON,就会显示出来。

    成品在我们的浏览器中是这样的(Figure 12–14):

    images

    图 12–14。 我的新闻应用

    当我们点击“获取新闻!”显示如下(图 12–15):

    images

    图 12–15。 新闻现已加载!

    现在我们已经从服务器加载了数据,从 web 服务加载了数据,我们可以开始最后一部分了:网页和数据库之间的来回交互。

    用户名可用性

    网站在过去几年中做的一件好事是“即时用户名可用性”字段。这是使用 AJAX 完成的,通过检查用户在“用户名”字段中输入的内容,同时检查它在数据库中的可用性。我们将使用 AJAX 创建这种体验,在后端使用 PHP 与 MySQL 数据库通信。这类似于谷歌对其即时搜索结果所做的,我们之前讨论过的功能。我们将从创建数据库开始,使用清单 12–6 中的模式。这个清单首先创建一个表,然后用几个测试用户名(“hardcore”、“恐龙”等)填充它。).

    清单 12–6。 用户表的 SQL 模式

    CREATE TABLE IF NOT EXISTS users (   name` varchar(25) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1;

    -- -- Dumping data for table users

    INSERT INTO users (name) VALUES ('hardcore'), ('dinosaur'), ('yelius'), ('tep');`

    使用前面的模式在 MySQL 数据库中创建 users 表。(MySQL 在[www.mysql.com/products/co…](http://www.mysql.com/products/community/)可用。)注意,您可以随意命名数据库,但是在本例中,它被称为“datab”现在我们需要一个简单的 PHP 脚本,它接受一个值并在数据库中检查它。清单 12–7 应该很好。

    **清单 12–7。**check _ name . PHP 脚本

    <?php $name = $_GET['u']; $user = "root"; $pass = ""; $server = "localhost"; $db = "datab"; mysql_connect($server,$user,$pass) or die("Can not connect"); mysql_select_db($db) or die("No such database"); $query = "SELECT * FROM userswherename = '$name'"; $result = mysql_query($query); if (mysql_num_rows($result) == 0) { echo "<font color=green>Available!</font>"; } else { echo "<font color=red>Not Available :( </font>"; } ?>

    前面的脚本相当简单。它连接到数据库并执行一个简单的查询,查看在多少行中输入了姓名。如果在任何行上都找不到该名称,那么它是可用的;脚本发回了“可用”(大概会有很多欣喜)。但是,如果它不可用,因为数据库中已经有一个包含该名称的行,那么脚本会返回一个更令人难过的“不可用”您可以通过访问 web 浏览器中的check_name.php脚本来测试这一点,包括带有某种测试用户名的&u=test。例如,在我的测试环境中,[localhost/~jon/uname/check_name.php?u=dino](http://localhost/~jon/uname/check_name.php?u=dino)返回“可用”,而[localhost/~jon/uname/check_name.php?u=dinosaur](http://localhost/~jon/uname/check_name.php?u=dinosaur)返回“不可用”如果这对你有用,那么你就可以继续了。

    后端完成后,我们现在将构建一个非常简单的表单,它将在用户输入时检查用户名,并告诉他或她所需的名称是否可用。

    我们将使用清单 12–8 中的代码来完成这项工作。

    **清单 12–8。**checkname.html页面

    `

    Registration Page

    request.onreadystatechange=function() {           if ( request.readyState == 4 && request.status == 200) {              document.getElementById("theres").innerHTML = request.response;                }           }

              request.open("GET","check_name.php?u=" + $name,true);           request.send();  }

    Register!

    ...

    ****
    `

    你会注意到,和上次一样,我们使用了与今日词汇相同的格式。这一次,我们更改了函数以接受一个参数(我们需要检查的名称),并且将按钮更改为一个文本字段。这个文本字段在每次释放一个键(onkeyup事件)时检查名称,并更新结果。加载后,页面看起来类似于图 12–16。

    images

    图 12–16。 查看用户名页面

    如果您输入一个开放的名称,如“跳过”,您将看到一条成功的消息,如图图 12–17 所示。

    images

    图 12–17。 甜蜜的胜利

    然而,如果你想要的用户名已经被某个了不起的人使用了,那么你将会看到一个悲伤的消息,比如图 12–18 中的消息。

    images

    图 12–18。 “不可用”屏幕

    在整个 web 表单中使用这种技术,不仅可以即时检查用户名,还可以验证信息,这样用户就不必点击“提交”按钮,却发现输入了无效的号码、电子邮件地址或用户名。

    在我们结束之前,有两个关于表单的快速提示可能会对您有所帮助。首先是考虑您希望将 AJAX 检查代码绑定到什么事件。在本例中,我们已经绑定到正在检查的表单字段上的onkeyup事件(用户名)。然而,这会导致每次按键时都有一个查找动作,这可能会使您的脚本陷入困境。另一种方法是将功能代码放在onfocus事件的下一个元素(例如,可能是一个密码字段)中,而不是放在onkeyup中。这将导致 AJAX 请求在用户移动到表单上的下一个字段后触发,从而减少负载。第二个考虑事项涉及表单的验证和自动提交。填写完最后一个字段后,让表单自动提交是很诱人的。毕竟,您可能会在用户输入信息时验证信息,所以为什么要让他们在完成最后一个字段后等待呢?这可能是一个问题,因为有些人可能希望在继续之前检查他们的答案。最好在页面上保留一个“提交”按钮,让用户在准备好的时候继续。

    AJAX 的注意事项

    在这个相对较短的章节中,我们使用的例子涵盖了在使用 AJAX 时要与之交互的三种主要数据类型。我们从服务器上获取数据,不经刷新就放入页面,我们查询 web 服务获取 RSS 标题,我们检查用户名以确保它们可用。至此,您已经拥有了编写利用 AJAX 功能的应用所需的基本工具。从这里开始构建时,有几件事情需要考虑,我们将在下面重点介绍。

    POST vs. GET

    您会注意到,在我们的例子中,我们一直使用 GET 方法而不是 POST 方法,如清单 12–3 和 12–4 所示。这主要是因为速度。GET 比 POST 快得多,因为它使用的格式更简单。如果您想知道为什么,这很可能是由于 GET 的原始意图——它被设计为只用于“等幂”数据。这仅仅意味着信息不能持久使用(也就是说,它应该只是一个查找值,而不是要输入数据库或以任何方式处理的数据)。

    然而,有些时候 POST 是合适的。首先,POST 没有 GET 的大小限制,所以如果您要向服务器传递大量信息,就需要使用 POST。其次,当您在服务器上更改某些东西(比如数据库更新)时,应该使用 POST,而不是引用静态或缓存的内容。简而言之,如果您正在传递不再需要的数据,请使用 GET。如果要传递应该处理或输入到数据库、电子邮件或文件中的数据,请使用 POST。

    使用 POST 比 GET 稍微复杂一些。您需要设置一个请求头,并通过 send 函数发送信息。这是因为 POST 数据编码在消息体中,而 GET 数据只是简单地附加在 URL 上。这就是为什么 Android 浏览器在 Figure 12–8 中提到重新发送 post data——它指的是这种特殊编码的消息。如果我们想将我们的用户名示例更改为使用 POST,我们可以更改以下几行:

    request.open("GET","check_name.php?u=" + $name,true); request.send();

    这一更改将导致清单 12–9 中的行。

    清单 12–9。 在用户名可用性示例中使用 POST

    request.open("POST","check_name.php",true); request.setRequestHeader("Content-type&","application/x-www-form-urlencoded"); request.send("u="+$name);

    我们还必须修改 PHP 脚本(参见清单 12–7,将第一行从$name = $_GET['u'];改为$name = $_POST['u'];

    设置异步为假?

    正如您在前面的例子中看到的,XMLHttpRequest 的open函数的第三个参数通常设置为“true”。这种方式是有意义的——毕竟,我们为什么要将它设置为 false 呢?答案是,我们很少会这样做!尽管如此,在某些情况下你可能会。例如,如果您正在编写一个脚本,并且您绝对不希望在请求被返回并准备好进行处理之前发生任何事情,那么可以将其设置为 false。我想到的一个例子是一个用户名检查表单,类似于图 12–16 中的表单,它应该只允许用户在用户名可用的情况下继续使用表单(也许可以基于它定制其他选项)。在这种情况下,可以禁用或隐藏所有后续的表单字段,然后等待请求返回;如果成功,则可以重新启用或显示这些字段。但是要注意的是,你的整个脚本将会被延迟,所以对大量的数据这样做并不是一个好主意。人们可以想象整个浏览器“卡住”了,这在任何平台上都是令人沮丧的事情,但在对速度的需求已经超过其可用性的移动设备上尤其令人烦恼。

    还要注意,如果您决定将 asynchronous 设置为 false,您不需要(也不应该使用)函数onreadystatechange。这是因为没有要寻找的就绪状态—请求就绪后,代码将继续处理。只需将剩余的 JavaScript 代码放在send函数之后,它就会按顺序处理。

    最后,在将 asynchronous 设置为 false 之前,您可能希望问问自己,对于您想要完成的任务,AJAX 是否真的是最佳解决方案。当然,它可能看起来很酷,但是如果你需要强迫用户等待,也许用不同的方式实现你的代码会更容易。例如:

    • 如果您的用户有可能禁用 JavaScript,要求 JavaScript 完成表单将会使页面对他们无用。使用异步设置为 true 的 AJAX 通常可以避免这个问题。
    • 在几个选项之后需要复杂验证(例如,数据库查找)的长表单可能更适合作为多页表单,允许用户在第一页创建一个帐户,然后在空闲时返回到后续页面。每个页面都可以保存表单的进度,允许用户跳回到需要的地方,同时还提供足够的验证。

    有了这些想法和您自己的测试经验,您不仅可以了解最好的表单提交方法 get 或 POST,还可以了解使用不常见的方法将 asynchronous 设置为 false 对您的脚本来说是否是个好主意。

    总结

    在这一章中,我们已经向前迈出了一大步,让我们的用户生活更加轻松。我们已经开始在后台对我们的表单或页面进行一些处理,这样用户就不需要刷新页面、提交表单或重新加载不必要的内容。通过在你的项目中,甚至在我们之前的例子中,实现这里概述的想法和概念,你将能够立刻创造出令人敬畏的“超级增压”设计!

    十三、打包您的应用

    因此,终于到了这一步:最后一章。在这本书里,我们回忆了过去的日子(也称为 20 世纪 90 年代),我们了解了 CSS3、HTML5 和 JavaScript 的神奇之处。我们玩了音频和视频。我们已经了解了使用 JavaScript 框架来提高我们的生产力并为我们的用户提供非常容易创建的页面布局的乐趣。我们甚至创建了一系列初学者应用,其中一个最终把你变成了一个国际神秘人,让你开始你未来的明星之路。希望在阅读完这本书之后,我们已经成功地强调了优化代码的重要性,并且在开发过程中要注意许多移动用户面临的有限带宽。

    然而,像所有美好的事物一样,我们的时代很快就要结束了。不过,在我们结束之前,我还有更多信息要告诉你。虽然我们已经完成并构建了一个有趣的应用库,但是我们仍然没有讨论在构建这些应用时应该做些什么!在这一章的其余部分,我们将涵盖从打包和压缩你的应用,让它们为互联网做好准备;选择一个合适的托管服务来存储你的应用;将您的文件传输到您使用的任何托管服务;甚至跳过整个托管服务解决方案,而不是将您可信赖的 HTML5 代码包装在 PhoneGap 或 Appcelerator 的 Titanium Mobile 之类的框架中,这样您的代码就像您的用户可以从 Android Market 安装在他们的设备上的原生应用一样工作!

    压缩应用

    现在,您已经完成了代码的编写并在本地开发环境中进行了测试,您可能很兴奋地将您的应用上传到互联网,并开始告诉您认识的每个人去查看它。在任何项目中达到这一阶段都是一项成就,但是仅仅因为你完成了代码并不意味着你没有任何工作要做。在这本书里,我一直试图强调聪明编码的重要性;做一些事情,例如使用 CSS3 来创建精彩的渐变效果,以及定制 web 字体(由 Google 的惊人的 web 字体目录提供)来代替图像或其他“沉重”的资源,如 Flash 电影。这些最终会帮助你的代码在用户的设备上快速加载。

    当然,我们正处于向任何想要的人提供全国范围的第四代移动互联网的尖端,但实际上,你的运营商的宽带服务有多快并不重要,因为移动网络严重缺乏延迟(在数据传输之前,你的手机与你试图加载的网站或服务进行通信所需的时间)。)为了帮助我们的代码更快地到达我们的用户,并反过来帮助减轻我们糟糕的 web 服务器的压力,我们将做一些通常被称为缩减代码的事情。缩小或压缩我们的代码包括通过一个应用或服务运行我们的 CSS 和 JavaScript 文件,该应用或服务将获取代码并删除所有换行符和不需要的空格,以使最终产品比以前小一点。

    什么是压缩?

    让我们再一次看看许多 web 开发人员使用的非常流行的 jQuery 框架。正如您在下面的图 13–1 中看到的,我们有两个版本的主 jQuery 库。该脚本的一个版本是未压缩的,重量高达 231KB,而另一个版本已经压缩并经过了一轮模糊处理,总重量降低到仍然很高,但更易于管理的 90KB。在代码编辑器中打开我们的 JavaScript 文档,我们可以立即看到两个文件之间的区别。如图图 13–2 所示,jQuery 的开发版本格式非常好,并且有一堆非常有用的注释,而 jQuery 的较小的生产就绪版本看起来就像一种奇怪的外星语言,几乎无法理解。看一看图 13–3 来更好地理解我指的是什么。这就是模糊代码的作用。我们不仅去掉了所有的换行符和漂亮的格式,而且代码本身也被压缩和处理,使代码模糊不清,更难理解。

    images

    图 13–1。 我们在这里检查两个不同版本的 jQuery 1.6.2 的文件大小

    images

    图 13–2。 在 Adobe Dreamweaver 5.5 中查看未压缩的 jQuery 脚本

    images

    图 13–3。 在 Adobe Dreamweaver 5.5 中查看压缩的、模糊的、陌生的 jQuery 代码

    有人可能会问为什么我们要隐藏代码——毕竟,难道我们不想让别人看到我们巧妙的技巧吗?嗯,在像这样的书里,我们当然知道,但是在现实生活中,把一些事情“藏在秘密里”会变得非常重要虽然模糊的代码不会阻止无畏的代码——读者猜出你所有的秘密(因此,永远不要依靠模糊的代码来保护诸如密码、信用卡号、核发射代码等。),它将阻止那些知识不多的人窃取你长期努力工作的代码,只是为了重用你整洁的过渡或酷的布局。

    压缩工具和实用程序

    trustyol 的互联网上有大量的程序可以帮助你使你的产品代码更小,减轻你的服务器和用户资源的负担。其中最受欢迎的是雅虎!sYUI 压缩机(图 13–4)。与其他一些压缩解决方案不同,YUI 压缩程序是一个用 Java 编写的应用,必须在您的开发工作站上运行。在运行应用并从命令行给它你想要的选项后,应用将获取你的代码,如我们所讨论的那样压缩它,甚至将你的许多不同的 JavaScript 或 CSS 文件合并成一个超级压缩的文档,准备好上传到你的服务器。你可以在[developer.yahoo.com/yui/compressor/](http://developer.yahoo.com/yui/compressor/)找到 YUI 压缩机。

    images

    图 13–4。

    使用 YUI 压缩器看起来有点吓人(当查看所有选项时,如图 13–4 所示),但它相当简单。例如,假设我想压缩“那条推特是谁?”中的main.js文件来自第二章的 app。首先,我会从网站上下载 YUI 压缩机。然后我提取文件,打开一个命令行窗口,切换到包含 Java JAR 文件的目录(在本例中是yuicompressor-2.4.7.jar;该名称会因版本而异)。接下来,我将复制我想要压缩的文件(到我的当前目录中)并运行压缩命令。我将使用的命令是:

    java -jar yuicompressor-2.4.7.jar main.js -o main.small.js

    这告诉 YUI 压缩器将main.js压缩成一个名为main.small.js的较小文件。在这种情况下,压缩程序将文件大小从 3,763 字节减少到 1,946 字节——略多于一半!

    还有一些其他压缩应用绝对值得一提。我想看的第一个是一个由狄恩·爱德华兹创建的叫做 Packer ( [dean.edwards.name/packer/](http://dean.edwards.name/packer/))的方便的小应用,如图图 13–5 所示。这个 web 服务将允许您将您的开发 JavaScript 复制到站点上的 textarea 字段中,只需快速点击一个按钮,就会显示出压缩的 JavaScript 代码,您只需复制并粘贴到一个空白的文本文件中,就可以上路了。如果你认为 YUI 对你的特殊需求来说可能有点多余,那么 Packer 可能是一个非常棒而且非常简单易用的替代品。

    然而,需要注意的是,虽然 Packer 是一个很好的压缩代码的工具,但是也很容易通过简单地禁用阻止您将代码粘贴到“复制”框并点击“解码”的 JavaScript 来隐藏这些代码!因此,应该将它简单地用作压缩器,而不是安全机制。

    images

    图 13–5。 使用 Packer 我们可以毫无痛苦地缩小我们的“那条推特是谁?”第二章的 JavaScript 代码,在顶部的文本区域,只占原始文档大小的一小部分,如底部的文本区域所示

    我想讨论的最后一个神奇的软件是一个代码和应用的小集合,叫做 HTML5 样板,由 Paul Irish 创建,在[html5boilerplate.com/](http://html5boilerplate.com/)找到。虽然它不是一个专门的压缩工具,但它是一个非常有用的框架,你可以考虑用于应用开发,它包括自己的压缩工具。HTML5 样板文件是一个非常年轻的项目(它于 2010 年 8 月 10 日推出),对于不想一遍又一遍地编写相同的旧基本代码的开发人员来说是一个很好的起点,因为它包含在他们创建的几乎每个项目中。有人喜欢将 HTML5 样板文件与框架混淆,但实际上远非如此。我更愿意把这个项目看作是一个组织结构和工具箱(图 13–6);它帮助您保持项目文件有序,并通过提供一种简单的方法来实现开发人员必须重复做的许多事情(例如指定某些文件、JavaScript 库等),让您避免重复工作。).

    images

    图 13–6。 一看 HTML5 样板文件的文件夹结构。所有神奇的压缩功能都发生在“build”文件夹中。

    在样板文件包中,目前是 2.0 版本,可以找到大量有用的项目和特性,比如已经编码好的index.html404.html文件的准系统框架布局;jQuery 的最新副本;一些预定义的 CSS 样式用于在浩瀚的互联网海洋中重置大量 web 浏览器的样式;在移动环境中使用的特殊优化;甚至还有一个漂亮的小代码压缩器,当您准备启动应用的生产版本时,它会为您压缩 HTML、CSS 和 JavaScript 文件。

    要用内置工具压缩你的文件,包括我们之前讨论过的像 YUI 压缩器这样的压缩器,你所要做的就是编辑位于构建目录中的build.xml文件(见图 13–7)。在这里,您会发现一系列选项,您可以指定将您的 web 应用压缩到您想要的内容。你可能需要一点时间来适应处理这个文件,但是一旦你按照你想要的方式设置好了一切,你所要做的就是运行runbuildscript.bat文件,你的代码将很快被压缩和优化。

    images

    图 13–7。 在 Adobe Dreamweaver 5.5 中配置 HTML5 样板构建设置

    寻找托管解决方案

    既然我们已经设法从代码中挤出了所有不需要的字节,使代码尽可能的小,那么是时候把这个美丽的东西上传到互联网上,让全世界都看到了。寻找一个适合你和你的项目的托管解决方案有时会是一件令人沮丧的事情,尤其是当你不确定你到底在找什么的时候。在这里,我们将谈论三个最大的托管公司,我们对他们的印象以及他们提供的功能。首先,让我们考虑一下选择宿主的过程。

    评估主机提供商

    并非每个提供商都是相同的,对一个开发人员有效的服务可能不适合另一个开发人员的需求。你需要了解提供商,明确自己的需求和目标。评估任何主机时,以下问题都是一个很好的起点:

    1. 我有多少个域名或子域名?当许多 web 开发人员开始工作时,最大的问题是,“我有多少空间?”或者“有多少传输量(你每个月可以发送的数据量,而不会产生超额费用——基本上就是你可以有多少访问者)?”。然而,现在大多数网站主机为初级程序员甚至一些高级程序员提供了充足的空间和转移。更大的问题可能是,提供了多少个域名(whatever.com)或子域名(something.whatever.com)?原因很简单:开发人员很少一次只有一个客户端。你可能会建立多个项目、多个客户端,甚至为你构建的应用或其他产品运行多个公共站点。你会希望每个品牌都不同,所以 newname.com 比 yourname.com/newname—更好,也更容易记住。
    2. 他们的技术支持响应速度如何?有常见问题或知识库吗?在我使用现在的网络主机的六年里,以及使用以前的十年里,我不得不给技术支持发五到十次电子邮件,询问各种各样的问题,从次要问题(“服务器是否支持…?”)到少校(“我所有的站点都瘫痪了。”).每次我都想立刻得到答复,尤其是后者,因为等待的时间太长了。不过更好的是,我目前的虚拟主机提供了一个非常好的 FAQ 和知识库,涵盖的内容远远不止如何重置密码或创建新的电子邮件帐户。它讨论了 PHP 版本、服务器软件、shell 访问等等。要点是:当你遇到麻烦时,你要确保信息已经可以帮助你,或者这种帮助是一封快速的电子邮件回复。
    3. **有哪些管理工具可用?**你会希望选择一个在你可以用账户做什么方面有足够可管理性的网络主机。有些主机可能希望您在每次需要设置一个新的域、数据库或其他任何东西时联系他们。其他人可能通过控制面板完全自动化这一过程。我倾向于后者,因为前者通常总是可用的。我现在的主机甚至允许我在网上取消域名或我的整个账户,如果我决定离开的话,就不用打一个尴尬的电话了。
    4. 如果我超出了我的计划,会发生什么?几年后,您可能需要访问更多功能或资源。接下来,在我们对 Dreamhost 的讨论中,我们注意到它提供了某些特性来“扩展”或“升级”你的包。如果你担心未来,你可以调查或询问潜在的主机对你来说改变计划或升级有多难。如果他们说您必须重新设置一切,您可能希望找到一个主机来为您迁移一切,或者简单地升级您而无需任何必要的更改。
    5. 我有 shell 和/或 CRON 访问权限吗?最后一条有点技术性,但如果你正在做一些开发工作,它可能很重要。Shell 访问或 shell 帐户是指您作为客户端以交互方式登录到主机服务器的能力。通常通过一种叫 SSH 的服务,shell 帐户可以让你直接在服务器上运行命令,就像现在你电脑上的命令提示符或终端窗口一样。CRON 是服务器上的一个特殊软件包,可以让您安排以后或定期运行命令。如果您创建一个需要定期自我检查的应用,比如一个向您的用户发送电子邮件的应用,这可能会非常有用。每隔 20 或 30 分钟,您可能需要自动运行一个脚本来检查是否有电子邮件要发送。CRON access 允许您这样做。然而,CRON 也可能被滥用,这就是为什么一些 web 主机不允许您使用它,或者根本不允许您交互登录服务器。

    除了前面的指导方针,当决定选择什么主机时,你也可以咨询评论网站。不过要小心:这些网站上一些过于热情或过于负面的评论可能并不代表实际的服务。在一天结束时,我们将永远相信我们知道真正使用过服务的人的建议,而不是粗略的评论,这就是为什么我们会很快花一秒钟来查看我们过去使用或工作过的一些主机提供商,以给你一个很好的起点,让你找到一个最适合你的。

    请注意,以下部分讨论了许多主机提供的功能,我们提到的特定主机只是我们个人使用过的主机。虽然我们显然对这些服务很满意,但我们从不认为它们适合所有人。拿起你在以下段落中读到的,考虑你的选择和价格范围,找到适合你的主机!

    梦幻主机

    在过去的六年里,我(罗科)个人一直是托管公司 Dreamhost ( [dreamhost.com/](http://dreamhost.com/))的超级粉丝,这是一家由四个雄心勃勃的计算机科学本科生在 1997 年创建的伟大的小公司(见图 13–8)。Dreamhost 已经存在了一段时间,虽然他们在过去经历了一些成长的烦恼,但他们为我提供的服务非常可靠,很少打嗝。他们的价格极具竞争力,通常每月 9 美元,他们甚至为客户提供无限的带宽和无限的存储空间。

    images

    图 13–8。自 1997 年以来,Dreamhost 已经在互联网上托管了数百万个网站。目前,他们有超过 500,000 个网站运行在 WordPress 开源内容管理解决方案上

    Dreamhost 提供了各种各样的主机,基本的主机形式是在一个共享的环境中。虽然共享主机对于基础项目来说很好,但是走这条路有一些主要的限制。首先,您正在与该服务器上的其他所有人共享一个环境,如果有人向服务器上传了一个脚本,该脚本设法占用了服务器的大量资源,甚至使服务器崩溃,那么该服务器上的所有人都会受到影响。最重要的是,您可以在共享服务器上执行的定制非常少。您不能安装在后台运行的自定义应用或服务,也不能对 web 服务器配置文件进行任何更改。

    如果你像我一样是个控制狂,你可能会考虑给自己买一台虚拟私人服务器或专用服务器。虚拟专用服务器基本上是一台运行在计算机内部的计算机。使用特殊的虚拟化软件,可以在安全的沙盒软件解决方案中模拟计算机的硬件,允许您在另一个操作系统中安装和运行整个操作系统,就像它是自己单独的计算机一样。当你从 Dreamhost 租用虚拟专用服务器(VPS)时,你仍然可以在与其他人共享的环境中使用它,但是你有巨大的优势,即受到沙箱保护,免受与你共享该物理服务器的任何其他人的有害行为。

    你不仅不用担心因为别人的疏忽而导致网站瘫痪,而且你的资源也得到保护。使用 Dreamhost 管理面板中的一个简单的滑块,您可以动态、实时地为您的服务器分配任意多的 RAM 和 CPU 处理能力(参见 Figure 13–9)。然而,给你的服务增加更多的 RAM 和 CPU 能力,确实会增加你的月租费;但是,如果您有一个应用,您知道它需要专用的 1GB RAM 和 CPU 能力来及时快速地为您的所有用户提供服务,那么知道这些资源会自动为您并且只为您提供保护是一件非常棒的事情。如果你有兴趣在 Dreamhost 上建立一个 VPS,它会给你提供第一周的免费服务,这样你就可以根据自己的需要调整服务器的大小,找到网站所需的最佳资源量。

    images

    图 13–9。

    Dreamhost 还让你可以选择拥有自己的专用环境。通常这些机器是相对强大的服务器,具有两到四个 CPU 核心,甚至高达 12GB 的 RAM。如果您是一名新的开发人员,您可能不需要那么多的处理能力,但是当有一天您确实需要它时,您现在知道去哪里找了。

    除了拥有大量的 Dreamhost 托管站点的选项外,您还可以访问一个反应非常迅速的技术支持团队。如果你有一个问题,或者在半夜你的服务器出了问题,在大多数情况下,你可以在几分钟内与技术人员进行文本聊天,并迅速解决你的问题。在我过去用过的所有托管公司中,当你需要帮助的时候,Dreamhost 是我最喜欢的公司之一。

    1 和 1

    转换作者(乔恩在这里),现在是时候听听我的网络主机在过去六年,1 和 1。1and1 实际上是一个相当大的主机,业内大多数人对它的评价都不冷不热。不是最好的(虽然谁是值得商榷),也不是最差的。Rocco 讨论过的 Dreamhost 提供的许多功能也可以从 1 和 1(以及许多其他主机,就此而言)中获得,因此我觉得最好简单地概述一下我认为 1 和 1 真正有用的部分。这分为两类:文档和可靠性。文档参考了 1 和 1 常见问题部分,让我惊讶的是,在一般问题中有我之前写的详细信息。我遇到了一个脚本问题,当 1and1 FAQ 网站上有关于服务器设置、PHP 版本和可用软件的非常具体的信息时,我感到非常惊讶。我能够调试我的问题,而不必写一封冗长、复杂的电子邮件。我真正喜欢 1 和 1 的第二个特点是我的服务的可靠性。虽然没有人可以吹嘘 100%的正常运行时间(服务器或服务可用的行业标准术语),但据我所见 1 和 1 非常接近。作为一个最底层的客户(也就是说,我每月支付大约 9 美元的基本共享主机包),如果我在这里或那里有不稳定的服务,我不会感到惊讶。事实上,相反的事情发生了——我在那里的整个时间里,我的网站一直保持正常运行。

    如果你正在考虑另一台主机,并想知道它的可靠性如何,你可能会在论坛上找到一个使用它的朋友或人,并询问他们的域名是什么。从那以后,我会建议在 Pingdom ( [www.pingdom.com](http://www.pingdom.com))这样的服务上建立一个免费账户,这是一个正常运行时间监控服务。Pingdom 可以让你免费监控一个网站,所以直接指向你朋友的网站吧。几周或几个月后,您将会看到一些报告,您可以参考这些报告来查看主机是否可靠地启动。

    现在,你知道了,1 和 1 对我来说是可靠和全面的。现在回到罗科来讨论最后一个主持人!

    媒体神殿

    我(Rocco)过去使用过的另一家托管公司,也是我在本章将与您讨论的第三家托管公司,是一家业界最喜欢的公司,名为 Media Temple ( [mediatemple.net/](http://mediatemple.net/))。从很多方面来说,对于更专业的用户来说,Media Temple 提供的服务可以被认为比 Dreamhost 更好。Media Temple 提供了大量的解决方案,首先是基本的网格服务器包(见图 13–10),它将您的站点托管在一个集群上,该集群由数百个其他服务器提供支持。它还像 Dreamhost 一样提供专用的虚拟服务器,以及各种非常强大的专用服务器。

    我对 Media Temple 的唯一真正问题是,它往往比 Dreamhost 等其他提供商贵一些,但它确实可以为你提供更好的硬件,以及与 Dreamhost 等公司一样的技术支持;所以,如果你正在寻找力量,一定要去看看媒体圣殿能提供什么。

    images

    图 13–10。 媒体寺的网格服务登陆页面

    文件传输协议

    现在,我们已经为您指出了寻找满足您需求的主机提供商的正确方向,我们必须将我们在本地开发服务器上创建的那些文件上传到我们全新的生产服务器上。这一步通常由文件传输协议(FTP)应用完成。FTP 是网络中的标准协议,用于将文件和文档从一台计算机传输到另一台计算机。在你的主机上有一个运行的 FTP 服务器,它允许你使用桌面或工作站上的 FTP 客户端连接到该主机。有很多免费的 FTP 程序,但是我个人最喜欢的是一个叫做 FileZilla ( [filezilla-project.org/](http://filezilla-project.org/))的免费开源软件,如图 13-11 所示。

    images

    图 13–11。 用 FileZilla 把这本书的代码转移到我的一个测试服务器上

    我喜欢 FileZilla 的主要原因之一是因为该软件不断更新,与这个项目相关的开发人员努力工作,以确保它是最快速和最稳定的 FTP 程序之一。

    使用 FTP 客户端实际上非常简单明了。一旦你注册了一个托管解决方案,你将获得证书,插入到你的应用中,一旦连接,如果你的 FTP 客户端支持该功能,你就可以拖放文件到服务器上你有权限访问的任何文件夹中。以下是一些 FTP 凭据的示例:

    url: ftp.myawesomesite.com user: testuser112 password: pssw0rdz port: 21 path: /var/www/myawesomesite.com/

    如果你以前从来没有这样做过,这可能看起来有点混乱。在下一节中,我们将从头到尾介绍一个应用的部署。

    使用安全 FTP 部署应用

    在这个例子中,我们将带你通过使用 SFTP 上传整个应用到一个虚拟主机服务。我们将在 Windows 机器上使用 FileZilla,但如果你使用的是 Mac,你可以使用一个由免费捐赠支持的名为 Cyberduck 的程序。步骤大致相同,尽管在 Mac 上屏幕会有所不同。

    首先,您需要收集以下信息:

    • 您的 web 主机需要的连接方法。一些网络主机不再支持 FTP,更喜欢加密版本,SFTP。你需要知道你的 FTP 地址(这通常是 ftp.yourdomainname.com,其中你的域名是你的个人域名,比如jonwestfall.com)、你的 FTP 用户名和 FTP 密码。
    • 您需要知道您的域的文件是否在您的 web 主机上的任何特定目录下。默认情况下,许多 web 主机会将您的 FTP 信息放入您的根目录(即,一旦您登录到服务器,您在“/”下看到的文件与您的域名下的文件相同。所以/test.txt对应[jonwestfall.com/test.txt](http://jonwestfall.com/test.txt)。其他主机可能会将您的文件放在一个以域名命名的目录中(即/jonwestfall.com)或一个名为/public_html/web的目录中。
    • 你还需要考虑你希望你的文件放在哪里。在这种情况下,我想要“那条推特是谁?”住在[jonwestfall.com/whosthattweet](http://jonwestfall.com/whosthattweet),所以我需要创建那个目录并将我的文件上传到那里。

    一旦你有了你需要的信息,下载并安装 FileZilla 客户端(从[filezilla-project.org/download.php](http://filezilla-project.org/download.php))。安装后,您应该在开始菜单的 FileZilla FTP 客户端组下找到它。打开 FileZilla,您应该会看到类似于 Figure 13–12 的屏幕。

    images

    图 13–12。 主 FileZilla 窗口没有任何配置

    你会注意到它很空,分成六个窗格。顶部窗格显示了 FileZilla 发送到服务器的 FTP 命令。左侧窗格显示您计算机上的文件(以树形格式列出您正在查找的目录中的文件),右侧窗格将显示您服务器上的文件(在我们连接后,以相同的排列方式)。底部显示了我们当前正在从一端传输到另一端的文件(从我们的计算机传输到服务器,反之亦然)。

    首先在顶部的主机框中输入您的 FTP 主机名、您的 FTP 用户名和您的 FTP 密码。如果您的主机支持 SFTP,这是更安全的方式,您将需要输入 SFTP 的端口号,通常在端口框中输入“22”。但是,如果您只能使用常规 FTP,您将使用 FTP 端口号,通常为“21”(注意:如果您的主机更改了这些值,这对于主机来说是非常罕见的,您应该能够在其 FAQ 部分或知识库中找到它们。输入所有信息后,按“快速连接”连接到服务器(图 13–13)。

    images

    图 13–13。??【SFTP】FileZilla 主机连接信息

    如果这是您第一次连接到此服务器,并且您正在使用 SFTP,您可能会看到以下对话框(图 13–14),要求您验证服务器身份。通常情况下,您不知道要验证什么值,但是您可能希望第一次就注意到它,以确保它总是相同的。这是一项安全功能,可确保您始终连接到正确的计算机。

    images

    图 13–14。 FileZilla 未知主机按键提示

    登录后,屏幕右侧的窗格会发生变化,显示服务器上的文件。点击文件夹,直到你找到你想上传文件的地方。在我的例子中,我将转到/new-jonwestfall.com目录(jonwestfall.com的 web 文件所在的位置)并创建一个whosthattweet目录。我可以通过双击右侧窗格中的new-jonwestfall.com,并右键单击文件旁边的空白区域来完成此操作。在出现的菜单中(图 13–15,我选择“创建目录”,在下一个窗口(图 13–16),我给它一个名字。

    images

    图 13–15。 右击显示上下文菜单,允许你创建一个目录

    images

    **图 13–16。**FileZilla【创建目录】对话框

    现在我确保我已经正确设置了目录:我想要移动的文件在左边,目标位置在右边,如图图 13–17。

    images

    图 13–17。 显示源(左边)和目标(右边)

    现在只需选择左侧的文件,右键单击它们,然后选择“上传”(参见图 13–18)。

    images

    图 13–18。 我现在可以点击“上传”选项将文件上传到服务器

    这样做之后,我应该在两个窗格中看到相同的文件,如图 13–19 所示。

    images

    图 13–19。 我电脑上的文件(左边)现在在服务器上(右边)

    现在大考验来了。现在可以访问这些文件了,我应该可以通过移动浏览器(或桌面)访问相应的地址来查看它们。在本例中,地址是[jonwestfall.com/whosthattweet/index.html](http://jonwestfall.com/whosthattweet/index.html)。通过在桌面网络浏览器中访问它,我可以看到文件是在线的,如图图 13–20 所示。这可能看起来很难看,因为这些文件是要在移动网络浏览器上查看的;但是,我们已经确认这些文件在线并且可以访问!祝贺您,您已经将您的项目上传到了网络上!

    images

    图 13–20。 游戏在桌面浏览器上无法正常渲染,但是这个测试验证了文件已经被正确上传

    软件版本化

    FTP 通常适用于只有一个开发人员的小型开发项目,尤其是当项目不是很复杂的时候。然而,举例来说,假设你正在和一个开发团队一起做一个项目,他们中的每一个人都可以访问 FTP 服务器,并且可以随时上传和修改文件。最终,您会遇到这样的情况:一个用户结束了对一个文件的更改,然后一分钟后有人上传了他们对完全相同的文件所做的更改,完全覆盖了第一个人刚刚上传的工作。

    这是一个非常令人沮丧的情况,在现实中,这种事情实际上是相当普遍的,并且在程序员没有组织的时候经常发生。防止这种情况的一个简单方法是使用某种形式的软件版本控制,比如 Subversion,来为您备份和控制文件。这样,假设 Jon 对我们共享的一个文件做了一些更改,而我意外地签入了该文件的一个新版本,其中没有 Jon 添加的代码。我们可以很容易地将文件恢复到它本身的早期版本,并保存我们认为已经丢失的代码,而不是惊慌失措。见鬼,使用版本控制,你甚至可以将一个文件的两个先前版本合并在一起,形成一个超级文件。

    有大量的版本控制解决方案等待使用,但是最流行的两个解决方案是 Apache Subversion ( [subversion.apache.org/](http://subversion.apache.org/))和 Git ( [git-scm.com/](http://git-scm.com/))。Subversion,也称为 SVN,已经存在了很长时间,是一个非常成熟的产品,在我过去使用的几乎每一个托管解决方案中都有广泛的支持。最好的部分是有一个非常漂亮的 Windows 应用,它将所有的 SVN 选项添加到你的右键菜单中,这将在帮助那些害怕使用命令行的新手开发者方面创造奇迹。

    尽管我很喜欢 SVN,但在过去的几年里,我越来越倾向于使用 Git 来满足我所有的版本需求。Git 是另一个用于版本控制的免费开源软件解决方案,与 SVN 相比,它的速度快得惊人,而且非常容易使用,如你在图 13–21 中所见。

    images

    图 13–21。 一个快速入门指南,通过几个简单的击键就可以开始使用 Git

    Git 也变得更加用户友好,因为它有一个非常受欢迎的网站 GitHub ( [github.com/](https://github.com/)),该网站将自己标榜为一个社交编码中心,利用 Web 2.0 的操作方式,让一切尽可能“社交化”(见图 13–22)。有了 GitHub,你可以免费将所有项目存储在 GitHub 云中;然后,您可以让其他开发人员派生或复制您的存储库,以便他们可以对其进行任何他们想要的更改,同时保持这些更改与您的工作完全分离。这有点噱头,但 Git 本身是一项非常棒的技术,如果你不喜欢,你可以学会忽略整个社交活动。

    images

    图 13–22。 使用社交编码 hub,GitHub

    最好将版本控制视为备份代码和应用的一种方式。事实上,即使您是项目中唯一的开发人员,最好也是在为应用创建第一个文件夹或文件时就对其进行版本化。这样,如果在此过程中发生任何事情,比如你的笔记本电脑爆炸,或者你的孩子觉得你的电脑看起来很渴,把它浸在苹果汁中,你将能够恢复代码,并将其下载到新的机器上继续工作。即使您的计算机没有爆炸,一旦您准备好将您的项目部署到您的服务器上,您所要做的就是登录并在提示符下运行一个简单的命令,将您的版本化程序的内容复制到您的生产服务器(即您的 webhost)上,而无需接触 FTP 程序。

    如果你的计算机老师像我成长过程中的老师一样,他们可能会反复强调不断保存你的作品的重要性。就像在大学里,当你不想在写一篇大文章的过程中被断电而失去一切时,确保经常保存你的工作,然后在版本控制解决方案中根据你的选择推出那些新的修订。

    本土化

    因此,现在我们已经构建了一个应用,通过压缩应用的永久生命优化了应用的大小,为自己找到了一个可接受的托管解决方案,并学习了如何使用 FTP、SVN 或 Git 将文件传输到该服务器——但如果您不想将应用打包,以便通过数据连接在互联网上使用,该怎么办呢?如果您正在构建一个应用,并且您知道该应用将用于没有任何数据覆盖的领域,该怎么办?如果您知道您的应用确实是资源密集型的,并且包含大量您不想等待加载到设备上的音频文件或图像,该怎么办?如果你的项目太棒了,你不想免费赠送,而是想卖给你的用户,怎么办?好吧,不要担心,因为我们有解决方案可以让你把难以置信的 HTML5 和 JavaScript 应用变成一个完全成熟的本地应用,可以在你的用户的手机上运行,而无需打开他们的互联网浏览器。

    最重要的是,通过让你访问手机的许多功能(如访问手机的联系人,或创建一个利用手机或平板电脑加速度计的游戏,或在手机的文件系统上创建文件),走原生路线为你开辟了许多事先不可用的途径。这些都是你在使用标准网络浏览器时通常不允许使用的功能,而且理由也很充分!如果有人能够从互联网上修改你的电脑、平板电脑或手机的文件系统,那将会是全球范围内的大规模恐慌。如果你认为现在的计算机世界存在病毒和木马的问题,想象一下,如果你访问了Amazon.com,一个愤怒的流氓开发者决定使用他的文件系统访问权限删除你计算机上的所有文件,会是怎样的情况?是的,我告诉过你,集体歇斯底里。这就是为什么你的浏览器被锁定了,正如我们在创建我们的 Twitter 应用时所讨论的“谁在发微博?”和“我爱火腿”

    然而,有时候需要这种访问,这就是 PhoneGap ( [www.phonegap.com/](http://www.phonegap.com/))和 Titanium Mobile ( [www.appcelerator.com/products/ti…](http://www.appcelerator.com/products/titanium-mobile-application-development/))等框架发挥作用的地方。这两个应用框架都允许开发人员将他们现有的 HTML5 和 JavaScript 代码转化为成熟的应用,可以上传到您选择的任何移动应用商店。虽然这两种产品都允许您将应用带入本机路径,但它们都以非常不同的方式实现,我觉得这值得一提。

    语音间隙

    PhoneGap 是一个免费的开源解决方案,就像许多流行的 web 开发解决方案一样,它在很短的时间内取得了很大的进步。PhoneGap 是由 Nitobi Software 在 2009 年 iPhone 开发营的 48 小时编码狂欢中创建的,它诞生了,并一直是希望进入移动开发领域而无需花费大量时间学习新编程语言的 web 开发人员的最爱。

    随着 Adobe Dreamweaver CS5.5 的最新发布,Adobe 已经将 PhoneGap 框架集成到 Dreamweaver 中,因此开发人员只需简单地单击鼠标,就可以创建一个本地应用,并在 Android 模拟器中进行测试(参见图 13–23)。与如此强大的开发力量的合作,让 PhoneGap 在“一次编写,随处运行”的移动领域比其竞争对手拥有巨大的优势。

    images

    图 13–23。 配置 Adobe Dreamweaver CS5.5,使用 PhoneGap 将我们的 HTML5 应用构建为原生应用

    让我们快速看一下来自 PhoneGap 示例的一些代码,在清单 13–1 中,这样你就能感受到如何构建你的 HTML5 PhoneGap 应用。

    **清单 13–1。**phonegagpexample

    `

    Training App
    PhoneGap Training App
    Show My Location
    Settings
    ` `

    This is where you are

    Go Back
    Map Type       Road Map
          Satellite
          Terrain
          Hybrid
    Zoom Level       Super Far
          Far
          Normal
          Close
          Super Close
    Save
    `

    正如您在前面的厨房水槽示例中看到的那样,这里发生的事情与您通常构建页面的方式没有什么不同。实际上,这是一个 HTML 文档,这也是 PhoneGap 与其竞争对手相比的不足之处。看,当在你的手机上使用 PhoneGap 应用时,即使该应用现在是本地的,并且可以以正常的互联网托管的 Web 应用永远不能访问的权限挂接到操作系统,你仍然只是在设备上加载网页。这在大多数情况下没问题,但在 Android 设备上,我们必须承认浏览器不像 iPhone 浏览器那样是硬件加速的;所以,如果你的应用中有很多花哨的效果和动画,它仍然会像在网络浏览器中查看时一样缓慢和呆滞。仅仅因为你以一种我们称之为“本机”的方式包装你的应用,它就不是真正意义上的本机。这就是我最喜欢的移动平台发挥作用:钛移动!

    钛金属手机

    多年来,我一直大力支持 Appcelerator 使用 Titanium Mobile 所做的工作。他们开始采取与 PhoneGap 相同的方法,允许用户用纯 HTML 和 JavaScript 创建内容,但很快意识到有时最好完全本地化以提高性能和速度。大约在 Titanium 移动软件成熟到生产就绪 1.0 版本的时候,Appcelerator 发布了一组新的 API,仍然允许开发人员使用 HTML5 在 web 视图中创建应用,但现在他们可以完全跳过 HTML5,用纯 JavaScript 创建他们的应用。

    这样,他们就能够在构建时获取这些 JavaScript 文件,并使用操作系统自己的代码将它们完全转换成真正的本地应用来生成页面布局。这意味着,你不用创建自己的按钮或样式来使用你的应用,而是可以通过为你正在使用的任何平台使用原生用户界面元素来使你的应用看起来更像一个真正的原生应用。

    为了不被集成到 Adobe Dreamweaver 中的 PhoneGapwith 超越,Appcelerator 的优秀人员购买了集成开发环境(IDE)公司 Aptana,并创建了他们自己的成熟 IDE,用于他们的框架。自从 Titanium Studio 在 2011 年初发布以来,使用 Titanium 移动环境已经变得轻而易举。

    虽然 Titanium Mobile 是一个开源项目,可以免费使用,但有一些特殊的模块只提供给付费用户。成为 Titanium Mobile 的付费用户有其额外的好处,比如可以提前获得 Titanium Mobile 的新版本,并使用一些模块来访问 AdMob 等公司的应用内广告 API 和 Paypal 的应用内购买 API。成为 Titanium Mobile 的订阅会员也很容易,免费基本会员和付费会员的起价为每月 49.99 美元。

    如果你能负担得起,并且想要访问某些模块,如 GameKit 和 OpenGL 游戏模块,那么跳基本的独立计划是显而易见的。如果你只是想摆弄软件,创建没有花哨模块的应用,那么你也可以免费这样做!有了 Titanium Mobile,你将能够使用纯 JavaScript 或 HTML5 和 JavaScript 的组合来创建真正令人难以置信的移动应用。

    images

    图 13–24。 钛金工作室 IDE,钛金手机官方集成开发环境

    关门时间

    既然我们已经经历了在移动开发世界中起步和运行所需的一切,是时候说再见了,关掉灯,慢慢走开,而远处某处的钢琴上正在播放 20 世纪 70 年代末电视节目 The Incredible Hulk 的主题曲。我们真的很高兴与你分享所有这些知识和信息,并希望你能在不久的将来使用它来把自己变成一个 10 级的网络巫师,并击败任何棘手的开发情况。我们确信你现在笑得合不拢嘴,准备跳上你的电脑,开始编写你的下一个项目,我们笑得合不拢嘴是因为我们为你感到兴奋;但是在今天离开你之前,我们要再次提醒你一点点 20 年前给罗科的友好建议——保持简单,笨蛋!

    感谢您花时间阅读这本书,如果您碰巧知道任何初露头角的开发人员可以从这本关于移动 web 开发的大部头的内容中受益,那么请随意将您的副本借给他们,并将这些知识和信息传递给其他人。保重,编码愉快!

    乔恩、罗科和格兰特