Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

基于Apache Cordova开发移动应用程序

9
Nov
2015

基于Apache Cordova开发移动应用程序

By Alex
/ in Android,IOS,Mobile
/ tags Cordova
0 Comments
基础知识
名词术语
  1. 目标平台:本文中会反复出现该名词,目标平台是指移动操作系统+移动应用SDK构成的移动应用支撑环境。有时也称作移动平台,或简称平台
  2. 构建平台:在其上运行Cordova工具,生成目标平台应用程序的宿主操作系统
  3. PhoneGap:目前作为Apache Cordova的一个发行版,它们的命令行非常相似。PhoneGap提供了一些更高级的组件,例如云端构建、设备端工具(PhoneGap Developer App)
移动应用开发技术的选型

可以选择三种方式来开发移动应用,它们各有特点:

原生(Native)应用
  1. 为特定的设备、操作系统构建。需要熟悉设备SDK,甚至特殊的开发语言:Objective-C/Swift (iOS);Java (Android);C# (Windows)
  2. 安装到设备,作为本地程序运行
  3. 使用原生的API和控件
  4. 通常必须经过应用市场的验证才能被客户使用
  5. 可以离线使用
  6. 性能优秀
纯Web应用
  1. 在任何移动浏览器中运行
  2. 支持受限的使用设备特性
  3. 基于标准的Web技术构建,包括HTML、CSS、JavaScript
  4. 需要支持多种屏幕尺寸
  5. 需要Web服务器的支撑,不支持离线使用
  6. 性能较差
混合(Hybrid)应用

所谓混合应用,就是结合了前两者的特性和优势的应用,混合应用可以分为两种风格:

  1. 基于Web的混合应用(Web hybrid mobile apps):APP运行在一个很薄的Native容器+WebView中,该容器仅作为访问Native特性的桥梁,所有UI组件均基于Web技术构建
  2. 基于Native的混合应用(Native hybrid mobile apps):包含很多的Native控件,以及1-N个WebView。常常使用Native控件做导航、并在提供应用内容的WebView之间进行切换

混合应用具有以下特性:

  1. 安装到设备,作为本地程序运行
  2. 应用逻辑主要在WebView(嵌入的Web浏览器)中运行
  3. 大部分代码是跨平台的
  4. 支持访问原生特性
  5. 由于应用内容主要使用基于设备内置浏览器引擎,因此性能比起原生应用差
Apache Cordova简介

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工程默认不包含任何插件,所有插件都需要手工添加。

开发工作流(Workflow)

Cordova 应用的开发工作流有两种:

  1. 以Cordova CLI为中心跨平台工作流:如果需要应用在尽可能多的平台上运行,可以使用这种方式,该方式需要很少的平台特定开发工作量。CLI是3.0引入的,可以同时为多个平台构建工程的工具,它是Cordova跨平台工作流的核心。CLI会创建Cordova工程的初始结构、把Web资产文件拷贝到各平台的子目录下、对各平台进行必要的配置,然后运行脚本生成二进制程序。CLI也提供了为应用添加插件的公共接口
  2. 以平台为中心的工作流:如果需要构建特定单个平台的应用,以及需要在底层基于平台SDK对代码进行修改,可以使用该方式。典型的例子是开发Native-based混合应用,需要把WebView和其他Native组件集成时。使用这种方式开发时,可以通过Plugman来添加插件

