可以选择三种方式来开发移动应用,它们各有特点:
所谓混合应用,就是结合了前两者的特性和优势的应用,混合应用可以分为两种风格:
混合应用具有以下特性:
Apache Cordova是一个开源移动应用开发框架,它允许你使用标准的Web技术——HTML5、CSS3、JavaScript ——来进行跨平台开发,避免使用各移动平台Native的编程语言和SDK。基于Cordova的应用程序被包装在各平台的Wrapper中,使用标准兼容的API访问设备传感器、数据和其它Native特性。
Apache Cordova 工程依赖于一个命名为config.xml的配置文件,该配置文件影响应用程序的工作方式(例如是否对横屏做出响应)。
应用程序本身实现为网页,默认情况下是本地的一个index.html文件,该文件可能引用任何Web资源,例如JavaScript、CSS。应用程序被包装在Native的Wrapper中,作为WebView运行。该WebView作为更大的混合(Hybrid )应用的一个组件,或者占据整个UI。
插件接口(plugin interface )允许Cordova和Native组件之间进行通信,插件接口以JavaScript的形式提供,从而允许在网页上调用Native代码。理想情况下,各平台的API应该一致,在3.0中,官方插件提供标准化的设备API,而第三方插件可能提供一些特定于特殊平台的API。Cordova官方提供了自定义插件的开发文档。
从3.0开始,新创建的Cordova工程默认不包含任何插件,所有插件都需要手工添加。
Cordova 应用的开发工作流有两种:
推荐以第1种方式开始,使用CLI创建Cordova工程,在必要时切换到第2种方式。针对平台的低级别Shell工具可以在工程的platforms/*/cordova 目录下找到(其中*代表平台名称)。一旦切换,就不能返回,因为CLI管理的跨平台源代码集会在每次构建时被覆盖。为了保护你修改过的代码,必须使用平台特定的Shell工具,这些Shell工具忽略跨平台代码而依赖于平台特定的代码。
使用Cordova的命令行接口(CLI),可以完成新工程的创建、针对各平台进行构建、并部署到设备(或模拟器)中运行。
在安装和使用CLI前,必须下载和安装相关目标平台的SDK和相关工具,如果不安装,在调用CLI进行应用构建时会收到错误提示,例如:
#没有安装完整Android SDK机器上的报错信息 Running command: cmd "/s /c "...\cordova-study\platforms\android\cordova\build.bat"" [Error: Please install Android target: "android-22". Hint: Open the SDK manager by running: D:\Android\sdk\tools\android.BAT You will require: 1. "SDK Platform" for android-22 2. "Android SDK Platform-tools (latest) 3. "Android SDK Build-tools" (latest)] ERROR building one of the platforms: Error: cmd: Command failed with exit code 2 You may not have the required environment or OS to build this project
CLI支持的目标平台(构建平台)包括:
可以看到如果要支持全部主要的目标平台,你需要在不同操作系统上运行CLI命令,这意味着你应该使用代码库(SVN/Git)来管理工程。
# 安装Cordova为全局模块 npm install -g cordova #安装特定版本的Cordova npm install -g cordova@3.1.0-0.2.0 #更新Cordova npm update -g cordova #显示版本信息 cordova -v
执行下面的命令创建工程:
pushd D:\JavaScript\projects\cordova\5.4.1 # cordova-study在当前目录下创建的子目录,作为工程文件的容器 # cc.gmem.study.cordova 域名反转的包名,可能被生成的外部文件引用,例如Android包名 # CordovaStudy 应用程序的标题 # 第2/3个参数可以在config.xml中手工修改 cordova create cordova-study cc.gmem.study.cordova CordovaStudy
命令执行完毕后,生成如下目录结构:
目录/文件 | 说明 |
hooks | Cordova钩子脚本的存放目录 |
platforms | 生成的平台特定的文件,包括工程代码和元数据。基于CLI的跨平台工作流进行开发时,应该避免修改此目录下的任何文件 |
plugins | 应用程序使用的插件目录 |
merges | 用于合并到各平台assets/www中的文件,特定于平台的文件,按照www的结构,在此目录下存放,在构建时会自动合并 |
www | 存放应用程序的主页面(index.html),以及css、js、img等Web资源。这些资产内容会存放在设备的本地文件系统,而不是远程Web服务器上。开发Cordova应用的主要工作在此目录下进行 |
config.xml | 包含了用于生成和分发应用程序的重要元数据 |
运行下面的命令添加对特定平台的支持:
#添加Android平台的支持 cordova platform add android #输出如下: Running command: cmd "/s /c "...\create.bat ...\cordova-study\platforms\android cc.gmem.study.cordova CordovaStudy --cli"" Creating Cordova project for the Android platform: #创建目标平台工程特定的文件 Path: platforms\android Package: cc.gmem.study.cordova Name: CordovaStudy Activity: MainActivity Android target: android-22 Copying template files... Android project created with cordova-android@4.1.1 #安装插件 Discovered plugin "cordova-plugin-whitelist" in config.xml. Installing to the project Fetching plugin "cordova-plugin-whitelist@1" via npm Installing "cordova-plugin-whitelist" for android #添加iOS平台的支持,需要在安装了iOS SDK的Mac OS X上执行 cordova platform add ios #添加Windows Phone 8平台的支持,需要在Windows上运行 cordova platform add wp8 #下面的命令示例了如何移除平台的支持 cordova platform remove blackberry10 #添加指定版本的cordova平台支持,并保存到config.xml中 cordova platform add android@3.7.0 --save
运行上述命令后,Cordova工程的platforms、plugins子目录出现一些下载/生成的文件:
目录 | 子目录 | 说明 |
platforms/android | . | 当前目录包含了一个完整的Android工程,可以导入到Android Studio或者ADT中 |
cordova | 特定于Android平台的Shell工具,可以完成Android平台应用的构建、清理、运行 | |
CordovaLib | 一个Android工程,包含了作为Android库的Cordova源代码 | |
assets |
遵循Android工程的默认用途 其中:
|
|
src | ||
libs | ||
res | ||
plugins | 存放下载的对应各目标平台的插件源代码、文档 |
前面我们说过,创建新工程可以从CLI命令行开始,在必要时切换到特定平台的开发工作中去。在此,就可以进行切换了:只需要把platforms子目录导入到Eclipse、XCode等IDE即可,然后以IDE为中心完成后续开发。
如果继续执行以CLI为中心的工作流,则需要继续了解下面的小节。
执行下面的命令可以构建应用程序的二进制文件并打包:
# 构建所有平台 cordova build # 构建特定平台 cordova build ios
上述build命令实际上包含了两个步骤:
# 准备阶段,会把Cordova源码拷贝、合并到平台的对应目录中 # 一旦执行完该命令,就可以用特定平台提供的SDK进行修改、编译 cordova prepare ios # 编译 cordova compile ios
运行下面的命令重新构建特定平台的应用,并部署到模拟器中:
# 运行下面的命令后,Cordova会自动启动模拟器,并把APK安装到上面 # 如果有模拟器正在运行,则使用既有的模拟器 cordova emulate android # APK安装完毕后,将自动运行
或者,将启用了调试模式的手机连接到当前计算机,然后运行:
cordova run android
你可以使用Web技术修改Cordova生成的应用骨架,来开发漂亮的页面。但是如果想使用设备底层特性,则必须添加插件,利用插件可以访问核心Cordova API。第三方/自己开发的插件可以用来访问特殊的设备特性,要访问通用设备特性使用Cordova提供的的插件就足够了。官方插件和第三方插件的列表位于http://cordova.apache.org/plugins/。
下面的命令用来搜索插件:
#同时包含bar和code的插件 cordova plugin search bar code
下面的命令用来列出当前工程已添加的插件:
cordova plugin ls
下面的命令用来移除已经添加的插件:
cordova plugin rm cordova-plugin-console
下面的命令用来给应用程序添加插件:
#依据插件ID添加 cordova plugin add plugin-id #添加特定版本的插件 cordova plugin add plugin-id@latest cordova plugin add plugin-id@1.2.0 # 设备基本特性 cordova plugin add cordova-plugin-device # 网络连接信息 cordova plugin add cordova-plugin-network-information # 电池状态 cordova plugin add cordova-plugin-battery-status # 加速度计 cordova plugin add cordova-plugin-device-motion # 横屏切换 cordova plugin add cordova-plugin-device-orientation # 地理位置信息 cordova plugin add cordova-plugin-geolocation # 摄像头 cordova plugin add cordova-plugin-camera # 媒体截屏 cordova plugin add cordova-plugin-media-capture # 媒体回放 cordova plugin add cordova-plugin-media # 访问设备或网络上的文件 cordova plugin add cordova-plugin-file cordova plugin add cordova-plugin-file-transfer # 通过振动或者对话框通知用户 cordova plugin add cordova-plugin-dialogs cordova plugin add cordova-plugin-vibration # 访问通讯录 cordova plugin add cordova-plugin-contacts # 国际化 cordova plugin add cordova-plugin-globalization # 启动画面支持 cordova plugin add cordova-plugin-splashscreen # 打开新的应用内浏览器窗口 cordova plugin add cordova-plugin-inappbrowser # 调试控制台 cordova plugin add cordova-plugin-console
CLI根据需要为各平台添加插件代码。Plugman可以为单个平台添加插件支持。
如果插件没有在默认源(registry.cordova.io )注册,通过下面的命令添加:
# 从Git的master分支下载插件 cordova plugin add https://github.com/someone/aplugin.git # 从特定标记或者分支下载插件 cordova plugin add https://github.com/someone/aplugin.git#r0.2.0 # 如果插件(以及plugin.xml)在Git仓库的子目录下,可以 cordova plugin add https://github.com/someone/aplugin.git#:/sub/dir # 也可以从本地文件系统添加插件 cordova plugin add ../local_plugin_dir
前面提到过,在以CLI为中心的跨平台开发工作流下,不应当修改platforms子目录。那么,如果如何实现平台差异化呢?例如为不同平台提供不同的样式表.css文件,这是很合理的需求。
Cordova提供了一种合并机制,在工程顶级目录下,可以添加一个merges目录,其子目录是各平台的名称,例如merges/android 。这些子目录的内部结构和www目录一样,在构建时,会自动覆盖www中的文件,并最终拷贝到特定平台的资产目录下。举例来说:merges/android/css/index.css 会覆盖Android平台下对应的www/css/index.css 文件。
merges中的文件如果在www下没有对应物,会直接复制到特定平台的资产目录下。
命令格式:cordova 子命令 [选项]
选项 | 说明 |
-v, --version | 打印CLI版本 |
-d, --verbose | 显示CLI命令的活动的详细信息 |
--no-update-notifier | 禁止检查CLI的版本更新 |
子命令 | 说明 |
create | 创建一个新的Cordova工程 |
help | 显示命令帮助:
# 显示run子命令的帮助信息 cordova run --help |
子命令 | 说明 |
info | 显示当前工程的详细信息,例如哪些平台被支持,添加了哪些插件 |
requirements | 检查并显示指定平台的要求,例如SDK版本 |
platform |
管理工程支持的平台: |
plugin | 管理工程使用的插件: add 添加一个插件 remove 移除一个插件 list 列出当前安装的插件列表 search 从插件仓库搜索插件 |
prepare | 拷贝、合并工程文件到目标平台,以备构建 |
compile | 编译目标平台,命令格式: cordova compile [PROD] [TARGET] [EXP] [PLATS] [-- POPTS] PROD:编译的变体, --debug|--release |
build | 等价于cordova prepare && cordova compile |
clean | 清除已经构建出的构件(artifacts) |
run | prepare、compile,并在设备或者模拟器上运行工程: --nobuild 不进行构建 --debug 部署Debug版本 --release 部署Release版本 |
emulate | 等价于cordova run --emulator |
serve |
启动一个本地HTTP服务器,把工程作为Web服务使用: 此命令启动的服务与PhoneGap Developer App无法搭配使用,可以改用: phonegap serve |
首先,参考文章:基于Eclipse ADT和Maven的Android开发 完整Android开发环境的搭建。
由于Android平台官方的开发工具现在是Android Studio,并且基于Gradle构建,所以最好搭建好Gradle环境和Gradle的Eclipse插件。可参考文章:Gradle学习笔记。
通过CLI创建Cordova工程后,一旦添加了Android平台的支持,就可以把platforms/android子目录作为工程导入到Eclipse ADT或者Android Studio。
以Eclipse ADT为例,操作步骤为:
这两个工程就是普通的ADT工程。其中cordovalib是cordova-android的依赖库。在cordova-android上点击右键 ⇨ Run as ⇨ Android Application,即可打包并部署到设备上运行。
上述方式导入的工程结构比较混乱,如果后续开发脱离Cordova进行,建议清理其中不需要的目录和文件。如果不习惯基于Gradle进行构建,可以创建或者转换为Maven工程。
安装了Gradle的Eclipse插件后,可以把platforms/android子目录转换为Gradle工程:
如果习惯于使用Maven进行构建工作,可以参考下面的步骤,把platforms/android子目录转换为Maven工程:
target bin .* cli
mklink /D %MVN_PROJECT_ROOT%\cli %CORDOVA_PROJECT_ROOT%
<dependency> <groupId>org.apache.cordova</groupId> <artifactId>cordova-android</artifactId> <version>4.4.1-SNAPSHOT</version> <type>apklib</type> </dependency>
task syncdown_src(type : Copy){ from 'src' into '../../../src/main/java' } task syncdown_assets(type : Copy){ from 'assets' into '../../../src/main/assets' } task syncdown_res(type : Copy){ from 'res' into '../../../src/main/res' } task syncdown_libsrc(type : Copy){ def dest = '../../../../cordova-android/src/main/java' if(file(dest).exists()){ from 'CordovaLib/src' into dest } } task syncdown_manifest(type : Copy){ from 'AndroidManifest.xml' into '../../../src/main' } task syncdown( dependsOn: [syncdown_src, syncdown_assets, syncdown_res, syncdown_libsrc, syncdown_manifest] )
@echo off call cordova prepare pushd platforms\android call gradle syncdown popd
这会让所有修改从Cordova工程目录,同步到其Android平台子目录,然后再同步到Maven工程对应目录中。
Android平台特定的命令行工具位于platforms/android/cordova 子目录中,这些命令比Cordova CLI更有针对性,在以Android为中心的开发时,可以代替之:
### 构建工程 ### #Apache Cordova CLI方式 cordova build android #Android平台命令行工具 platforms/android/cordova/build --debug #生成调试信息 platforms/android/cordova/build --release #对应用进行签名 #其它参数 # --ant 使用Ant进行构建 # --gradle 使用Gradle进行构建,Cordova 4.0以后的默认值 # --nobuild 不进行构建 # --prepenv 不进行构建,但是拷贝必要的构建脚本 # --versionCode=# 指定本次构建的版本号 # --minSdkVersion=# 指定本次构建要求的最低Android SDK版本代码 # --gradleArg=# 指定传递给Gradle的命令行参数 # --buildConfig 指定包含了构建配置的JSON文件 ### 部署到模拟器 ### # 需要首先配置并启动一台Android模拟器 #Apache Cordova CLI方式 cordova emulate android #Android平台命令行工具 platforms/android/cordova/run --emulator platforms/android/cordova/run --target=targetId #指定特定ID的模拟器 #当执行run时,默认会自动构建,可以通过参数-debug --release --nobuild控制此行为 platforms/android/cordova/run --emulator --nobuild #通过Eclipse部署 #也可以在Eclipse中,Run As - Android Application方式部署应用 ### 部署到真实设备 ### #Apache Cordova CLI方式 cordova run android #Android平台命令行工具 platforms/android/cordova/run --device ### 其他Android平台命令行工具 ### platforms/android/cordova/log #记录APP详细的运行日志 platforms/android/cordova/clean #清理工程文件
使用Android命令行build、run时,可以通过--buildConfig 传入一个JSON,为构建提供配置信息。下面的JSON提供了APK签名所需的信息:
{ "android": { "debug": { "keystore": "android.keystore", "storePassword": "android", "alias": "mykey1", "password" : "password", "keystoreType": "" }, "release": { "keystore": "android.keystore", "storePassword": "", //Release的密码可以不写,等待命令行提示 "alias": "mykey2", "password" : "password", "keystoreType": "" } } }
自4.0开始Gradle是Cordova默认的构建工具。
下表列出Cordova提供的Gradle工程属性,可以用于定制构建:
属性 | 说明 |
cdvBuildMultipleApks |
默认值:false,表示为所有平台生成一个通用的大的APK 如果设置为true,对library projects支持的每个平台(x86, ARM...)分别生成一个APK。如果工程使用大的Native库时很重要,因为Native库可能大大增加APK体积 |
cdvVersionCode | 覆盖AndroidManifest.xml中的versionCode |
cdvReleaseSigningPropertiesFile |
默认值:release-signing.properties 包含Release版本APK签名需信息的属性文件的名称,属性文件的内容示例如下: storeFile=relative/path/to/keystore.p12 storePassword=SECRET1 storeType=pkcs12 keyAlias=DebugSigningKey keyPassword=SECRET2 #密码是可选的,如果不提供,构建时会进行交互式的提示 |
cdvDebugSigningPropertiesFile |
默认值:debug-signing.properties 包含Debug版本APK签名需信息的属性文件的名称 |
cdvBuildToolsVersion | 覆盖自动检测到的android.buildToolsVersion属性值。该属性由Android的Gradle插件引入 |
cdvCompileSdkVersion | 覆盖自动检测到的android.compileSdkVersion属性值。该属性由Android的Gradle插件引入 |
如果需要扩展Gradle构建逻辑,可以创建一个build-extras.gradle 文件,并在其中编写脚本。该脚本会自动被包含在build.gradle 的首部。注意避免修改build.gradle本身,该文件是自动生成的,可能被Cordova覆盖。下面是扩展脚本的一个例子:
# 此文件的内容被放在build.gradle的开始处 # 设置工程扩展属性 ext.cdvDebugSigningPropertiesFile = 'android-debug-keys.properties' # 这里指定的闭包,会在build.gradle结尾处执行, 因为build.gradle的最后包含如下代码: # if (hasProperty('postBuildExtras')) { # postBuildExtras() # } ext.postBuildExtras = { android.buildTypes.debug.applicationIdSuffix = '.debug' }
有两种方式来打包Cordova应用,并部署到Android设备或者模拟器上测试:
注意,必须让你的设备或者模拟器链接到当前机器上。
这两种方式都比较慢,每次部署都需要数十秒,非常浪费时间。因此可以使用PhoneGap提供的设备端工具,该工具可以免部署的运行Cordova应用。
应用启动后,会自动启用一个WebView,加载config.xml中指定的起始页(默认index.html),让HTML页面占据整个屏幕空间。
例如,对Android平台,系统会执行MainActivity,该Activity是CordovaActivity的子类:
public class MainActivity extends CordovaActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 加载HTML loadUrl(launchUrl); } }
<!DOCTYPE html> <html> <head> <!-- 内容安全策略 --> <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *"> <!-- 禁止IOS的电话号码识别 --> <meta name="format-detection" content="telephone=no"> <!-- 禁止Windows Phone 8+的触碰时高亮 --> <meta name="msapplication-tap-highlight" content="no"> <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes --> <!-- 视口元标签:指定应用程序占用屏幕的多大空间,以及应用程序如何缩放(zoom) minimum-scale、maximum-scale 最小/最大缩放比率 initial-scale 为初始缩放比率 user-scalable 是否允许用户缩放 width、height 界面的宽高 --> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width"> <link rel="stylesheet" type="text/css" href="css/index.css"> <title>Hello World</title> </head> <body> <div class="app"> <h1>Apache Cordova</h1> <div id="deviceready" class="blink"> <p class="event listening">Connecting to Device</p> <p class="event received">Emulater is Ready</p> </div> </div> <!-- 该JS是 Apache Cordova 提供的,用于访问设备硬件(例如摄像头、GPS)的JavaScript API 该JS只是一个占位符,没有对应的文件。该脚本在运行时由PhoneGap Developer App注入;或者在构建时由Cordova CLI注入 --> <script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="js/index.js"></script> </body> </html>
var app = { // 程序入口点 initialize: function() { this.bindEvents(); }, // 绑定事件监听器,例如'load', 'deviceready', 'offline', 'online' bindEvents: function() { document.addEventListener('deviceready', this.onDeviceReady, false); }, //事件deviceready是Cordova专有的,该事件发生后,Cordova提供的设备API加载完毕并可用 onDeviceReady: function() { app.receivedEvent('deviceready'); }, // 修改DOM内容 receivedEvent: function(id) { var parentElement = document.getElementById(id); var listeningElement = parentElement.querySelector('.listening'); var receivedElement = parentElement.querySelector('.received'); listeningElement.setAttribute('style', 'display:none;'); receivedElement.setAttribute('style', 'display:block;'); console.log('Received Event: ' + id); } }; app.initialize();
Cordova应该是基于单页面应用设计的。所谓单页面应用,是指不存在URL导航的Web应用。单页面引用仅在最初加载一次页面,后续的更新通过JavaScript、Ajax完成。
单页面应用有利于增强移动应用的性能,因为避免了重复加载各种资产文件(脚本、图片)。单页面应用对Cordova有额外的好处,因为Cordova应用必须等待deviceready事件,URL导航导致重复的事件等待。
Cordova开发者往往错误的假设,移动设备能够达到和桌面应用一样性能。实际上,尽管移动设备已经长足发展了近十年,在电池、性能方面,仍然无法和桌面应用比较。注意以下几个方面:
使用Cordova提供的offline、online事件的支持,你可以识别出离线状态,并正确的响应用户。注意,这两种事件并不是非常可靠,有时候你应当使用Ajax来判断设备是否真正的断开网络了。
注意:苹果的商店拒绝不能正确处理离线状态的APP上架。
有几种存储方案可以供Apache Cordova应用使用:
测试Cordova应用时,你可以使用真实设备、模拟器,甚至是桌面浏览器。但是,在多种真实设备上测试是很有必要的:
使用PGDA可以避免编译、打包、部署到设备的繁冗步骤,在开发阶段能够节约很多时间。
使用XCode可以调试Cordova应用Native的那一部分。
使用Safari的web inspector,你可以Debug Webview和Cordova应用的JavaScript代码,仅支持OS X和iOS6+。通过OS X中的Safari连接到设备(或模拟器),可以使用Safari的dev tools调试Cordova应用。
与Safari类似,Chrome Dev Tools也可以用来调试Cordova应用。需要Android 4.4、API 19+、Chrome 30+才可以进行调试。使用WebKit proxy,Chrome Dev Tools也可以调试iOS应用。
Ripple是一个基于Web的移动设备环境模拟器,用于快速开发基于Apache Cordova、Blackberry WebWorks等框架的移动Web应用。
综合性的移动应用调试工具,支持在现代移动设备(iOS、Android)上调试混合应用,对PhoneGap、Cordova提供非常好的支持。
该工具实质上是对Chrome Dev Tools的包装和增强。
除非特别说明所有事件均在document 对象上发布。
事件 | 说明 |
deviceready | 对任何Cordova应用程序都非常关键,该事件的发生意味着Cordova设备API已经加载完毕、并可以使用。用法示例:
document.addEventListener("deviceready", onDeviceReady, false); function onDeviceReady() { // 现在可以安全的使用Cordova设备API了 } |
pause | 当应用程序进入后台时,发布该事件 注意:在iOS中,此事件的监听器对Cordova API的调用、对alert、console.log的调用都被阻塞,直到resume发生时才执行。 |
resume | 当应用程序从后台返回前台执行时,发布此事件 注意:在iOS中,resume的监听器中,对交互式函数(例如alert)的调用,必须异步执行,否则应用程序会挂起。下面是正确的代码示例: document.addEventListener("resume", onResume, false); function onResume() { setTimeout(function() { alert(1); }, 0); } |
backbutton | 当用户按下后退按钮时,发布此事件,可以覆盖后台按钮的默认行为 不支持iOS系统 |
menubutton | 当用户按下菜单按钮时,发布此事件,可以覆盖菜单按钮的默认行为 不支持iOS系统 |
searchbutton | 当用户按下搜索按钮时,发布此事件,可以覆盖搜索按钮的默认行为 仅支持Android系统 |
volumedownbutton | 当用户按下减小音量按钮时,发布此事件,仅支持Android、BlackBerry 10 |
volumeupbutton | 当用户按下增大音量按钮时,发布此事件,仅支持Android、BlackBerry 10 |
插件cordova-plugin-battery-status引入的事件 | |
batterycritical |
这些事件都在window对象上发布。分别在关键电量、低电量、电池状态变化时(增减超过1%、或者插上电源、拔下电源)时发布。可以访问事件对象的如下属性:
|
batterylow | |
batterystatus | |
插件cordova-plugin-network-information引入的事件 | |
online | 当设备上线(连接到互联网)时,以及设备下线时,发布对应的事件 |
offline |
Cordova自带了一个最小化的API集合,工程可以通过插件添加额外的API。本节介绍Cordova核心插件的API。
本节中,使用样式区分不同的API类型:
提供三个电池相关的事件,如上节所述
该插件定义了一个全局的navigator.camera 对象,用于拍摄照片、从系统的图片库选择照片。该插件常用API如下表:
所有者 | 方法/属性 | 说明 |
navigator. camera |
getPicture() |
camera.getPicture( onSuccess successCallback, onError errorCallback, CameraOptions options ) 使用摄像头拍照,或者从设备的图片库中获取照片。如果
图片通过Base64编码或者URI的方式(默认)传递给successCallback 。如果
得到图片URI或者Base64编码后,你可以:
|
cleanup() | 清理图片临时文件,仅当options.sourceType为CAMERA、options.destinationType为FILE_URI时需要调用 仅支持iOS |
|
onError() | 获取照片的错误回调,入参:
|
|
onSuccess() | 获取照片的成功回调,入参:
|
|
CameraOptions |
用于指定摄像头参数的对象,包含以下属性:
|
|
Camera | enum DestinationType |
图片目标类型,可选值: DATA_URL FILE_URI NATIVE_URI |
enum EncodingType |
图像编码方式,可选值: JPEG PNG |
|
enum MediaType |
媒体类型,可选值: PICTURE:仅选择图片 VIDEO:仅选择视频,对于视频,DestinationType只能时URI ALLMEDIA:同时选择图片和视频 |
|
enum PictureSourceType |
图片来源类型,可选值: PHOTOLIBRARY:图片库,对于Android和SAVEDPHOTOALBUM一样 CAMERA:即时拍照 SAVEDPHOTOALBUM:图片库,对于Android和SAVEDPHOTOALBUM一样 |
|
enum Direction |
使用哪个摄像头,可选值:BACK、FRONT |
该插件确保console.log() 能够正常工作,为非Android平台提供额外的函数支持。该插件定义了一个全局的console 对象,并引入以下方法:
方法 | 说明 |
log | 这些方法支持C语言printf风格的字符串格式化:
|
error | |
exception | |
warn | |
info | |
debug | |
assert | |
dir | |
dirxml | |
time | |
timeEnd | |
table |
位于Cordova工程根目录的配置文件config.xml,可以在全局上控制Cordova应用程序的行为:
config.xml指定的配置会影响所有应用程序和CordovaWebView实例。
当使用Cordova的命令行接口(CLI)构建工程时,该文件会被修改并拷贝到各平台的对应目录,例如platforms/ios/AppName/config.xml
<?xml version='1.0' encoding='utf-8'?> <!-- widget元素: id 当前应用程序的唯一标识,通常是域名倒写,在Android中对应了包名 version 主版本.次版本.补丁版本 --> <widget id="cc.gmem.study.cordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0"> <!-- 应用程序的正式名称,该名称会出现在设备的主屏幕,以及应用商店 --> <name>CordovaStudy</name> <!-- 应用程序描述和作者信息,会显示在应用商店 --> <description> A sample Apache Cordova application that responds to the deviceready event. </description> <author email="dev@cordova.apache.org" href="http://cordova.io"> Apache Cordova Team </author> <!-- 指定应用的起始网页 --> <content src="index.html" /> <!-- 指定应用使用的Cordova插件 --> <plugin name="cordova-plugin-whitelist" spec="1" /> <!-- 指定应用可以和哪些外部域名进行交互,默认值允许与任何外部服务交互 --> <access origin="*" /> <!-- Intent白名单 --> <allow-intent href="http://*/*" /> <allow-intent href="https://*/*" /> <allow-intent href="tel:*" /> <allow-intent href="sms:*" /> <allow-intent href="mailto:*" /> <allow-intent href="geo:*" /> <!-- platform元素只会拷贝到对应平台下的config.xml中 --> <platform name="android"> <allow-intent href="market:*" /> <!-- 平台特定的方向设置 --> <preference name="Orientation" value="sensorLandscape" /> </platform> <platform name="ios"> <allow-intent href="itms:*" /> <allow-intent href="itms-apps:*" /> <!-- IOS:同时设置portrait、landscape模式 --> <preference name="Orientation" value="all" /> </platform> <!-- 以键值对的形式定义若干选项,键大小写不敏感 --> <preference> <!-- 是否隐藏设备顶部的状态栏 --> <preference name="Fullscreen" value="false" /> <!-- 支持Android、IOS。是否禁止拖拽滚动超过顶部或者底部,如果不需要“下拉以刷新”之类的功能,可以禁止 --> <preference name="DisallowOverscroll" value="false" /> <!-- 支持Android、Blackberry。应用的背景色 --> <preference name="BackgroundColor" value="0xff0000ff" /> <!-- 支持Blackberry。隐藏键盘上方额外的工具栏 --> <preference name="HideKeyboardFormAccessoryBar" value="false" /> <!-- 锁定方向,禁止响应设备的转动。可选值landscape、portrait、default --> <preference name="Orientation" value="default" /> </preference> <!-- 如果使用CLI,添加的插件不会反应到feature元素,但是如果使用针对特定平台的config.xml, 可以设置feature元素,以启用设备级别的API或者外部插件 --> <!-- 在Android平台上启用Device API --> <feature name="Device"> <param name="android-package" value="org.apache.cordova.device.Device" /> </feature> <!-- 在IOS平台上启用Device API --> <feature name="Device"> <param name="ios-package" value="CDVDevice" /> </feature> <!-- 添加钩子,以扩展Cordova的功能 --> <hook type="after_plugin_install" src="scripts/afterPluginInstall.js" /> <!-- 指定应用程序图标,platform/width/height/density都是可选的,density为Android专有 --> <icon src="res/ios/icon.png" platform="ios" width="57" height="57" density="mdpi" /> <!-- 可以采用平台专有的方式指定图标 --> <platform name="android"> <icon src="res/android/ldpi.png" density="ldpi" /> <icon src="res/android/mdpi.png" density="mdpi" /> <icon src="res/android/hdpi.png" density="hdpi" /> <icon src="res/android/xhdpi.png" density="xhdpi" /> </platform> <platform name="ios"> <!-- iOS 8.0+ --> <!-- iPhone 6 Plus --> <icon src="res/ios/icon-60@3x.png" width="180" height="180" /> <!-- iOS 7.0+ --> <!-- iPhone / iPod Touch --> <icon src="res/ios/icon-60.png" width="60" height="60" /> <icon src="res/ios/icon-60@2x.png" width="120" height="120" /> <!-- iPad --> <icon src="res/ios/icon-76.png" width="76" height="76" /> <icon src="res/ios/icon-76@2x.png" width="152" height="152" /> <!-- iOS 6.1 --> <!-- Spotlight Icon --> <icon src="res/ios/icon-40.png" width="40" height="40" /> <icon src="res/ios/icon-40@2x.png" width="80" height="80" /> <!-- iPhone / iPod Touch --> <icon src="res/ios/icon.png" width="57" height="57" /> <icon src="res/ios/icon@2x.png" width="114" height="114" /> <!-- iPad --> <icon src="res/ios/icon-72.png" width="72" height="72" /> <icon src="res/ios/icon-72@2x.png" width="144" height="144" /> <!-- iPhone Spotlight and Settings Icon --> <icon src="res/ios/icon-small.png" width="29" height="29" /> <icon src="res/ios/icon-small@2x.png" width="58" height="58" /> <!-- iPad Spotlight and Settings Icon --> <icon src="res/ios/icon-50.png" width="50" height="50" /> <icon src="res/ios/icon-50@2x.png" width="100" height="100" /> </platform> <!-- 指定启动画面,也可用使用Splashscreen插件,动态编程控制 --> <platform name="android"> <!-- you can use any density that exists in the Android project --> <splash src="res/screen/android/splash-land-hdpi.png" density="land-hdpi"/> <splash src="res/screen/android/splash-land-ldpi.png" density="land-ldpi"/> <splash src="res/screen/android/splash-land-mdpi.png" density="land-mdpi"/> <splash src="res/screen/android/splash-land-xhdpi.png" density="land-xhdpi"/> <splash src="res/screen/android/splash-port-hdpi.png" density="port-hdpi"/> <splash src="res/screen/android/splash-port-ldpi.png" density="port-ldpi"/> <splash src="res/screen/android/splash-port-mdpi.png" density="port-mdpi"/> <splash src="res/screen/android/splash-port-xhdpi.png" density="port-xhdpi"/> </platform> <platform name="ios"> <!-- images are determined by width and height. The following are supported --> <splash src="res/screen/ios/Default~iphone.png" width="320" height="480"/> <splash src="res/screen/ios/Default@2x~iphone.png" width="640" height="960"/> <splash src="res/screen/ios/Default-Portrait~ipad.png" width="768" height="1024"/> <splash src="res/screen/ios/Default-Portrait@2x~ipad.png" width="1536" height="2048"/> <splash src="res/screen/ios/Default-Landscape~ipad.png" width="1024" height="768"/> <splash src="res/screen/ios/Default-Landscape@2x~ipad.png" width="2048" height="1536"/> <splash src="res/screen/ios/Default-568h@2x~iphone.png" width="640" height="1136"/> <splash src="res/screen/ios/Default-667h.png" width="750" height="1334"/> <splash src="res/screen/ios/Default-736h.png" width="1242" height="2208"/> <splash src="res/screen/ios/Default-Landscape-736h.png" width="2208" height="1242"/> </platform> </widget>
<!-- 应用程序是否保持后台运行,甚至在pause事件发生之后 设置为fasle不会在pause事件后终止应用,而是仅仅当应用位于后台时,暂停CordovaWebView中代码的执行 --> <preference name="KeepRunning" value="true"/> <!-- 加载页面超时的毫秒数 --> <preference name="LoadUrlTimeoutValue" value="20000"/> <!-- 启动屏幕,位于res/drawable-*中的资源名称,不带扩展名 --> <preference name="SplashScreen" value="splash"/> <!-- 启动屏幕图片显示的毫秒数 --> <preference name="SplashScreenDelay" value="3000"/> <!-- 控制通过InAppBrowser打开的页面,是否可以和通过默认浏览器打开的页面访问同一localStorage和WebSQL --> <preference name="InAppBrowserStorageEnabled" value="true"/> <!-- 默认为null,如果设置,那么在加载第一个页面时,显示指定的标题、消息以及一个spinner。标题和消息使用逗号分隔 --> <preference name="LoadingDialog" value="My Title,My Message"/> <!-- 默认为null,与上一个配置类似,但是用于除了第一个页面的所有其它页面 --> <preference name="LoadingPageDialog" value="My Title,My Message"/> <!-- 默认为null,出错时显示的页面 --> <preference name="ErrorUrl" value="myErrorPage.html"/> <!-- 是否在屏幕顶部显示标题 --> <preference name="ShowTitle" value="false"/> <!-- 设置应用的日志级别:ERROR, WARN, INFO, DEBUG, VERBOSE --> <preference name="LogLevel" value="ERROR"/> <!-- 设置Activity的android:launchMode属性 --> <preference name="AndroidLaunchMode" value="singleTop"/> <!-- 设置User Agent,默认不设置 --> <preference name="OverrideUserAgent" value="Mozilla/5.0 My Browser" />
从Cordova4.3开始,支持保存(save )、恢复(restore )平台支持版本、插件版本信息。
当使用--save 选项调用cordova platform 、cordova plugin 命令时,会自动把版本信息存放到config.xml中。执行cordova prepare 时,会从config.xml中读取版本信息,并同步相应文件到platforms子目录中。
执行下面的命令,即可保存特定版本的平台:
# 命令格式 cordova platform add <platform[@<version>] | directory | git_url> --save # 命令举例 cordova platform add android --save cordova platform add android@3.7.0 --save #后续不带@version添加平台,自动使用 3.7.0版本 cordova platform add android@https://github.com/apache/cordova-android.git --save cordova platform add C:/path/to/android/platform --save # 保存所有平台的版本 cordova platform save
运行此命令后,config.xml中出现类似下面的条目:
<engine name="android" spec="~4.0.0" />
执行下面的命令,可以更新特定平台的版本:
# 命令格式 cordova platform update <platform[@<version>] | directory | git_url> --save # 命令举例 cordova platform update android --save cordova platform update android@3.8.0 --save cordova platform update /path/to/android/platform --save
执行下面的命令,即可保存插件版本到config.xml:
# 命令格式 cordova plugin add <plugin[@<version>] | directory | git_url> --save # 命令举例 cordova plugin add cordova-plugin-console --save cordova plugin add cordova-plugin-console@0.2.13 --save #后续不带@version添加此插件,自动使用0.2.13版本 cordova plugin add https://github.com/apache/cordova-plugin-console.git --save cordova plugin add C:/path/to/console/plugin --save # 保存所有插件的版本 cordova plugin save
运行此命令后,config.xml中出现类似下面的条目:
<plugin name="cordova-plugin-console" spec="~1.0.0" />
执行下面的命令,可以更新特定插件的版本:
# 命令格式 cordova plugin update <plugin[@<version>] | directory | git_url> --save # 命令举例 cordova plugin update cordova-plugin-console --save cordova plugin update cordova-plugin-console@0.2.13 --save cordova plugin update /path/to/console/plugin --save
移动应用的隐私问题是每个移动App都需要关注的内容,用户需要它们的私人信息被合理使用,并不泄漏。下面是一些被广泛接受的建议:
本节包含一些开发Cordova应用时,处理安全问题的最佳实践。
域名白名单(Domain whitelisting)机制用来控制Cordova应用对外部域名的访问。默认的,新创建的App被允许访问所有外部域名,在产品发布时,你必须确定需要访问哪些域名,并进行白名单配置。
对于Android和iOS,上述安全策略通过插件cordova-plugin-whitelist实现,具有更好的安全性和可配置性,推荐使用:
<!-- 导航白名单(Navigation Whitelist) 控制WebView可以被导航到那些URL,仅应用到顶级导航 --> <!-- 允许连接到google.com--> <allow-navigation href="http://google.com/*" /> <!-- 允许使用HTTP/HTTPS或者其它任何协议连接到google.com的所有子域 --> <allow-navigation href="*://*.google.com/*" /> <!-- 允许导航到任意网站--> <allow-navigation href="*" /> <!-- 上面一条等价于这三条:--> <allow-navigation href="http://*/*" /> <allow-navigation href="https://*/*" /> <allow-navigation href="data:*" /> <!-- Intent白名单(Intent Whitelist) 控制App可以要求系统打开哪些URL,默认任何URL都不允许 --> <!-- 允许在一个浏览器窗口中打开网页 --> <allow-intent href="http://*/*" /> <allow-intent href="https://*/*" /> <allow-intent href="http://google.com/*" /> <allow-intent href="*://*.example.com/*" /> <!-- 允许在短信应用中打开SMS链接 --> <allow-intent href="sms:*" /> <!-- 允许拨打电话 --> <allow-intent href="tel:*" /> <!-- 允许打开地图 --> <allow-intent href="geo:*" /> <!-- 允许使用对应的App打开所有其它类型的URL --> <allow-intent href="*" /> <!-- 网络请求白名单(Network Request Whitelist) 控制哪些网络请求被允许:Ajax、images等 注意,最好使用Content Security Policy(CSP),CSP更安全。这节的配置主要用于不支持CSP的老旧Webview 默认Android允许访问https://ssl.gstatic.com/accessibility/javascript/android/,这确保TalkBack正常工作 --> <!-- 允许对google.com执行Ajax、图片请求 --> <access origin="http://*.google.com" /> <!-- 允许针对content URL的请求 --> <access origin="content:///*" /> <!-- 允许任何请求 --> <access origin="*" />
对于其它平台,Cordova应用依赖于config.xml中的<access> 元素进行白名单设置:
<!-- 允许访问google.com --> <access origin="http://google.com" /> <!-- 允许访问HTTPS版本的google.com --> <access origin="https://google.com" /> <!-- 允许访问maps.google.com --> <access origin="http://maps.google.com" /> <!-- 允许访问google.com的所有子域名 --> <access origin="http://*.google.com" /> <!-- 允许访问所有网站 --> <access origin="*" />
参见:HTML知识集锦
CSP用于控制图片、Ajax、<video> 、WebSocket等所有请求。上面的whitelist插件的network request whitelist,只能控制图片、Ajax,因此有必要在HTML的<meta> 配置CSP:
<!-- 较为安全的默认值 --> <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *"> <!-- 允许同源和google.com的所有内容--> <meta http-equiv="Content-Security-Policy" content="default-src 'self' google.com"> <!-- 允许所有内容,除了: 对于CSS,仅允许同源的CSS文件,以及内联的样式 对于脚本,仅允许同源的JS文件,内联的JavaScript脚本,以及eval() --> <meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'"> <!-- 仅允许同源的、通过HTTPS的Ajax请求 --> <meta http-equiv="Content-Security-Policy" content="default-src 'self' https:"> <!-- 允许来自google.com的IFrame --> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; frame-src 'self' https://google.com">
钩子是Cordova Application、Plugin添加的特殊脚本,用于定制化Cordova的命令。可以在hooks目录添加钩子,也可以在config.xml、plugin.xml中声明钩子。钩子按照下面的顺序串行执行:
目前支持的钩子类型有:
如果把钩子存放在hooks目录,必须遵从严格的命名规定:hooks/钩子类型/脚本文件.js 。例如,如果你需要在prepare命令执行完毕后,附加一些行为,可以编写脚本:hooks/after_prepare/cordova-syncdown.js 。应避免使用hooks目录,未来的Cordova版本可能废弃这种方式。
在config.xml、plugin.xml中声明钩子的方式如下:
<hook type="before_build" src="scripts/appBeforeBuild.bat" /> <hook type="before_build" src="scripts/appBeforeBuild.js" /> <hook type="before_plugin_install" src="scripts/appBeforePluginInstall.js" />
一般使用NodeJS来编写钩子,Node模块定义的方式如下:
module.exports = function( ctx ) { }
其中ctx包含很多上下文信息:
{ "hook": "after_prepare", "scriptLocation": "after_prepare/script.js", "cmdLine": "/path/to/cordova arguments", "opts": { "projectRoot":"/path/to/project", "cordova": { "platforms": ["android"], "plugins": ["com.plugin.withhooks"], "version": "0.21.7-dev" }, "plugin": { "id": "com.plugin.withhooks", "pluginInfo": { ... }, "platform": "android", "dir": "/path/to/project/plugins/com.plugin.withhooks" } }, "cordova": {} //cordova object }
修改$CORDOVA_PROJECT_ROOT/platforms/android/cordova/lib/build.js 中如下变量的值:
var distributionUrl = 'distributionUrl=../../../gradle-2.2.1-all.zip';
然后,把本地磁盘的 gradle-2.2.1-all.zip拷贝或者链接到$CORDOVA_PROJECT_ROOT/platforms 即可。执行cordova prepare 时,会从config.xml中读取版本信息,并同步到已经添加的各平台的对应目录中。
让Gradle使用本地Maven仓库中的构件,避免不必要的下载动作
修改$CORDOVA_PROJECT_ROOT/platforms/android/build.gradle中的内容:
repositories { mavenLocal() //添加上面一行的内容 mavenCentral() }
Leave a Reply