使用 Jo 和 PhoneGap 构建本地移动应用程序
移动 web 或移动应用程序?
移动应用程序开发基本上可以分为两类:web 或本地。移动 web 应用程序开发与传统 web 开发差不多,区别在于前者针对移动平台。您的应用程序存储在 web 服务器上并由其提供服务,然后由移动 web 浏览器消费。可以预料到,浏览器上可供使用的资源和功能非常有限。将这一点与本地开发相比,后者使您能够利用移动操作系统的核心特性。因此,移动 web 应用程序开发鼓励您使用浏览器,而本地移动应用程序开发鼓励您使用移动操作系统。
构建本地移动应用程序为开发人员带来了更多的可能性。过去,您需要掌握多种语言和应用程序编程接口(API),在多个平台上构建移动应用程序。现在,您再也不需要这样做了。
本文将介绍 Jo 和 PhoneGap 的基本用法。Jo 是一个轻量级框架,提供广泛的跨平台支持,并与其他框架实现了良好的集成。PhoneGap 对于构建本地应用程序非常关键,因为它的作用类似于一个桥梁,能够利用移动平台的所有核心特性,同时保留面向 HTML、CSS 和 JavaScript 代码的开发环境。
Jo 是什么?
Jo 是一种新框架,由 Dave Balmer 从 Palm 开发而来。它是一种极为轻量级的 HTML5 移动 web 应用程序框架,提供丰富的平台支持,包括 HP webOS、Apple iOS、Android、Symbian,甚至是 Mac OS®X Dashboard 小部件。尽管 Jo 目前仍然在积极的开发当中,但是它十分适合进行移动 web 应用程序开发。它的大小和特性集非常友好,使您能够将注意力放在核心概念上。
Jo 有哪些功能?
下面的例子将构建一个简单的基于卡的布局,展示 Jo 的一些重要特性,帮助您快速开始开发应用程序。
开始
首先,确保拥有一个合适的支持 HTML5 的浏览器,将其作为开发环境。Safari 和 Chrome 是两个最适合 Jo 开发的浏览器。使用这些浏览器提供的控制台调试脚本,设置断点并转储数据以供检查。其次,从 GitHub(参见 参考资料)下载 Jo 源代码并提取到您的本地 web 服务器的根目录。将提取后的目录重命名为更具体的名字,例如 Jo。现在,浏览 Jo 的示例页面 http://localhost/jo/samples/test.html,将看到类似 图 1 所示的屏幕。
图1.JoKitchenSinkDemo
现在,您已经下载并解压缩了 Jo,下一步是构建自己的 Jo 应用程序。首先在您的 web 根目录中创建两个文件:index.html 和 application.js。index.html 文件包含 清单 1 所示的代码。
清单1.样例应用程序的索引页面
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>My First Jo App</title> <!-- jo styles --> <link rel="stylesheet" type="text/css" href="jo/css/jo.css" /> </head> <body> <!-- jo framework script --> <script src="jo/js/jo.js"></script> <!-- our application script --> <script src="App.js"></script> <script> // initializes jo jo.load(); // our app initialization code App.init(); </script> </body> </html> |
清单 1 显示了一个索引页面,可用于组织和调用您的脚本和样式。如果以前开发过 JavaScript 应用程序的话,那么应该对该页面很熟悉。文档头部包含支持 Jo 的默认样式;文档主体中包含脚本。注意,jo.js 文件也包含在其中。该版本的框架尚未进行缩减,适合进行开发。当准备好部署到生产环境时,将 jo_min.js 文件包含进来即可。文件的末尾是 jo.load()
语句,该语句的作用是初始化 Jo 框架,然后初始化 App.init()
表示的代码。清单 2 显示了初始化代码。
清单2.样例应用程序的初始化代码
// demonstrates the javascript module pattern var App = function() { // private members var init = function() { alert("the app is initialized"); }; // returns an object literal of members to be made public return { init: init }; }(); |
构建 Jo 布局
现在您已经具备了一个外壳,只需要稍加修改来生成一个基本的 Jo 布局,如 清单 3 所示。该布局是一个简单的主-细(master-detail)模式的开头部分。
清单3.使用Jo构建布局
var App = function() { var deviceScreen; var mainContainer; var mainNavBar; var mainMenu; var cardStack; var menuCard; // initialization function var init = function() { // create the main container mainContainer = new joContainer([ mainNavBar = new joNavbar("My First Jo App"), cardStack = new joStackScroller() ]).setStyle({position: "absolute", top: "0", left: "0", bottom: "0", right: "0"}); // create the device screen deviceScreen = new joScreen(mainContainer); // hook up the nav bar with the card stack mainNavBar.setStack(cardStack); // create a menu card menuCard = new joCard([ mainMenu = new joMenu([ { title: "Go to form", id: "form-card" } ]) ]); // add the menu card to the card stack cardStack.push(menuCard); }; // public members return { init: init }; }(); |
Jo 直到这时候才真正发挥威力。首先,定义若干变量来表示应用程序中的一些关键资源,比如设备屏幕、卡布局管理和导航。主要布局通过创建 joContainer
管理,它有一个导航栏(表示为一个 joNavbar
对象)和一个卡管理机制(表示为一个 joStackScroller
对象)。该容器被添加到设备屏幕并填充所有可用的空间。mainNavBar.setStack(cardStack)
语句用于将卡槽绑定到导航部件,从而自动管理卡之间的导航。最后,创建一个 joCard
实例并添加到卡槽,该实例包含一个菜单 — 一个漂亮的列表。成功执行这段代码后,将生成一个类似 图 2 的屏幕。
图2.呈现的Jo布局
高级布局技巧
对列表布局进行配置后,继续创建细目卡并将它们连接起来,如 清单 4 所示。
清单4.使用joCache
的高级布局
var App = function() { var deviceScreen; var mainContainer; var mainNavBar; var mainMenu; var cardStack; var menuCard; // initialization function var init = function() { // ... same code here as listing 3 // register click handler for menu mainMenu.selectEvent.subscribe(function(id) { cardStack.push(joCache.get(id)); }); // initialize the card cache initCardCache(); }; // initializes the cache used to store cards // this helps us only use what we need when we need it var initCardCache = function() { // create the form card joCache.set("form-card", function() { return new joCard([ new joLabel("Name:"), new joInput(), new joLabel("Password:"), new joPasswordInput(), new joLabel("Description:"), new joTextarea(), new joLabel("Options:"), new joOption([ "Option 1", "Option 2", "Option 3" ]), new joLabel("Toggle:"), new joToggle(true), new joLabel("Selection:"), new joSelect([ "Item 1", "Item 2", "Item 3" ]), new joButton("Submit") ]); }); }; // public members return { init: init }; }(); |
清单 4 中给出了两个重要的概念。第一个是创建一个名为 initCardCache
的新函数,该函数利用了 Jo 的缓存特性。缓存条目添加了一个字符串 ID(唯一标识符)和一个函数(条目值)。该函数返回一个新构建的 joCard
,使用 Jo 框架的表单控件配置。通过这种方式应用 joCache
,可以在您的应用程序中推迟细节视图的对象创建,从而实现更好的性能。第二个概念是使用一个事件处理程序将列出的卡与细节视图连接起来。当选中菜单中的某个项目后,将使用菜单项的 ID 从缓存中检索视图。虽然您在这里只能定义一个视图,但是这种模式可以很轻易进行扩展。
单击 Go to form 列表项,将看到类似 图 3 所示的屏幕。
图3.Jo表单控件示例
注意屏幕左上方的 Back 按钮。这是通过绑定前面提到的卡槽和导航部件实现的。现在,将空表单连接到数据源。
Jo 中的数据源
Jo 提供了许多方法来管理信息存储库,如 WebKit SQLite 和 HTML5 数据库。然而,最简单、最有用的数据管理类是 joRecord
,可以使用该类作为表单的接口,如 清单 5 所示。
清单5.绑定表单数据与joRecord
var App = function() { // ...same as listing 4 var formRecord; // initialization function var init = function() { // ... same as listing 4 }; // initializes the cache used to store cards // this helps us only use what we need when we need it var initCardCache = function() { // create the form card joCache.set("form-card", function() { // initialize the persistent form record formRecord = new joRecord({ name: "Nigel Bitters", password: "somepassword", description: "Some long winded description here.\nWith a line break!", option: 1, isActive: true, selection: 2 }); return new joCard([ new joLabel("Name:"), new joInput(formRecord.link("name")), new joLabel("Password:"), new joPasswordInput(formRecord.link("password")), new joLabel("Description:"), new joTextarea(formRecord.link("description")), new joLabel("Options:"), new joOption([ "Option 1", "Option 2", "Option 3" ], formRecord.link("option")), new joLabel("Toggle:"), new joToggle(formRecord.link("isActive")), new joLabel("Selection:"), new joSelect([ "Item 1", "Item 2", "Item 3" ], formRecord.link("selection")), new joButton("Submit").selectEvent.subscribe(function() { // dump out the modified data console.dir(formRecord); }) ]); }); }; // public members return { init: init }; }(); |
在 initCardCache
函数中,创建了一个 joRecord
实例,它的作用是初始化表单值和管理对表单作出的修改。图 4 展示了值的初始化过程。
图4.表单中的初始化值
运行 清单 5 中的示例,修改表单数据,然后单击 Submit 按钮。检查浏览器的控制台,应当可以看到修改后的表单记录。
您已经使用了创建有效的移动 web 应用程序所需的主要特性。下一步是通过添加 PhoneGap 构建一个本地移动应用程序。
PhoneGap 是什么?
PhoneGap 是一个开源框架,用于使用 HTML 和 JavaScript 代码构建本地移动应用程序。它可以将您的用户界面与目标移动平台的操作系统绑定在一起。PhoneGap 支持 iPhone、Android、Blackberry、Symbian 和 Palm 等平台。PhoneGap 提供的本地特性 — 如加速器访问、相机和媒体支持、联系人、地理定位、文件、网络和存储 — 也十分适合移动应用程序的开发。
接下来构建一个针对 Android 平台的联系人应用程序示例。首先,配置开发环境。
运行 PhoneGap,如果以前只从事过纯 web 开发,那么运行起来会有一点复杂。表 1 列出了运行 PhoneGap 所必需的软件需求。
表1.PhoneGap软件需求
软件描述Eclipse集成开发环境(IDE)构建和运行PhoneGap应用程序Java开发工具箱(JDK)包括Java编译器和支持工具Android软件开发包(SDK)包括运行应用程序所需的基本库和模拟程序Android开发工具(ADT)访问Eclipse开发插件ApacheAnt管理项目构建流程Ruby管理PhoneGap中的各种任务,例如项目创建
本文没有涵盖配置开发环境的全部过程。然而,参考资料 提供了一些配置工具。首先,遵循 Android 开发人员网站中的安装 SDK 文档进行操作,这将涉及表 1 中列出的前四个需求。接下来,下载并安装 Apache Ant 和 Ruby。
此时,所有主要组件已经就绪。您拥有一个可以加载、构建和运行 PhoneGap 项目(Eclipse)的 IDE 以及所有支持工具。最后,需要做一些配置工作。
在构建期间,需要在系统中定义大量环境变量,如 表 2 所示。
表2.环境变量
变量描述ANDROID_HOME
指向AndroidSDK在计算机上的根位置ANT_HOME
指向ApacheAnt在计算机上的安装根位置JAVA_HOME
指向JDK在计算机上的根位置PATH
定义AndroidSDK安装目录下Ruby、Ant、JDK的bin文件夹以及工具文件夹的路径
最后,在 Eclipse 中定义一个 Android Virtual Device (AVD)。AVD 是一组配置选项,可以对由 Android 驱动的设备建模,对于在 Android 模拟程序上运行 PhoneGap 应用程序非常关键。要创建 AVD,打开 Eclipse 并导航到 Window > Android SDK and AVD Manager。将看到类似 图 5 所示的屏幕。
图5.AndroidSDK和AVDManager
选择左侧菜单中的 Virtual Devices 项并单击 New… 按钮。输入信息,如 图 6 所示,然后单击 Create AVD。关闭 Android SDK 和 AVD Manager 后,您就可以加载、构建和运行 PhoneGap 项目了。
图6.创建新的AndroidVirtualDevice(AVD)
运行 PhoneGap 示例项目
为 PhoneGap 配置开发环境有一点复杂,但是加载项目则简单许多。要运行您的第一个 PhoneGap 应用程序,从 GitHub 中将最新的 phonegap-android 项目包下载并提取到您的计算机(参见 参考资料)。接下来,打开命令提示行并将目录修改为 PhoneGap 安装的根目录。运行命令,如 清单 6 所示。
清单6.创建PhoneGap项目的命令
./bin/droidgap create example |
该命令在示例文件夹中从 web 源文件创建了一个 Android 项目。要在 Eclipse 中加载项目,导航到 File > New > Project…。进入到Android 文件夹并选择 Android Project,然后单击 Next >。配置项目,如 图 7 所示,然后单击 Finish。
图7.项目设置的屏幕截图
源位置为 PhoneGap 安装目录中的 example_android 文件夹。这就是用 droidgap
命令创建项目文件的位置。现在项目已被加载到 Eclipse 项目浏览器中,进入到 libs 文件夹,右键单击 phonegap.jar 文件并选择 Build Path > Add to Build Path,如 图 8 所示。
图8.将phonegap.jar加入到构建路径
在 Eclipse 中以 Android 应用程序的方式运行应用程序时,应当看到类似 图 9 所示的屏幕。
图9.在Android模拟程序中运行的PhoneGap示例应用程序
将 Jo 添加到 PhoneGap
您也许已经注意到,尽管必须完成许多步骤才能启动和运行 PhoneGap,但是该框架的用法与任何其他现代 JavaScript 框架没有什么不同。现在,您可以针对使用 Eclipse 的 Android 创建、构建和运行 PhoneGap 应用程序。您可以轻松地添加一些 Jo 来管理您的用户界面。事实上,Jo wiki 站点提供了一个简单的索引文件,其中包含推荐的配置,如 清单 7 所示。
清单7.使用PhoneGap的示例索引页面
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>My App</title> <!-- stylesheets --> <link rel="stylesheet" href="css/aluminum.css" type="text/css"> <link rel="stylesheet" href="css/chrome.css" type="text/css"> <link rel="stylesheet" href="css/myapp.css" type="text/css"> </head> <body> <!-- lib --> <script src="phonegap.js"></script> <script src="js/jo_min.js"></script> <!-- app --> <script src="js/myapp.js"></script> <script> jo.load(); joEvent.touchy = true; MyApp.load(); </script> </body> </html> |
清单 7 提供了一个类似的格式,因为文档头部包含了样式表。文档主体首先包含链接的框架脚本,其次是应用程序脚本文件。您尚未使用到 joEvent.touchy = true
。这个属性确保所有相关的基于鼠标的事件都被转换为可以在移动设备上使用的接触式事件。
结束语
尽管结合使用 Jo 和 PhoneGap 可以完成许多工作,但要记住,Jo 和 PhoneGap 两者之间不是互相依赖的。它们可以独立使用或与其他框架结合。然而,Jo 的简单性和轻量级与 PhoneGap 的强大功能相结合,最终将生成一个有效的工具,可以针对广泛的平台开发丰富的移动本地应用程序。