推荐以第1种方式开始,使用CLI创建Cordova工程,在必要时切换到第2种方式。针对平台的低级别Shell工具可以在工程的 platforms/*/cordova 目录下找到(其中*代表平台名称)。一旦切换,就不能返回,因为CLI管理的跨平台源代码集会在每次构建时被覆盖。为了保护你修改过的代码,必须使用平台特定的Shell工具,这些Shell工具忽略跨平台代码而依赖于平台特定的代码。

基于CLI的跨平台工作流

使用Cordova的命令行接口(CLI),可以完成新工程的创建、针对各平台进行构建、并部署到设备(或模拟器)中运行。

在安装和使用CLI前,必须下载和安装相关目标平台的SDK和相关工具,如果不安装,在调用CLI进行应用构建时会收到错误提示,例如:

Shell
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支持的目标平台(构建平台)包括:

  1. iOS(Mac)
  2. Android (Mac, Linux, Windows)
  3. BlackBerry 10 (Mac, Linux, Windows)
  4. Windows Phone 8 (Windows)

可以看到如果要支持全部主要的目标平台,你需要在不同操作系统上运行CLI命令,这意味着你应该使用代码库(SVN/Git)来管理工程。

安装Cordova CLI
  1. 安装Node.js
  2. 安装Git客户端
  3. 通过npm命令安装cordova模块:
    Shell
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 安装Cordova为全局模块
    npm install -g cordova
    #安装特定版本的Cordova
    npm install -g cordova@3.1.0-0.2.0
     
    #更新Cordova
    npm update -g cordova
     
    #显示版本信息
    cordova -v
创建Cordova工程

执行下面的命令创建工程:

Shell
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 包含了用于生成和分发应用程序的重要元数据
添加目标平台支持

运行下面的命令添加对特定平台的支持:

Shell
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工程的默认用途

其中:

  1. assets/www包含了Cordova应用的所有Web资源文件,包括HTML、CSS、JS等。Cordova工程中的www目录中的内容全部复制一份覆盖到该目录。插件的Web资源也拷贝并覆盖到plugins子目录
  2. src目录包含自动生成的一个Activity源码、已经拷贝过来的插件源代码
src
libs
res
plugins 存放下载的对应各目标平台的插件源代码、文档

前面我们说过,创建新工程可以从CLI命令行开始,在必要时切换到特定平台的开发工作中去。在此,就可以进行切换了:只需要把platforms子目录导入到Eclipse、XCode等IDE即可,然后以IDE为中心完成后续开发。

如果继续执行以CLI为中心的工作流,则需要继续了解下面的小节。

构建应用

执行下面的命令可以构建应用程序的二进制文件并打包:

Shell
1
2
3
4
# 构建所有平台
cordova build
# 构建特定平台
cordova build ios

上述build命令实际上包含了两个步骤: 

Shell
1
2
3
4
5
# 准备阶段,会把Cordova源码拷贝、合并到平台的对应目录中
# 一旦执行完该命令,就可以用特定平台提供的SDK进行修改、编译
cordova prepare ios
# 编译
cordova compile ios
在设备上测试应用

运行下面的命令重新构建特定平台的应用,并部署到模拟器中:

Shell
1
2
3
4
# 运行下面的命令后,Cordova会自动启动模拟器,并把APK安装到上面
# 如果有模拟器正在运行,则使用既有的模拟器
cordova emulate android
# APK安装完毕后,将自动运行

 或者,将启用了调试模式的手机连接到当前计算机,然后运行:

Shell
1
cordova run android
添加插件支持

你可以使用Web技术修改Cordova生成的应用骨架,来开发漂亮的页面。但是如果想使用设备底层特性,则必须添加插件,利用插件可以访问核心Cordova API。第三方/自己开发的插件可以用来访问特殊的设备特性,要访问通用设备特性使用Cordova提供的的插件就足够了。官方插件和第三方插件的列表位于http://cordova.apache.org/plugins/。

下面的命令用来搜索插件:

Shell
1
2
#同时包含bar和code的插件
cordova plugin search bar code

下面的命令用来列出当前工程已添加的插件:

Shell
1
cordova plugin ls

下面的命令用来移除已经添加的插件:

Shell
1
cordova plugin rm cordova-plugin-console

下面的命令用来给应用程序添加插件:

Shell
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 )注册,通过下面的命令添加:

Shell
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下没有对应物,会直接复制到特定平台的资产目录下。

CLI命令说明

命令格式: cordova 子命令 [选项] 

通用选项
选项 说明
-v, --version 打印CLI版本
-d, --verbose 显示CLI命令的活动的详细信息
--no-update-notifier 禁止检查CLI的版本更新
全局命令
子命令 说明
create 创建一个新的Cordova工程
help 显示命令帮助:
Shell
1
2
# 显示run子命令的帮助信息
cordova run --help
工程命令
子命令 说明
info 显示当前工程的详细信息,例如哪些平台被支持,添加了哪些插件
requirements 检查并显示指定平台的要求,例如SDK版本
platform

管理工程支持的平台:
add 添加一个平台支持
remove 移除平台支持
list 列出已经安装和可用的平台
update 更新特定平台使用的Cordova版本
check 列出支持cordova platform update的平台

plugin 管理工程使用的插件:
add 添加一个插件
remove 移除一个插件
list 列出当前安装的插件列表
search 从插件仓库搜索插件
prepare 拷贝、合并工程文件到目标平台,以备构建
compile 编译目标平台,命令格式:
cordova compile [PROD] [TARGET] [EXP] [PLATS] [-- POPTS] 

PROD:编译的变体, --debug|--release
TARGET:目标设备, --device|--emulator|--target=FOO
PLATS:目标平台,可以指定多个平台
POPTS:平台特定的选项 

build 等价于 cordova prepare && cordova compile 
clean 清除已经构建出的构件(artifacts)
run prepare、compile,并在设备或者模拟器上运行工程:
 --nobuild 不进行构建
--debug 部署Debug版本
--release  部署Release版本
emulate 等价于 cordova run --emulator 
serve

启动一个本地HTTP服务器,把工程作为Web服务使用:
cordova serve [PORT] 

此命令启动的服务与PhoneGap Developer App无法搭配使用,可以改用:

Shell
1
phonegap serve
以Android平台为中心的工作流

首先,参考文章:基于Eclipse ADT和Maven的Android开发 完整Android开发环境的搭建。

由于Android平台官方的开发工具现在是Android Studio,并且基于Gradle构建,所以最好搭建好Gradle环境和Gradle的Eclipse插件。可参考文章:Gradle学习笔记。

导入为Eclipse ADT工程

通过CLI创建Cordova工程后,一旦添加了Android平台的支持,就可以把platforms/android子目录作为工程导入到Eclipse ADT或者Android Studio。

以Eclipse ADT为例,操作步骤为:

  1. File ⇨ Import
  2. 在弹出的对话框中选择 Android ⇨ Existing Android Code Into Workspace,点击下一步
  3. 把Root Directory定位到Cordova工程的platforms/android目录,选择其中的两个工程,如下图:
    import-cordova-project
  4. 点击完成,工作区出现两个新的ADT工程,导入完毕

这两个工程就是普通的ADT工程。其中cordovalib是cordova-android的依赖库。在cordova-android上点击右键 ⇨ Run as ⇨ Android Application,即可打包并部署到设备上运行。

上述方式导入的工程结构比较混乱,如果后续开发脱离Cordova进行,建议清理其中不需要的目录和文件。如果不习惯基于Gradle进行构建,可以创建或者转换为Maven工程。

转换为Eclipse Gradle工程

安装了Gradle的Eclipse插件后,可以把platforms/android子目录转换为Gradle工程:

  1. File ⇨ Import
  2. 在弹出的对话框中选择 Gradle ⇨ Gradle Project,点击下一步
  3. 在弹出的对话框中,把Root folder定位到platforms/android子目录,然后点击右侧的Build Model按钮。Gradle从Maven仓库下载一些构件到Gradle缓存目录,完毕后显示如下画面:import-as-gradle-project
  4. 点击完成。你可以自由的修改Eclipse工程的名称
转换为Eclipse Maven工程

如果习惯于使用Maven进行构建工作,可以参考下面的步骤,把platforms/android子目录转换为Maven工程:

  1. 参考:基于Eclipse ADT和Maven的Android开发创建Android的Maven工程,设工程根目录为 %MVN_PROJECT_ROOT% 。删除自动生成的Activity、res目录,并转换为android-maven-plugin 4.3.0标准的工程结构
  2. 如果使用SVN,在目录%MVN_PROJECT_ROOT% 上设置属性svn:ignore为:
    1
    2
    3
    4
    target
    bin
    .*
    cli
  3. 通过CLI创建对应的(同名同包)Cordova工程,添加必要的插件,设工程根目录为 %CORDOVA_PROJECT_ROOT% 
  4. 创建Maven工程指向Cordova工程的符号链接:
    MS DOS
    1
    mklink /D %MVN_PROJECT_ROOT%\cli %CORDOVA_PROJECT_ROOT%
  5. 另外创建一个Android的Maven工程“cordova-android”,project.properties中设置 android.library=true ,表示这是一个库工程。设工程根目录为 %MVN_LIB_ROOT% 
  6. 修改 %MVN_PROJECT_ROOT%\pom.xml ,添加cordova-android的依赖,例如:
    XHTML
    1
    2
    3
    4
    5
    6
    <dependency>
        <groupId>org.apache.cordova</groupId>
        <artifactId>cordova-android</artifactId>
        <version>4.4.1-SNAPSHOT</version>
        <type>apklib</type>
    </dependency>
  7. 修改Cordova工程的 %CORDOVA_PROJECT_ROOT%\cli\platforms\android\build-extras.gradle 文件,添加以下Tasks:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    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] )
  8. 每当添加Cordova插件,或者修改Cordova工程中其它源码文件后,定位到 %MVN_PROJECT_ROOT%\cli目录,执行:
    cordovasyncdown.bat
    MySQL
    1
    2
    3
    4
    5
    @echo off
    call cordova prepare
    pushd platforms\android
    call gradle syncdown
    popd

    这会让所有修改从Cordova工程目录,同步到其Android平台子目录,然后再同步到Maven工程对应目录中。 

Android平台命令行工具

Android平台特定的命令行工具位于 platforms/android/cordova 子目录中,这些命令比Cordova CLI更有针对性,在以Android为中心的开发时,可以代替之:

Shell
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签名所需的信息:

JavaScript
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": ""
         }
     }
}
通过Gradle执行构建

自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签名需信息的属性文件的名称,属性文件的内容示例如下:

1
2
3
4
5
6
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构建脚本

如果需要扩展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设备或者模拟器上测试:

  1. 使用Maven: package android:deploy android:run 
  2. 使用ADT:在apk工程上面点击右键 Run As ⇨ Android Application

注意,必须让你的设备或者模拟器链接到当前机器上。

这两种方式都比较慢,每次部署都需要数十秒,非常浪费时间。因此可以使用PhoneGap提供的设备端工具,该工具可以免部署的运行Cordova应用。

理解Cordova HelloWorld
启动

应用启动后,会自动启用一个WebView,加载config.xml中指定的起始页(默认index.html),让HTML页面占据整个屏幕空间。

例如,对Android平台,系统会执行MainActivity,该Activity是CordovaActivity的子类:

Java
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);
    }
}
HTML和JavaScript脚本
index.html
XHTML
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>

index.js
JavaScript
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();
开发与调试指南
开发最佳实践
单页面应用(SPA)

Cordova应该是基于单页面应用设计的。所谓单页面应用,是指不存在URL导航的Web应用。单页面引用仅在最初加载一次页面,后续的更新通过JavaScript、Ajax完成。

单页面应用有利于增强移动应用的性能,因为避免了重复加载各种资产文件(脚本、图片)。单页面应用对Cordova有额外的好处,因为Cordova应用必须等待deviceready事件,URL导航导致重复的事件等待。

性能方面的考虑

Cordova开发者往往错误的假设,移动设备能够达到和桌面应用一样性能。实际上,尽管移动设备已经长足发展了近十年,在电池、性能方面,仍然无法和桌面应用比较。注意以下几个方面:

  1. click vs touch:click事件被大量误用。大部分移动设备添加300ms的延迟,用以区分touch和touch hold。使用touchstart、touchend可能有很大的性能改善——避免频繁的UI更新和其它行为
  2. CSS 变换 vs DOM操控:硬件加速的CSS变换比起基于JavaScript的动画,性能有极大的优势
  3. 网络延迟:尽量使用Cordova支持的本地存储机制,避免反复通过网络获取数据、资源
识别并处理离线状态

使用Cordova提供的offline、online事件的支持,你可以识别出离线状态,并正确的响应用户。注意,这两种事件并不是非常可靠,有时候你应当使用Ajax来判断设备是否真正的断开网络了。

注意:苹果的商店拒绝不能正确处理离线状态的APP上架。

数据存储方案

有几种存储方案可以供Apache Cordova应用使用:

  1. LocalStorage:同步的基于键值对的存储
  2. WebSQL:基于SQL语句的API,支持Android、iOS
  3. IndexedDB:支持Windows 8、Windows Phone 8
  4. cordova-plugin-file插件:缓存数据到本地文件系统
测试Cordova应用

测试Cordova应用时,你可以使用真实设备、模拟器,甚至是桌面浏览器。但是,在多种真实设备上测试是很有必要的: 

  1. 模拟器(Simulator)不能模拟一些真实存在的情况:例如低电池时,应用会出现某个问题,这个问题在模拟器上难以体现
  2. 模拟器(Emulator)和真实设备的行为存在不一致:某些模拟器会导致页面显示混乱,但是在真实设备上没有这种问题。4.1.2的AVD,运行5.4版本Cordova的HelloWorld应用,就存在页面显示混乱的情况。你可能需要禁用Host GPU加速
  3. Simulator往往比真实设备快很多,而Emulator则慢很多
  4. 在不同OS的设备上测试是有必要的,应用的行为可能不符合预期
PhoneGap Developer App

使用PGDA可以避免编译、打包、部署到设备的繁冗步骤,在开发阶段能够节约很多时间。

调试Cordova应用
iOS Debugging

使用XCode可以调试Cordova应用Native的那一部分。

Safari Remote Debugging with Web Inspector

使用Safari的web inspector,你可以Debug Webview和Cordova应用的JavaScript代码,仅支持OS X和iOS6+。通过OS X中的Safari连接到设备(或模拟器),可以使用Safari的dev tools调试Cordova应用。

Chrome Remote Debugging

与Safari类似,Chrome Dev Tools也可以用来调试Cordova应用。需要Android 4.4、API 19+、Chrome 30+才可以进行调试。使用WebKit proxy,Chrome Dev Tools也可以调试iOS应用。

Ripple

Ripple是一个基于Web的移动设备环境模拟器,用于快速开发基于Apache Cordova、Blackberry WebWorks等框架的移动Web应用。

GapDebug

综合性的移动应用调试工具,支持在现代移动设备(iOS、Android)上调试混合应用,对PhoneGap、Cordova提供非常好的支持。

该工具实质上是对Chrome Dev Tools的包装和增强。

具体参见:使用GapDebug调试Phonegap应用

Cordova生命周期事件

除非特别说明所有事件均在 document 对象上发布。

事件 说明
deviceready 对任何Cordova应用程序都非常关键,该事件的发生意味着Cordova设备API已经加载完毕、并可以使用。用法示例:
JavaScript
1
2
3
4
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
    // 现在可以安全的使用Cordova设备API了
}
pause 当应用程序进入后台时,发布该事件
注意:在iOS中,此事件的监听器对Cordova API的调用、对alert、console.log的调用都被阻塞,直到resume发生时才执行。
resume 当应用程序从后台返回前台执行时,发布此事件
注意:在iOS中,resume的监听器中,对交互式函数(例如alert)的调用,必须异步执行,否则应用程序会挂起。下面是正确的代码示例:
JavaScript
1
2
3
4
5
6
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%、或者插上电源、拔下电源)时发布。可以访问事件对象的如下属性:

  1. level,电量百分比数值,0-100
  2. isPlugged,布尔型,判断是否插入电源
batterylow
batterystatus
插件cordova-plugin-network-information引入的事件
online  当设备上线(连接到互联网)时,以及设备下线时,发布对应的事件
offline
Cordova插件API

Cordova自带了一个最小化的API集合,工程可以通过插件添加额外的API。本节介绍Cordova核心插件的API。

本节中,使用样式区分不同的API类型:

  1. 斜体:表示静态(static)成员
  2. 下划线标注:类型定义(typedef)
  3. 括号后缀:表示方法/函数
cordova-plugin-battery-status

提供三个电池相关的事件,如上节所述

cordova-plugin-camera

该插件定义了一个全局的 navigator.camera 对象,用于拍摄照片、从系统的图片库选择照片。该插件常用API如下表:

所有者 方法/属性 说明
navigator.
camera
getPicture()
JavaScript
1
2
3
4
5
camera.getPicture(
    onSuccess successCallback,
    onError errorCallback,
    CameraOptions options
)

使用摄像头拍照,或者从设备的图片库中获取照片。如果
options.sourceType == Camera.PictureSourceType. :

  1. CAMERA(默认):打开摄像头并拍照,一旦拍照完毕,则关闭默认照相程序,并返回到当前应用
  2. PHOTOLIBRARY、SAVEDPHOTOALBUM:显示一个对话框,让用户选择一个既有的照片。此时当前函数返回一个CameraPopoverHandle,用于重新定位图片选择对话框(例如设备的方向改变时)

图片通过Base64编码或者URI的方式(默认)传递给 successCallback 。如果
options.destinationType == Camera.DestinationType. :

  1. FILE_URI(默认):返回文件URI,对于Android返回 content:// 形式的URI。这是最好的方式,因为现代设备的拍的照片、图片库中的照片的质量可能很高,而此插件没有对其进行缩小、压缩处理,因此使用DATA_URL可能导致内存方面的问题
  2. NATIVE_URI:返回Native的URI
  3. DATA_URL:返回Base64编码的字符串

得到图片URI或者Base64编码后,你可以:

  1. 使用 <img> 渲染到当前页面
  2. 存储到本地
  3. 发送到远程服务器
cleanup() 清理图片临时文件,仅当options.sourceType为CAMERA、options.destinationType为FILE_URI时需要调用
仅支持iOS
onError() 获取照片的错误回调,入参:
  1. sring message:来自设备Native代码的错误信息
onSuccess() 获取照片的成功回调,入参:
  1. sring imageData:Base64图片数据或者URI
CameraOptions

用于指定摄像头参数的对象,包含以下属性:

  1. quality:图片质量,0-100,100表示全分辨率+无损压缩。注意摄像头的分辨率无法得知
  2. destinationType、sourceType:参考getPicture()方法的介绍
  3. allowEdit:在选择前,允许简单的编辑照片
  4. encodingType:图像编码方式,默认Camera.EncodingType.JPEG
  5. targetWidth、targetHeight:目标图片的尺寸,纵横比保持不变
  6. mediaType:当sourceType为PHOTOLIBRARY 或SAVEDPHOTOALBUM时,指定媒体类型,默认Camera.MediaType.PICTURE
  7. correctOrientation:修正照片的方向
  8. saveToPhotoAlbum:在拍照后,保存照片到设备相册
  9. popoverOptions:仅用于iOS的iPad,用来指定popover的位置
  10. cameraDirection:使用前摄像头还是后摄像头,默认Camera.Direction.BACK
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
cordova-plugin-console

该插件确保 console.log() 能够正常工作,为非Android平台提供额外的函数支持。该插件定义了一个全局的 console 对象,并引入以下方法:

方法 说明
log 这些方法支持C语言printf风格的字符串格式化:
  1. %j 格式化为JSON
  2. %o 格式化为JSON
  3. %c 格式化为''
  4. %% 转义%
  5. %* 其他均使用目标参数的 toString() 方法进行打印
error
exception
warn
info
debug
assert
dir
dirxml
time
timeEnd
table
Cordova配置文件:config.xml

位于Cordova工程根目录的配置文件config.xml,可以在全局上控制Cordova应用程序的行为:

  1. 指定核心Cordova API特性
  2. 启用Cordova插件
  3. 进行平台相关的设置

config.xml指定的配置会影响所有应用程序和CordovaWebView实例。

当使用Cordova的命令行接口(CLI)构建工程时,该文件会被修改并拷贝到各平台的对应目录,例如 platforms/ios/AppName/config.xml 

全局与跨平台配置选项
XHTML
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>
安卓配置选项
XHTML
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子目录中。

保存平台版本

执行下面的命令,即可保存特定版本的平台:

Shell
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中出现类似下面的条目:

XHTML
1
<engine name="android" spec="~4.0.0" />

执行下面的命令,可以更新特定平台的版本: 

Shell
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:

Shell
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中出现类似下面的条目:

XHTML
1
<plugin name="cordova-plugin-console" spec="~1.0.0" />

执行下面的命令,可以更新特定插件的版本: 

Shell
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都需要关注的内容,用户需要它们的私人信息被合理使用,并不泄漏。下面是一些被广泛接受的建议:

  1. 隐私策略(Privacy Policy):使用平白的语言声明你的App的隐私策略
  2. 敏感信息的收集:在获取敏感信息,例如通讯录、地理位置、摄像机信息前,获得用户的许可
  3. 与第三方共享敏感信息:如果你的App获取的信息需要与第三方网站/应用共享,应当获得用户许可
  4. 仅在必要的时候才收集隐私信息
安全指南

本节包含一些开发Cordova应用时,处理安全问题的最佳实践。

  1. 不要使用自签名的网站证书:如果你的服务器使用SSL,务必使用知名CA签发的数字证书
  2. 避免使用IFrame引用外部网页(不受你控制的第三方网站):位于白名单中的网页,如果运行在IFrame中,它是可以访问Native Cordova Bridge的。引用外部链接,最好使用InAppBrowser,外部链接不会有机会执行Cordova API
  3. 关于域名白名单:Android API 10以下、WP8中的IFrame和XMLHttpRequest,都不受域名白名单控制,这意味着任何网页都可以调用Cordova接口
  4. 不要缓存敏感信息,例如用户名、密码
  5. 避免使用 eval() ,除非你确切知道脚本的内容
域名白名单配置

域名白名单(Domain whitelisting)机制用来控制Cordova应用对外部域名的访问。默认的,新创建的App被允许访问所有外部域名,在产品发布时,你必须确定需要访问哪些域名,并进行白名单配置。

对于Android和iOS,上述安全策略通过插件cordova-plugin-whitelist实现,具有更好的安全性和可配置性,推荐使用:

config.xml
XHTML
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> 元素进行白名单设置:

config.xml
XHTML
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="*" />
内容安全策略(Content Security Policy)

参见:HTML知识集锦

CSP用于控制图片、Ajax、 <video> 、WebSocket等所有请求。上面的whitelist插件的network request whitelist,只能控制图片、Ajax,因此有必要在HTML的 <meta> 配置CSP:

index.html
XHTML
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 Hooks

钩子是Cordova Application、Plugin添加的特殊脚本,用于定制化Cordova的命令。可以在hooks目录添加钩子,也可以在config.xml、plugin.xml中声明钩子。钩子按照下面的顺序串行执行:

  1. 来自/hooks目录的Application钩子
  2. 来自config.xml的Application钩子
  3. 来自plugins/.../plugin.xml的插件钩子

目前支持的钩子类型有:

  1. after_build
  2. after_compile
  3. after_clean
  4. after_docs
  5. after_emulate
  6. after_platform_add
  7. after_platform_rm
  8. after_platform_ls
  9. after_plugin_add
  10. after_plugin_ls
  11. after_plugin_rm
  12. after_plugin_search
  13. after_plugin_install  仅执行被安装插件声明在plugin.xml中的钩子
  14. after_prepare
  15. after_run
  16. after_serve
  17. before_build
  18. before_clean
  19. before_compile
  20. before_docs
  21. before_emulate
  22. before_platform_add
  23. before_platform_rm
  24. before_platform_ls
  25. before_plugin_add
  26. before_plugin_ls
  27. before_plugin_rm
  28. before_plugin_search
  29. before_plugin_install  仅执行被安装插件声明在plugin.xml中的钩子
  30. before_plugin_uninstall  仅执行被卸载插件声明在plugin.xml中的钩子
  31. before_prepare
  32. before_run
  33. before_serve
  34. pre_package 仅支持Windows、Windows Phone平台
在何处存放钩子

如果把钩子存放在hooks目录,必须遵从严格的命名规定: hooks/钩子类型/脚本文件.js 。例如,如果你需要在prepare命令执行完毕后,附加一些行为,可以编写脚本: hooks/after_prepare/cordova-syncdown.js 。应避免使用hooks目录,未来的Cordova版本可能废弃这种方式。

在config.xml、plugin.xml中声明钩子的方式如下:

config.xml
XHTML
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模块定义的方式如下:

JavaScript
1
2
3
module.exports = function( ctx )
{
}

其中ctx包含很多上下文信息: 

JavaScript
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在构建时自动下载gradle

修改$CORDOVA_PROJECT_ROOT/platforms/android/cordova/lib/build.js 中如下变量的值:

JavaScript
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中的内容:

platforms/android/build.gradle
1
2
3
4
5
repositories {
    mavenLocal()
    //添加上面一行的内容
    mavenCentral()
}

 

← IntelliJ平台知识集锦
ProGuard学习笔记 →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • PhoneGap学习笔记
  • Sencha Cmd学习笔记
  • 使用GapDebug调试Phonegap应用
  • 基于Eclipse ADT和Maven的Android开发
  • Android Studio知识集锦

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • Ceph学习笔记 27 people like this
  • 基于Calico的CNI 27 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2