Apache Cordova 教程:使用 Cordova 开发移动应用程序
已发表: 2022-03-11移动应用程序无处不在,从智能手机和平板电脑到智能手表,很快也会出现在其他可穿戴设备中。 但是,为每个单独的移动平台进行开发可能是一项艰巨的任务,尤其是在您的资源有限,或者您是单个开发人员而不是移动应用程序开发公司的情况下。
这就是成为精通 Apache Cordova 开发人员可以派上用场的地方,因为它提供了一种使用标准 Web 技术(HTML5、CSS3 和 JavaScript)开发移动应用程序的方法。
2009 年,一家名为 Nitobi 的初创公司创建了 PhoneGap,这是一个用于访问本地移动资源的开源 API,其目标是使开发人员能够使用标准 Web 技术创建移动应用程序。 在 Nitobi 的设想中,大多数移动应用程序很快就会使用 PhoneGap 开发,但开发人员仍然可以在必要时选择编写本机代码,无论是由于性能问题,还是缺乏访问特定硬件的方法。
科尔多瓦PhoneGap?
没有这样的事,真的。 发生的事情是,Adobe 在 2011 年收购了 Nitobi,并将开源核心捐赠给了 Apache 软件基金会,后者将其重新命名为 Apache Cordova。 您经常遇到的一个常见类比是,Cordova 之于 PhoneGap,就像 WebKit 之于 Chrome 或 Safari。
显然,Cordova 和 PhoneGap 之间的差异在一开始是微乎其微的。 随着时间的推移,Adobe PhoneGap 开发了自己的一组专有功能,而 Cordova 曾经——现在仍然——得到开源社区的支持。 本 Apache Cordova 评论和教程将更详细地研究 Cordova 应用程序开发,虽然其中一些可能适用于 PhoneGap,但本质上不应将其视为 PhoneGap 教程。
Apache Cordova 功能
本质上,Cordova 对于本地开发的应用程序没有任何限制。 使用 Cordova 获得的只是一个 JavaScript API,它充当本机代码的包装器,并且跨设备保持一致。 您可以将 Cordova 视为具有 Web 视图的应用程序容器,它覆盖了设备的整个屏幕。 Cordova 使用的 Web 视图与本机操作系统使用的 Web 视图相同。 在 iOS 上,这是默认的 Objective-C UIWebView
或自定义的WKWebView
类; 在 Android 上,这是android.webkit.WebView
。
Apache Cordova 带有一组预先开发的插件,可以访问设备的相机、GPS、文件系统等。随着移动设备的发展,添加对附加硬件的支持只是开发新插件的问题。
最后,Cordova 应用程序就像本地应用程序一样安装。 这意味着为 iOS 构建代码将生成 IPA 文件,为 Android 构建 APK 文件,为 Windows Phone 构建代码将生成 XAP 文件。 如果您在开发过程中投入足够的精力,您的用户甚至可能没有意识到他们没有使用本机应用程序。
Apache Cordova 开发工作流程
使用 Cordova 进行开发时,您可以遵循两条基本路径:
- 当您打算将应用程序部署到尽可能多的平台时,很少或没有特定于平台的开发,您应该使用跨平台工作流。 支持此工作流的主要工具是 Cordova 命令行界面 (CLI),它用作更高级别的抽象,用于为不同平台配置和构建应用程序。 这是比较常用的开发路径。
- 如果您计划在考虑特定平台的情况下开发应用程序,则应使用以平台为中心的工作流程。 这样,您将能够通过将本机组件与 Cordova 组件混合,在较低级别调整和修改您的代码。 即使您可以使用这种方法进行跨平台开发,但过程会更长,更乏味。
通常建议从跨平台开发工作流程开始,因为切换到以平台为中心的开发相当简单。 但是,如果您最初从以平台为中心的工作流程开始,您将无法切换到跨平台开发,因为一旦您运行构建过程,CLI 将覆盖您的自定义设置。
先决条件和 Cordova 安装
在安装和运行与 Cordova 相关的任何内容之前,您需要为您打算为其构建应用程序的每个平台安装 SDK。 本文将重点介绍Android平台; 但是,涉及其他平台的过程是相似的。
您应该下载此处找到的 Android SDK。 对于 Windows,SDK 以安装程序的形式提供,而对于 Linux 和 OSX,它以存档的形式提供,可以简单地提取。 解压/安装软件包后,您需要将sdk/tools
和sdk/platform-tools
目录添加到PATH
变量中。 Cordova 使用PATH
变量来查找构建过程所需的二进制文件。 如果您没有安装 Java,您应该继续安装 JDK 和 Ant。 ANT_HOME
和JAVA_HOME
应设置为 JDK 和 Ant 的 bin 文件夹,安装 Android SDK 后,将ANDROID_HOME
变量设置为Android/Sdk
。 三个*_HOME
变量中的所有位置也应该在您的PATH
变量中。
安装 SDK 后, android
命令将在您的命令行中可用。 执行它以打开 SDK 管理器并安装最新的工具和 Android API。 您可能需要Android SDK 工具、Android SDK 平台工具、Android SDK 构建工具、SDK 平台、Google API 英特尔 x86 Atom 系统映像、Android SDK 源和英特尔 x86 仿真器加速器(HAXM 安装程序) 。 之后,您将能够使用android avd
创建一个模拟器。
Cordova CLI 依赖于 Node.js 和 Git 客户端,因此请继续从 nodejs.org 下载并安装 Node,从 git-scm.com 下载并安装 Git。 您将使用 npm 安装 Cordova CLI 本身以及安装其他插件,并且 Cordova 将在后台使用 git 以下载所需的依赖项。 最后,运行
npm install -g cordova
…全局安装 Cordova CLI( npm install cordova
本身是不够的。)
总而言之,这些是您将需要的软件包:
- 爪哇
- 蚂蚁
- 安卓 SDK
- 节点JS
- 吉特
这些环境变量需要更新:
-
PATH
-
JAVA_HOME
-
ANT_HOME
-
ANDROID_HOME
引导应用程序
如果您已成功安装 Cordova,您现在应该可以访问 Cordova 命令行实用程序。 打开您的终端或命令行,然后导航到您要创建第一个 Cordova 项目的目录。 要引导应用程序,请键入以下命令:
cordova create toptal toptal.hello HelloToptal
命令行由命令cordova
的名称和子命令create
组成。 使用三个附加参数调用该子命令:将放置应用程序的文件夹、应用程序的命名空间及其显示名称。 这会在具有以下结构的文件夹中引导应用程序:
toptal/ |-- hooks/ |-- platforms/ |-- plugins/ |-- www/ `-- config.xml
www
文件夹包含您的应用程序核心。 这是您放置所有平台通用的应用程序代码的地方。
虽然 Cordova 允许您轻松开发适用于不同平台的应用程序,但有时您需要添加自定义项。 在为多个平台开发时,您不想修改各种platforms/[platform-name][assets]/www
目录中的源文件,因为它们经常被顶级www
文件覆盖。
此时,您还可以打开config.xml
文件并更改应用程序的元数据,例如作者和描述。
使用以下方法添加您的第一个平台:
cordova platform add android
如果您稍后改变主意,您可以轻松地从构建过程中删除一个平台:
cordova platform rm android
检查平台目录后,您会注意到其中的android
文件夹。 对于您添加的每个平台,Cordova 将在平台中创建一个新目录并复制其中的www
文件夹。 例如,如果您想为 Android 定制您的应用程序,您可以修改platforms/android/assets/www
中的文件并切换到特定于平台的shell 工具。
但是,请记住,如果您使用 CLI(用于跨平台开发)重新构建应用程序,Cordova 将覆盖您为每个平台所做的更改,因此请确保您将它们置于版本控制之下,或者您执行特定于平台的操作完成跨平台开发后的变化。 正如我们前面提到的,从跨平台迁移到特定于平台的开发很容易。 朝另一个方向发展则不然。
如果您想继续使用跨平台工作流程并仍然进行特定于平台的自定义,您应该使用顶级合并文件夹。 从 Cordova 版本 3.5 开始,此文件夹已从默认应用程序模板中删除,但如果您需要它,您可以在其他顶级目录( hooks
、 platforms
、 plugins
和www
)旁边简单地创建它。
特定于平台的自定义放在merges/[platform-name]
中,并在顶级www
文件夹中的源文件之后应用。 这样,您可以为某些平台添加新的源文件,也可以用特定于平台的源文件覆盖整个顶级源文件。 以下面的结构为例:
merges/ |-- wp8/ | `-- app.js |-- android/ | `-- android.js |-- www/ `-- app.js
在这种情况下,Android 的输出文件将包含app.js
和android.js
文件,但 Windows Phone 8 的输出文件将仅包含在 merges merges/wp8
文件夹中找到的app.js
文件,因为merges/[platform]
中的文件会覆盖www
中的文件。
plugins 目录包含每个平台的插件的信息。 此时,您应该只有android.json
文件,该文件应具有以下结构:
{ "prepare_queue": { "installed": [], "uninstalled": [] }, "config_munge": { "files": {} }, "installed_plugins": {}, "dependent_plugins": {} }
让我们构建应用程序并将其部署到 Android 设备。 如果需要,您也可以使用模拟器。
Cordova 提供了几个 CLI 步骤来构建和运行您的应用程序: cordova prepare
、 cordova compile
、 cordova build
(这是前两个的快捷方式)、 cordova emulate
和cordova run
(它包含build
并且也可以运行模拟器)。 这不应该让您感到困惑,因为在大多数情况下,您希望在模拟器中构建和运行您的应用程序:
cordova run --emulator
如果需要,您可以通过 USB 端口插入您的设备,启用 USB 调试模式并将您的第一个 Apache Cordova 应用程序直接部署到您的设备上,只需运行:
cordova run
这会将您的所有文件复制到platforms/*
并执行所有必需的任务。
您可以通过指定要为其构建应用程序和/或什至特定模拟器的平台的名称来限制构建过程的范围,例如:
cordova run android --emulator
要么
cordova run ios --emulator --target="iPhone-8-Plus"
动手实践 Apache Cordova 教程
让我们创建一个简单的教程应用程序来演示 Cordova 及其插件的使用。 整个演示可以在这个 GitHub 存储库中找到,以便您可以下载它并通过这个简短的 Cordova 教程来浏览它的一部分。
我们将使用您创建的初始设置并添加其他代码。 假设我们想将新项目添加到虚构的 Toptal 数据库中,并查看现有项目。 打开 index.html 并按以下方式设置两个选项卡:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="format-detection" content="telephone=no" /> <meta name="msapplication-tap-highlight" content="no" /> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" /> <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" /> <link rel="stylesheet" href="css/jquery.mobile-1.4.5.min.css" /> <link rel="stylesheet" type="text/css" href="css/toptal.css" /> <title>Hello Toptal</title> </head> <body> <div> <div> </div> </div> <footer> <ul> <li class="tab-button active" data-tab="#search-tab">Search Projects</li> <li class="tab-button" data-tab="#add-tab">Post a Project</li> </ul> </footer> <div></div> <script src="js/lib/jquery-1.11.1.min.js"></script> <script src="js/lib/jquery.mobile-1.4.5.min.js"></script> <script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="js/SQLiteStorageService.js"></script> <script type="text/javascript" src="js/Controller.js"></script> <script type="text/javascript" src="js/index.js"></script> </body> </html>
请注意,我添加了 Bootstrap 和 jQuery Mobile 作为依赖项。 请注意,已经为构建现代混合应用程序开发了更好的解决方案和框架,但是由于大多数(如果不是全部)Web 开发人员都熟悉这两个库,因此将它们用于初学者教程是有意义的。 如果您愿意,可以从 GitHub 下载样式表或使用您自己的样式表。
让我们移动到index.js
文件,并将其剥离为以下内容:
var app = { // Application Constructor initialize: function() { if (navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/)) { document.addEventListener("deviceready", this.onDeviceReady, false); } else { this.onDeviceReady(); } }, onDeviceReady: function() { // We will init / bootstrap our application here }, }; app.initialize();
请记住,Cordova 应用程序所提倡的架构是设置单页应用程序 (SPA)。 这样,所有资源只在应用程序启动时加载一次,并且只要应用程序运行,就可以一直停留在 Web 视图中。 此外,使用 SPA,用户将不会有页面重新加载,这对于本机应用程序来说并不典型。 记住这一点,让我们设置一个简单的控制器来在两个选项卡之间切换:
var Controller = function() { var controller = { self: null, initialize: function() { self = this; this.bindEvents(); self.renderSearchView(); }, bindEvents: function() { $('.tab-button').on('click', this.onTabClick); }, onTabClick: function(e) { e.preventDefault(); if ($(this).hasClass('active')) { return; } var tab = $(this).data('tab'); if (tab === '#add-tab') { self.renderPostView(); } else { self.renderSearchView(); } }, renderPostView: function() { $('.tab-button').removeClass('active'); $('#post-tab-button').addClass('active'); var $tab = $('#tab-content'); $tab.empty(); $("#tab-content").load("./views/post-project-view.html", function(data) { $('#tab-content').find('#post-project-form').on('submit', self.postProject); }); }, renderSearchView: function() { $('.tab-button').removeClass('active'); $('#search-tab-button').addClass('active'); var $tab = $('#tab-content'); $tab.empty(); var $projectTemplate = null; $("#tab-content").load("./views/search-project-view.html", function(data) { $projectTemplate = $('.project').remove(); // Load projects here }); } } controller.initialize(); return controller; }
到目前为止,控制器有两种方法,一种用于渲染 Search View,另一种用于渲染 Post Project 视图。 让我们在index.js
文件中初始化它,首先在顶部声明它并在 onDeviceReady 方法中构造它:

// top of index.js var controller = null
// inside onDeviceReady method controller = new Controller();
最后,在index.html
的index.js
引用上方添加一个脚本引用。 您可以直接从 GitHub 下载 Search 和 Post 视图。 由于部分视图是从文件中读取的,因此某些浏览器(例如 Chrome)在尝试呈现您的页面时会抱怨跨域请求。
这里可能的解决方案是运行本地静态服务器,例如使用node-static
npm 模块。 此外,在这里您可以开始考虑使用一些框架,例如 PhoneGap 和/或 Ionic。 它们都提供了一系列开发工具,包括在浏览器中模拟、热重载和代码生成(脚手架)。
现在,让我们通过运行以下命令简单地部署到 Android 设备:
cordova run android
此时,您的应用程序应该有两个选项卡。 第一个选项卡允许搜索项目:
第二个选项卡允许发布新项目:
我们现在所拥有的只是一个在 Web 视图中运行的经典 Web 应用程序。 我们还没有真正使用过任何本机功能,所以让我们现在尝试这样做。 一个常见的问题是如何在设备上本地存储数据,或者更准确地说,使用什么类型的存储。 有几种方法可以去:
- 本地存储
- WebSQL
- 索引数据库
- 通过 Web 服务访问的服务器端存储
- 提供其他选项的第三方插件
LocalStorage 可以存储少量数据,但如果您正在构建数据密集型应用程序,它就不够了,因为可用空间从 3 MB 到 10 MB 不等。 对于这种情况,IndexedDB 可能是更好的解决方案。 WebSQL 已被弃用,并且在某些平台上不受支持。 最后,使用 Web 服务来获取和修改数据非常适合 SPA 范式,但是当您的应用程序脱机时它就会崩溃。 PWA 技术和 Service Worker 最近已进入 Cordova 世界以帮助解决此问题。
此外,还有许多额外的第三方插件可以填补 Cordova 核心的空白。 File 插件可能非常有用,因为它可以让您访问设备的文件系统,从而允许您创建和存储文件。 现在,让我们试试 SQLitePlugin,它为您提供本地 SQLite 数据库。 您可以通过运行将其添加到您的项目中:
cordova plugin add https://github.com/brodysoft/Cordova-SQLitePlugin
SQLitePlugin 为设备的 SQLite 数据库提供 API,并作为真正的持久性机制。 我们可以通过以下方式创建一个简单的存储服务:
SQLiteStorageService = function () { var service = {}; var db = window.sqlitePlugin ? window.sqlitePlugin.openDatabase({name: "demo.toptal", location: "default"}) : window.openDatabase("demo.toptal", "1.0", "DB para FactAV", 5000000); service.initialize = function() { // Initialize the database var deferred = $.Deferred(); db.transaction(function(tx) { tx.executeSql( 'CREATE TABLE IF NOT EXISTS projects ' + '(id integer primary key, name text, company text, description text, latitude real, longitude real)' ,[], function(tx, res) { tx.executeSql('DELETE FROM projects', [], function(tx, res) { deferred.resolve(service); }, function(tx, res) { deferred.reject('Error initializing database'); }); }, function(tx, res) { deferred.reject('Error initializing database'); }); }); return deferred.promise(); } service.getProjects = function() { // fetch projects } service.addProject = function(name, company, description, addLocation) { // add a new project } return service.initialize(); }
您可以从 GitHub 下载用于获取和添加项目的代码,并将其粘贴到相应的占位符中。 不要忘记将 SQLiteStorageService.js 添加到 Controller.js 上方的 index.html 文件中,并通过修改 Controller 的 init 函数在控制器中对其进行初始化:
initialize: function() { self = this; new SQLiteStorageService().done(function(service) { self.storageService = service; self.bindEvents(); self.renderSearchView(); }).fail(function(error) { alert(error); }); }
如果您看一下 service.addProject(),您会注意到它调用了 navigator.geolocation.getCurrentPosition() 方法。 Cordova 有一个地理定位插件,您可以使用它来获取手机的当前位置,您甚至可以使用 navigator.geolocation.watchPosition() 方法在用户位置发生变化时接收更新。
最后,让我们添加控制器事件句柄,以便从数据库中添加和获取项目:
renderPostView: function() { $('.tab-button').removeClass('active'); $('#post-tab-button').addClass('active'); var $tab = $('#tab-content'); $tab.empty(); $("#tab-content").load("./views/post-project-view.html", function(data) { $('#tab-content').find('#post-project-form').on('submit', self.postProject); }); }, postProject: function(e) { e.preventDefault(); var name = $('#project-name').val(); var description = $('#project-description').val(); var company = $('#company').val(); var addLocation = $('#include-location').is(':checked'); if (!name || !description || !company) { alert('Please fill in all fields'); return; } else { var result = self.storageService.addProject( name, company, description, addLocation); result.done(function() { alert('Project successfully added'); self.renderSearchView(); }).fail(function(error) { alert(error); }); } }, renderSearchView: function() { $('.tab-button').removeClass('active'); $('#search-tab-button').addClass('active'); var $tab = $('#tab-content'); $tab.empty(); var $projectTemplate = null; $("#tab-content").load("./views/search-project-view.html", function(data) { $('#addressSearch').on('click', function() { alert('Not implemented'); }); $projectTemplate = $('.project').remove(); var projects = self.storageService.getProjects().done(function(projects) { for(var idx in projects) { var $div = $projectTemplate.clone(); var project = projects[idx]; $div.find('.project-name').text(project.name); $div.find('.project-company').text(project.company); $div.find('.project-description').text(project.description); if (project.location) { var url = '<a target="_blank" href="https://www.google.com.au/maps/preview/@' + project.location.latitude + ',' + project.location.longitude + ',10z">Click to open map</a>'; $div.find('.project-location').html(url); } else { $div.find('.project-location').text("Not specified"); } $tab.append($div); } }).fail(function(error) { alert(error); }); }); }
要添加控制台和对话框插件,请执行以下命令:
cordova plugin add org.apache.cordova.dialogs cordova plugin add org.apache.cordova.console
cordova.console 插件将通过在模拟器中启用console.log()
功能来帮助您进行调试。
您可以通过 Chrome 远程调试器轻松调试 Android 应用程序。 连接设备后,单击右上角(X 按钮下方)的下拉菜单,展开更多工具,然后单击检查设备。 您应该会在列表中看到您的设备,并且应该能够打开其调试控制台。
Safari 为调试在 USB 连接的设备或模拟器上运行的 iOS 应用程序提供了相同的功能。 只需在 Safari 设置 > 高级选项卡下启用开发人员工具。
cordova.dialogs 插件启用本机通知。 一种常见的做法是使用 cordova.dialogs API 以下列方式重新定义windows.alert
方法:
overrideBrowserAlert: function() { if (navigator.notification) { // Override default HTML alert with native dialog window.alert = function (message) { navigator.notification.alert( message, // message null, // callback "Toptal", // title 'OK' // buttonName ); }; } }
应该在deviceready
事件处理程序中调用overrideBrowserAlert
函数。
您现在应该能够添加新项目并从数据库中查看现有项目。 如果您选中“包括位置”复选框,设备将调用 Geolocation API 并将您的当前位置添加到项目中。
让我们通过设置图标和启动画面来为应用程序添加点睛之笔。 将以下内容添加到您的config.xml
文件中:
<platform name="android"> <icon src="www/img/logo.png" /> <splash src="www/img/logo.png" density="mdpi"/> <splash src="www/img/logo.png" density="hdpi"/> <splash src="www/img/logo.png" density="xhdpi"/> </platform>
最后,在www/img
文件夹中放置一个徽标图像。
您自己的 Cordova 应用程序
我们完成了 Apache Cordova 应用程序开发的基本步骤,并使用了我们自己的 JavaScript 架构和 CSS 样式表。 本 Cordova 教程试图展示 Apache Cordova 作为一种使用熟悉技术开发移动应用程序的方法的潜力,从而减少开发时间和为不同平台构建多个应用程序所需的工作量。
但是,在构建将要投入生产的应用程序时,建议您使用现有框架。 除了在预定义的体系结构中构建您的应用程序之外,这还可能为您提供一组组件,这些组件将帮助您的应用程序更接近原生的外观和感觉。 一些值得注意的框架是 Ionic、Framework7、Weex、Ratchet、Kendo UI 和 Onsen UI。 祝你好运!