基于Apache Cordova开发移动应用程序
- 目标平台:本文中会反复出现该名词,目标平台是指移动操作系统+移动应用SDK构成的移动应用支撑环境。有时也称作移动平台,或简称平台
- 构建平台:在其上运行Cordova工具,生成目标平台应用程序的宿主操作系统
- PhoneGap:目前作为Apache Cordova的一个发行版,它们的命令行非常相似。PhoneGap提供了一些更高级的组件,例如云端构建、设备端工具(PhoneGap Developer App)
可以选择三种方式来开发移动应用,它们各有特点:
- 为特定的设备、操作系统构建。需要熟悉设备SDK,甚至特殊的开发语言:Objective-C/Swift (iOS);Java (Android);C# (Windows)
- 安装到设备,作为本地程序运行
- 使用原生的API和控件
- 通常必须经过应用市场的验证才能被客户使用
- 可以离线使用
- 性能优秀
- 在任何移动浏览器中运行
- 支持受限的使用设备特性
- 基于标准的Web技术构建,包括HTML、CSS、JavaScript
- 需要支持多种屏幕尺寸
- 需要Web服务器的支撑,不支持离线使用
- 性能较差
所谓混合应用,就是结合了前两者的特性和优势的应用,混合应用可以分为两种风格:
- 基于Web的混合应用(Web hybrid mobile apps):APP运行在一个很薄的Native容器+WebView中,该容器仅作为访问Native特性的桥梁,所有UI组件均基于Web技术构建
- 基于Native的混合应用(Native hybrid mobile apps):包含很多的Native控件,以及1-N个WebView。常常使用Native控件做导航、并在提供应用内容的WebView之间进行切换
混合应用具有以下特性:
- 安装到设备,作为本地程序运行
- 应用逻辑主要在WebView(嵌入的Web浏览器)中运行
- 大部分代码是跨平台的
- 支持访问原生特性
- 由于应用内容主要使用基于设备内置浏览器引擎,因此性能比起原生应用差
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 应用的开发工作流有两种:
- 以Cordova CLI为中心跨平台工作流:如果需要应用在尽可能多的平台上运行,可以使用这种方式,该方式需要很少的平台特定开发工作量。CLI是3.0引入的,可以同时为多个平台构建工程的工具,它是Cordova跨平台工作流的核心。CLI会创建Cordova工程的初始结构、把Web资产文件拷贝到各平台的子目录下、对各平台进行必要的配置,然后运行脚本生成二进制程序。CLI也提供了为应用添加插件的公共接口
- 以平台为中心的工作流:如果需要构建特定单个平台的应用,以及需要在底层基于平台SDK对代码进行修改,可以使用该方式。典型的例子是开发Native-based混合应用,需要把WebView和其他Native组件集成时。使用这种方式开发时,可以通过Plugman来添加插件
推荐以第1种方式开始,使用CLI创建Cordova工程,在必要时切换到第2种方式。针对平台的低级别Shell工具可以在工程的 platforms/*/cordova 目录下找到(其中*代表平台名称)。一旦切换,就不能返回,因为CLI管理的跨平台源代码集会在每次构建时被覆盖。为了保护你修改过的代码,必须使用平台特定的Shell工具,这些Shell工具忽略跨平台代码而依赖于平台特定的代码。
使用Cordova的命令行接口(CLI),可以完成新工程的创建、针对各平台进行构建、并部署到设备(或模拟器)中运行。
在安装和使用CLI前,必须下载和安装相关目标平台的SDK和相关工具,如果不安装,在调用CLI进行应用构建时会收到错误提示,例如:
1 2 3 4 5 6 7 8 9 10 11 |
#没有安装完整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支持的目标平台(构建平台)包括:
- iOS(Mac)
- Android (Mac, Linux, Windows)
- BlackBerry 10 (Mac, Linux, Windows)
- Windows Phone 8 (Windows)
可以看到如果要支持全部主要的目标平台,你需要在不同操作系统上运行CLI命令,这意味着你应该使用代码库(SVN/Git)来管理工程。
- 安装Node.js
- 安装Git客户端
- 通过npm命令安装cordova模块:
12345678910# 安装Cordova为全局模块npm install -g cordova#安装特定版本的Cordovanpm install -g cordova@3.1.0-0.2.0#更新Cordovanpm update -g cordova#显示版本信息cordova -v
执行下面的命令创建工程:
1 2 3 4 5 6 |
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 | 包含了用于生成和分发应用程序的重要元数据 |
运行下面的命令添加对特定平台的支持:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#添加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为中心的工作流,则需要继续了解下面的小节。
执行下面的命令可以构建应用程序的二进制文件并打包:
1 2 3 4 |
# 构建所有平台 cordova build # 构建特定平台 cordova build ios |
上述build命令实际上包含了两个步骤:
1 2 3 4 5 |
# 准备阶段,会把Cordova源码拷贝、合并到平台的对应目录中 # 一旦执行完该命令,就可以用特定平台提供的SDK进行修改、编译 cordova prepare ios # 编译 cordova compile ios |
运行下面的命令重新构建特定平台的应用,并部署到模拟器中:
1 2 3 4 |
# 运行下面的命令后,Cordova会自动启动模拟器,并把APK安装到上面 # 如果有模拟器正在运行,则使用既有的模拟器 cordova emulate android # APK安装完毕后,将自动运行 |
或者,将启用了调试模式的手机连接到当前计算机,然后运行:
1 |
cordova run android |
你可以使用Web技术修改Cordova生成的应用骨架,来开发漂亮的页面。但是如果想使用设备底层特性,则必须添加插件,利用插件可以访问核心Cordova API。第三方/自己开发的插件可以用来访问特殊的设备特性,要访问通用设备特性使用Cordova提供的的插件就足够了。官方插件和第三方插件的列表位于http://cordova.apache.org/plugins/。
下面的命令用来搜索插件:
1 2 |
#同时包含bar和code的插件 cordova plugin search bar code |
下面的命令用来列出当前工程已添加的插件:
1 |
cordova plugin ls |
下面的命令用来移除已经添加的插件:
1 |
cordova plugin rm cordova-plugin-console |
下面的命令用来给应用程序添加插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#依据插件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 )注册,通过下面的命令添加:
1 2 3 4 5 6 7 8 |
# 从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 | 显示命令帮助:
|
子命令 | 说明 | ||
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无法搭配使用,可以改用:
|
首先,参考文章:基于Eclipse ADT和Maven的Android开发 完整Android开发环境的搭建。
由于Android平台官方的开发工具现在是Android Studio,并且基于Gradle构建,所以最好搭建好Gradle环境和Gradle的Eclipse插件。可参考文章:Gradle学习笔记。
通过CLI创建Cordova工程后,一旦添加了Android平台的支持,就可以把platforms/android子目录作为工程导入到Eclipse ADT或者Android Studio。
以Eclipse ADT为例,操作步骤为:
- File ⇨ Import
- 在弹出的对话框中选择 Android ⇨ Existing Android Code Into Workspace,点击下一步
- 把Root Directory定位到Cordova工程的platforms/android目录,选择其中的两个工程,如下图:
- 点击完成,工作区出现两个新的ADT工程,导入完毕
这两个工程就是普通的ADT工程。其中cordovalib是cordova-android的依赖库。在cordova-android上点击右键 ⇨ Run as ⇨ Android Application,即可打包并部署到设备上运行。
上述方式导入的工程结构比较混乱,如果后续开发脱离Cordova进行,建议清理其中不需要的目录和文件。如果不习惯基于Gradle进行构建,可以创建或者转换为Maven工程。
安装了Gradle的Eclipse插件后,可以把platforms/android子目录转换为Gradle工程:
- File ⇨ Import
- 在弹出的对话框中选择 Gradle ⇨ Gradle Project,点击下一步
- 在弹出的对话框中,把Root folder定位到platforms/android子目录,然后点击右侧的Build Model按钮。Gradle从Maven仓库下载一些构件到Gradle缓存目录,完毕后显示如下画面:
- 点击完成。你可以自由的修改Eclipse工程的名称
如果习惯于使用Maven进行构建工作,可以参考下面的步骤,把platforms/android子目录转换为Maven工程:
- 参考:基于Eclipse ADT和Maven的Android开发创建Android的Maven工程,设工程根目录为 %MVN_PROJECT_ROOT% 。删除自动生成的Activity、res目录,并转换为android-maven-plugin 4.3.0标准的工程结构
- 如果使用SVN,在目录%MVN_PROJECT_ROOT% 上设置属性svn:ignore为:
1234targetbin.*cli - 通过CLI创建对应的(同名同包)Cordova工程,添加必要的插件,设工程根目录为 %CORDOVA_PROJECT_ROOT%
- 创建Maven工程指向Cordova工程的符号链接:
1mklink /D %MVN_PROJECT_ROOT%\cli %CORDOVA_PROJECT_ROOT% - 另外创建一个Android的Maven工程“cordova-android”,project.properties中设置 android.library=true ,表示这是一个库工程。设工程根目录为 %MVN_LIB_ROOT%
- 修改
%MVN_PROJECT_ROOT%\pom.xml ,添加cordova-android的依赖,例如:
123456<dependency><groupId>org.apache.cordova</groupId><artifactId>cordova-android</artifactId><version>4.4.1-SNAPSHOT</version><type>apklib</type></dependency> - 修改Cordova工程的
%CORDOVA_PROJECT_ROOT%\cli\platforms\android\build-extras.gradle 文件,添加以下Tasks:
123456789101112131415161718192021222324task 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] ) - 每当添加Cordova插件,或者修改Cordova工程中其它源码文件后,定位到
%MVN_PROJECT_ROOT%\cli目录,执行:
12345@echo offcall cordova preparepushd platforms\androidcall gradle syncdownpopd这会让所有修改从Cordova工程目录,同步到其Android平台子目录,然后再同步到Maven工程对应目录中。
Android平台特定的命令行工具位于 platforms/android/cordova 子目录中,这些命令比Cordova CLI更有针对性,在以Android为中心的开发时,可以代替之:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
### 构建工程 ### #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签名所需的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "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签名需信息的属性文件的名称,属性文件的内容示例如下:
|
||
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覆盖。下面是扩展脚本的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 |
# 此文件的内容被放在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设备或者模拟器上测试:
- 使用Maven: package android:deploy android:run
- 使用ADT:在apk工程上面点击右键 Run As ⇨ Android Application
注意,必须让你的设备或者模拟器链接到当前机器上。
这两种方式都比较慢,每次部署都需要数十秒,非常浪费时间。因此可以使用PhoneGap提供的设备端工具,该工具可以免部署的运行Cordova应用。
应用启动后,会自动启用一个WebView,加载config.xml中指定的起始页(默认index.html),让HTML页面占据整个屏幕空间。
例如,对Android平台,系统会执行MainActivity,该Activity是CordovaActivity的子类:
1 2 3 4 5 6 7 8 9 10 |
public class MainActivity extends CordovaActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 加载HTML loadUrl(launchUrl); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<!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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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开发者往往错误的假设,移动设备能够达到和桌面应用一样性能。实际上,尽管移动设备已经长足发展了近十年,在电池、性能方面,仍然无法和桌面应用比较。注意以下几个方面:
- click vs touch:click事件被大量误用。大部分移动设备添加300ms的延迟,用以区分touch和touch hold。使用touchstart、touchend可能有很大的性能改善——避免频繁的UI更新和其它行为
- CSS 变换 vs DOM操控:硬件加速的CSS变换比起基于JavaScript的动画,性能有极大的优势
- 网络延迟:尽量使用Cordova支持的本地存储机制,避免反复通过网络获取数据、资源
使用Cordova提供的offline、online事件的支持,你可以识别出离线状态,并正确的响应用户。注意,这两种事件并不是非常可靠,有时候你应当使用Ajax来判断设备是否真正的断开网络了。
注意:苹果的商店拒绝不能正确处理离线状态的APP上架。
有几种存储方案可以供Apache Cordova应用使用:
- LocalStorage:同步的基于键值对的存储
- WebSQL:基于SQL语句的API,支持Android、iOS
- IndexedDB:支持Windows 8、Windows Phone 8
- cordova-plugin-file插件:缓存数据到本地文件系统
测试Cordova应用时,你可以使用真实设备、模拟器,甚至是桌面浏览器。但是,在多种真实设备上测试是很有必要的:
- 模拟器(Simulator)不能模拟一些真实存在的情况:例如低电池时,应用会出现某个问题,这个问题在模拟器上难以体现
- 模拟器(Emulator)和真实设备的行为存在不一致:某些模拟器会导致页面显示混乱,但是在真实设备上没有这种问题。4.1.2的AVD,运行5.4版本Cordova的HelloWorld应用,就存在页面显示混乱的情况。你可能需要禁用Host GPU加速
- Simulator往往比真实设备快很多,而Emulator则慢很多
- 在不同OS的设备上测试是有必要的,应用的行为可能不符合预期
使用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已经加载完毕、并可以使用。用法示例:
|
||
pause | 当应用程序进入后台时,发布该事件 注意:在iOS中,此事件的监听器对Cordova API的调用、对alert、console.log的调用都被阻塞,直到resume发生时才执行。 |
||
resume | 当应用程序从后台返回前台执行时,发布此事件 注意:在iOS中,resume的监听器中,对交互式函数(例如alert)的调用,必须异步执行,否则应用程序会挂起。下面是正确的代码示例:
|
||
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类型:
- 斜体:表示静态(static)成员
- 下划线标注:类型定义(typedef)
- 括号后缀:表示方法/函数
提供三个电池相关的事件,如上节所述
该插件定义了一个全局的 navigator.camera 对象,用于拍摄照片、从系统的图片库选择照片。该插件常用API如下表:
所有者 | 方法/属性 | 说明 | ||
navigator. camera |
getPicture() |
使用摄像头拍照,或者从设备的图片库中获取照片。如果
图片通过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应用程序的行为:
- 指定核心Cordova API特性
- 启用Cordova插件
- 进行平台相关的设置
config.xml指定的配置会影响所有应用程序和CordovaWebView实例。
当使用Cordova的命令行接口(CLI)构建工程时,该文件会被修改并拷贝到各平台的对应目录,例如 platforms/ios/AppName/config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
<?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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<!-- 应用程序是否保持后台运行,甚至在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子目录中。
执行下面的命令,即可保存特定版本的平台:
1 2 3 4 5 6 7 8 9 10 |
# 命令格式 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中出现类似下面的条目:
1 |
<engine name="android" spec="~4.0.0" /> |
执行下面的命令,可以更新特定平台的版本:
1 2 3 4 5 6 7 |
# 命令格式 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:
1 2 3 4 5 6 7 8 9 10 11 |
# 命令格式 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中出现类似下面的条目:
1 |
<plugin name="cordova-plugin-console" spec="~1.0.0" /> |
执行下面的命令,可以更新特定插件的版本:
1 2 3 4 5 6 7 |
# 命令格式 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都需要关注的内容,用户需要它们的私人信息被合理使用,并不泄漏。下面是一些被广泛接受的建议:
- 隐私策略(Privacy Policy):使用平白的语言声明你的App的隐私策略
- 敏感信息的收集:在获取敏感信息,例如通讯录、地理位置、摄像机信息前,获得用户的许可
- 与第三方共享敏感信息:如果你的App获取的信息需要与第三方网站/应用共享,应当获得用户许可
- 仅在必要的时候才收集隐私信息
本节包含一些开发Cordova应用时,处理安全问题的最佳实践。
- 不要使用自签名的网站证书:如果你的服务器使用SSL,务必使用知名CA签发的数字证书
- 避免使用IFrame引用外部网页(不受你控制的第三方网站):位于白名单中的网页,如果运行在IFrame中,它是可以访问Native Cordova Bridge的。引用外部链接,最好使用InAppBrowser,外部链接不会有机会执行Cordova API
- 关于域名白名单:Android API 10以下、WP8中的IFrame和XMLHttpRequest,都不受域名白名单控制,这意味着任何网页都可以调用Cordova接口
- 不要缓存敏感信息,例如用户名、密码
- 避免使用 eval() ,除非你确切知道脚本的内容
域名白名单(Domain whitelisting)机制用来控制Cordova应用对外部域名的访问。默认的,新创建的App被允许访问所有外部域名,在产品发布时,你必须确定需要访问哪些域名,并进行白名单配置。
对于Android和iOS,上述安全策略通过插件cordova-plugin-whitelist实现,具有更好的安全性和可配置性,推荐使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<!-- 导航白名单(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> 元素进行白名单设置:
1 2 3 4 5 6 7 8 9 10 |
<!-- 允许访问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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<!-- 较为安全的默认值 --> <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目录的Application钩子
- 来自config.xml的Application钩子
- 来自plugins/.../plugin.xml的插件钩子
目前支持的钩子类型有:
- after_build
- after_compile
- after_clean
- after_docs
- after_emulate
- after_platform_add
- after_platform_rm
- after_platform_ls
- after_plugin_add
- after_plugin_ls
- after_plugin_rm
- after_plugin_search
- after_plugin_install 仅执行被安装插件声明在plugin.xml中的钩子
- after_prepare
- after_run
- after_serve
- before_build
- before_clean
- before_compile
- before_docs
- before_emulate
- before_platform_add
- before_platform_rm
- before_platform_ls
- before_plugin_add
- before_plugin_ls
- before_plugin_rm
- before_plugin_search
- before_plugin_install 仅执行被安装插件声明在plugin.xml中的钩子
- before_plugin_uninstall 仅执行被卸载插件声明在plugin.xml中的钩子
- before_prepare
- before_run
- before_serve
- pre_package 仅支持Windows、Windows Phone平台
如果把钩子存放在hooks目录,必须遵从严格的命名规定: hooks/钩子类型/脚本文件.js 。例如,如果你需要在prepare命令执行完毕后,附加一些行为,可以编写脚本: hooks/after_prepare/cordova-syncdown.js 。应避免使用hooks目录,未来的Cordova版本可能废弃这种方式。
在config.xml、plugin.xml中声明钩子的方式如下:
1 2 3 |
<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模块定义的方式如下:
1 2 3 |
module.exports = function( ctx ) { } |
其中ctx包含很多上下文信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
{ "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 中如下变量的值:
1 |
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中的内容:
1 2 3 4 5 |
repositories { mavenLocal() //添加上面一行的内容 mavenCentral() } |
Leave a Reply