Android 平台指南

本指南将帮助您设置开发环境,以便在 Android 设备上构建 Cordova 应用。此外,它还提供了将特定于 Android 的命令行工具集成到您的开发工作流程中的选项。

无论您是打算使用特定于 Android 的命令行工具还是 Cordova CLI 命令,您都需要安装和配置必要的先决条件。

Android API 级别支持

下表列出了与 Cordova-Android 发布版本相对应的支持的 Android API 级别(Android 版本)

cordova-android 版本 Android API 级别(Android 版本) 库 & 工具版本
12.0.x 24 (7.0) - 33 (13.0)
  • 构建工具:^33.0.2
  • Kotlin: 1.7.21
  • Gradle: 7.6
  • Android Gradle 插件: 7.4.2
  • AndroidX Compat 库: 1.6.1
  • AndroidX WebKit 库: 1.6.0
  • AndroidX Core SplashScreen: 1.0.0
  • Google Services Gradle 插件: 4.3.15
11.0.x 22 (5.1) - 32 (12L)
  • 构建工具:^32.0.0
  • Kotlin: 1.7.21
  • Gradle: 7.4.2
  • Android Gradle 插件: 7.2.1
  • AndroidX Compat 库: 1.4.2
  • AndroidX WebKit 库: 1.4.0
  • AndroidX Core SplashScreen: 1.0.0-rc01
  • Google Services Gradle 插件: 4.3.10
10.1.x 22 (5.1) - 30 (11.0)
  • 构建工具:^30.0.3
  • Kotlin: 1.5.21
  • Gradle: 7.1.1
  • Android Gradle 插件: 4.2.2
  • AndroidX Compat 库: 1.3.1
  • AndroidX WebKit 库: 1.4.0
  • Google Services Gradle 插件: 4.3.8
10.0.x 22 (5.1) - 30 (11.0)
  • 构建工具:^30.0.3
  • Kotlin: 1.5.20
  • Gradle: 7.1.1
  • Android Gradle 插件: 4.2.2
  • AndroidX Compat 库: 1.3.0
  • AndroidX WebKit 库: 1.4.0
  • Google Services Gradle 插件: 4.3.5
9.X.X 22 (5.1) - 29 (10.0) -
8.X.X 19 (4.4) - 28 (9.0) -
7.X.X 19 (4.4) - 27 (8.1) -
6.X.X 16 (4.1) - 26 (8.0) -
5.X.X 14 (4.0) - 23 (6.0) -
4.1.X 14 (4.0) - 22 (5.1) -
4.0.X 10 (2.3.3) - 22 (5.1) -
3.7.X 10 (2.3.3) - 21 (5.0) -

注意: 上面列出的 cordova-android 版本不是 Cordova CLI 版本。

要查找您的 Cordova 项目中安装的 Cordova-Android 包的版本,请导航到项目的根目录并执行命令 cordova platform ls

Cordova 通常会停止支持在 Google 的分发仪表板上低于 5% 的 Android 版本。 您可以参考 Google 的 分发仪表板 以获取更多信息。

系统要求

Cordova-Android 依赖于 Android SDK,该 SDK 可以安装在 macOS、Linux 或 Windows 操作系统上。

为确保您的系统满足必要的要求,请参考 Google 提供的“安装 Android Studio”指南。

所需的软件和工具

Java 开发工具包 (JDK)

如果您使用的是 cordova-android 10.0.0 或更高版本,请安装 Java 开发工具包 (JDK) 11

如果您使用的是低于 cordova-android 10.0.0 的任何版本,请安装 Java 开发工具包 (JDK) 8

必须根据您的 JDK 安装路径设置 JAVA_HOME 环境变量。请参阅设置环境变量部分,了解如何设置环境变量。或者,从 cordova-android 10.0.0 或更高版本开始,可以设置 CORDOVA_JAVA_HOME 来代替 JAVA_HOME,允许专门用于 Cordova 开发的 JDK 安装。

Gradle

从 Cordova-Android 6.4.0 开始,需要安装 Gradle

在 Windows 上安装时,您需要将 Gradle 的二进制目录的路径添加到您的 path 环境变量中。请参阅 设置环境变量),了解如何配置系统环境变量。

注意: 这是系统的 Gradle 版本。 系统的 Gradle 二进制文件将创建 Gradle Wrapper 文件,该文件声明并获取构建 Android 应用程序所需的适当版本的 Gradle。 系统级别和项目级别的 Gradle 版本可能不匹配,也不需要匹配。 项目级别的 Gradle 版本在 Cordova-Android 的包中定义,并根据 Android 支持的内容进行设置。

Android Studio

下载并安装 Android Studio。 按照链接的 Android 开发人员站点上的说明开始操作。

首次打开 Android Studio 将指导您完成安装 Android SDK 包的过程。

SDK 包

建议根据项目安装的 Cordova-Android 版本安装最新版本的 SDK 平台和 SDK 工具。请参阅 Android API 级别支持部分,了解根据 Cordova-Android 版本支持的版本。

安装 SDK 平台
  1. 打开 Android Studio 的
  2. 打开 SDK 管理器 (工具 > SDK 管理器)
  3. 单击 SDK 平台 选项卡
  4. 选择与Android API 级别支持中基于最高支持的 SDK 相匹配的 Android 版本
  5. 单击应用

例如:如果项目安装了 [email protected],则最高支持的 SDK 是 33。在上述步骤 3 中,应选择“Android 13.0 (Tiramisu)”。

Android SDK Platform

安装 Android SDK 构建工具
  1. 打开 Android Studio 的
  2. 打开 SDK 管理器 (工具 > SDK 管理器)
  3. 单击 SDK 工具 选项卡
  4. 勾选 显示软件包详细信息
  5. 展开 Android SDK 构建工具
  6. 根据Android API 级别支持,检查最高支持的构建工具。
  7. 单击应用

例如:如果项目安装了 [email protected],则最高支持的 SDK 是 33。我们要选择 33.x 的最高可用版本。在撰写本文时,应在步骤 6 中选择“33.0.2”。

Android SDK Build-Tools

安装 SDK 命令行工具(最新)
  1. 打开 Android Studio 的
  2. 打开 SDK 管理器 (工具 > SDK 管理器)
  3. 单击 SDK 工具 选项卡
  4. 勾选 显示软件包详细信息
  5. 展开 Android SDK 命令行工具(最新)
  6. 勾选 Android SDK 命令行工具(最新)
  7. 单击应用

SDK Command-line Tools (latest)

安装 Android SDK 平台工具
  1. 打开 Android Studio 的
  2. 打开 SDK 管理器 (工具 > SDK 管理器)
  3. 单击 SDK 工具 选项卡
  4. 勾选 显示软件包详细信息
  5. 勾选 Android SDK 平台工具
  6. 单击应用

Android SDK Platform-Tools

安装 Android 模拟器
  1. 打开 Android Studio 的
  2. 打开 SDK 管理器 (工具 > SDK 管理器)
  3. 单击 SDK 工具 选项卡
  4. 勾选 显示软件包详细信息
  5. 勾选 Android 模拟器
  6. 单击应用

Android Emulator

设置环境变量

Cordova 的 CLI 需要特定的环境变量才能正常运行。 如果环境变量缺失,CLI 将尝试临时解析变量。 如果缺失的变量无法解析,则必须手动设置。

必须设置以下变量

  • JAVA_HOME - 指向您的 JDK 安装位置的环境变量
  • ANDROID_HOME - 指向您的 Android SDK 安装位置的环境变量

还建议更新 PATH 环境变量以包含以下目录。

  • cmdline-tools/latest/bin
  • platform-tools
  • build-tools
  • emulator
    • apksignerzipalign 工具需要此项。

注意: 上述目录通常位于 Android SDK ROOT 中。

macOS 和 Linux

在 Mac 或 Linux 上,使用文本编辑器创建或修改 ~/.bash_profile 文件。

要设置环境变量,请添加一行使用 export 的行,如下所示(将路径替换为您的本地安装)

export ANDROID_HOME=/Development/android-sdk/

要更新您的 PATH,请添加一行类似于以下内容的行(将路径替换为您本地 Android SDK 安装的位置)

export PATH=$PATH:$ANDROID_HOME/platform-tools/
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin/
export PATH=$PATH:$ANDROID_HOME/build-tools
export PATH=$PATH:$ANDROID_HOME/emulator/

重新加载终端以查看此更改反映或运行以下命令

source ~/.bash_profile

Windows

这些步骤可能会因您安装的 Windows 版本而异。在进行更改后关闭并重新打开任何命令提示符窗口,以查看它们是否已反映。

  1. 单击 开始 菜单或按 Windows 键 (Win)
  2. 在搜索栏中键入 环境变量
  3. 选择 编辑系统环境变量 选项
  4. 在出现的窗口中单击 环境变量… 按钮。
要创建新的环境变量
  1. 单击 新建… 按钮
  2. 键入 变量名称
  3. 键入 变量值
  4. 单击 确定 按钮
要设置您的 PATH
  1. 从已定义的变量列表中选择 PATH
  2. 单击 编辑… 按钮
  3. 单击 新建 按钮
  4. 键入相关位置。

重复步骤 3 和 4,直到添加所有路径。

示例路径(将路径替换为您本地 Android SDK 安装的位置)

C:\Users\[your user]\AppData\Local\Android\Sdk\platform-tools
C:\Users\[your user]\AppData\Local\Android\Sdk\cmdline-tools\latest\bin
C:\Users\[your user]\AppData\Local\Android\Sdk\build-tools
C:\Users\[your user]\AppData\Local\Android\Sdk\emulator

添加所有路径后,单击 确定 按钮,直到关闭所有打开的用于设置和编辑环境变量的窗口。

项目配置

设置模拟器

如果您希望在 Android 模拟器上运行您的 Cordova 应用,您首先需要创建 Android 虚拟设备 (AVD)。

请参阅以下 Android 文档以了解更多详细信息

正确配置 AVD 后,您应该能够通过运行以下命令将您的 Cordova 应用程序部署到模拟器

cordova run --emulator

配置 Gradle

Cordova-Android 项目是使用 Gradle 构建的。

设置 Gradle 属性

可以通过设置 Cordova 公开的某些 Gradle 属性的值来配置 Gradle 构建。

以下属性可用

属性 描述
cdvAndroidXAppCompatVersion 设置 androidx.appcompat:appcompat 库的版本。
cdvAndroidXWebKitVersion 设置 androidx.webkit:webkit 库的版本。
cdvBuildArch 覆盖应用程序构建的目标架构。默认值由 Cordova 的构建脚本自动检测。
cdvBuildMultipleApks 如果设置此项,将生成多个 APK 文件:每个库项目支持的原生平台(x86、ARM 等)一个。如果您的项目使用大型原生库,这可能很重要,因为这会大大增加生成的 APK 的大小。如果未设置,则将生成一个可在所有设备上使用的 APK。
cdvBuildToolsVersion 覆盖自动检测到的 android.buildToolsVersion 值。
cdvCompileSdkVersion 设置应用程序编译所用的框架 SDK 版本。此设置将覆盖对 android.compileSdkVersion 值的自动检测。
cdvDebugSigningPropertiesFile 默认值:debug-signing.properties
指向包含调试版本签名信息的 .properties 文件的路径(请参阅签名应用程序)。当您需要与其他开发人员共享签名密钥时很有用。
cdvMaxSdkVersion 设置应用程序可运行的最大 API 级别。
cdvMinSdkVersion 覆盖在 AndroidManifest.xml 中设置的 minSdkVersion 值。在基于 SDK 版本创建多个 APK 时很有用。
cdvReleaseSigningPropertiesFile 默认值:release-signing.properties
指向包含发布版本签名信息的 .properties 文件的路径(请参阅签名应用程序)。
cdvSdkVersion 覆盖 targetSdkVersion 值。
cdvVersionCode 覆盖在 AndroidManifest.xml 中设置的 versionCode。
cdvVersionCodeForceAbiDigit 是否在仅构建单个 APK 时,将 0 “abi 位”附加到 versionCode。

您可以通过以下四种方式之一设置这些属性:

  • 使用环境变量

    示例

      export ORG_GRADLE_PROJECT_cdvMinSdkVersion=20
      cordova build android
    
  • 使用带有 Cordova buildrun 命令的 --gradleArg 标志

    示例

      cordova run android -- --gradleArg=-PcdvMinSdkVersion=20
    
  • 在项目的 Android 平台目录中创建 gradle.properties

    <project-root>/platforms/android 目录中创建一个名为 gradle.properties 的文件,内容如下:

    示例文件内容

      cdvMinSdkVersion=20
    
  • 使用 `build-extras.gradle` 文件扩展 build.gradle

    <project-root>/platforms/android/app 目录中创建一个名为 build-extras.gradle 的文件,内容如下:

      ext.cdvMinSdkVersion = 20
    

后两种选项都涉及在您的 Android 平台文件夹中包含一个额外的文件。通常不鼓励编辑此文件夹的内容,因为这些更改很容易丢失或被覆盖。相反,这些文件应作为构建命令的一部分复制到文件夹中,方法是使用 before_build hook 脚本

扩展 build.gradle

如果您需要自定义 build.gradle 文件,而不是直接编辑它,建议创建一个名为 build-extras.gradle 的同级文件。如果存在此文件,则主 build.gradle 脚本将包含此文件。此文件必须放置在 Android 平台目录的 app 文件夹中 (<your-project>/platforms/android/app)。建议使用 before_build hook 脚本 将此文件复制过来。

这是一个示例

// Example build-extras.gradle
// This file is included at the beginning of `build.gradle`

// special properties (see `build.gradle`) can be set and overwrite the defaults
ext.cdvDebugSigningPropertiesFile = '../../android-debug-keys.properties'

// normal `build.gradle` configuration can happen
android {
  defaultConfig {
    testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
  }
}
dependencies {
  androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2', {
    exclude group: 'com.android.support', module: 'support-annotations'
  }
}

// When set, this function `ext.postBuildExtras` allows code to run at the end of `build.gradle`
ext.postBuildExtras = {
    android.buildTypes.debug.applicationIdSuffix = '.debug'
}

请注意,插件还可以通过以下方式包含 build-extras.gradle 文件

<framework src="some.gradle" custom="true" type="gradleReference" />

配置 Gradle JVM 参数

要更改 Gradle JVM 参数,可以将 --jvmargs 标志与 Cordova 的 buildrun 命令一起使用。这主要用于控制 Gradle 在构建过程中允许使用的内存量。建议至少允许 2048 MB。

默认情况下,JVM 参数的值为 -Xmx2048m。要增加允许的最大内存量,请使用 -Xmx JVM 参数。下面给出一个示例:

cordova build android -- --jvmargs='-Xmx4g'

支持以下单位:

单位 示例
千字节 k -Xmx2097152k
兆字节 m -Xmx2048m
千兆字节 g -Xmx2g

设置版本代码

要更改应用程序生成的 apk 的版本代码,请在应用程序的config.xml 文件的 widget 元素中设置 android-versionCode 属性。

如果未设置 android-versionCode,则将使用 version 属性确定版本代码。例如,如果版本为 MAJOR.MINOR.PATCH

versionCode = MAJOR * 10000 + MINOR * 100 + PATCH

如果您的应用程序启用了 cdvBuildMultipleApks Gradle 属性(请参阅设置 Gradle 属性),则您的应用程序的版本代码也将乘以 10,以便代码的最后一位可以用于指示构建 apk 的架构。无论版本代码是从 android-versionCode 属性获取还是使用 version 生成,都会进行此乘法运算。

注意: 请注意,添加到您的项目中的某些插件可能会自动设置此 Gradle 属性。

注意: 更新 android-versionCode 属性时,不建议增加从构建的 apk 中获取的版本代码。建议基于 config.xml 文件中的 android-versionCode 属性中的值增加代码。这是因为 cdvBuildMultipleApks 属性会导致构建的 apk 中的版本代码乘以 10,因此使用该值将导致您的下一个版本代码是原始代码的 100 倍,等等。

签名应用程序

建议先阅读 Android 的签名您的应用文档,因为它包含创建签名所需文件的必要步骤。

使用标志

要签名应用程序,您需要以下参数:

参数 标志 描述
密钥库 --keystore 指向可以保存一组密钥的二进制文件的路径。
密钥库密码 --storePassword 密钥库的密码
别名 --alias 指定用于签名的私钥的 ID。
密码 --password 指定私钥的密码。
密钥库的类型 --keystoreType 默认值:根据文件扩展名自动检测。
可以是 pkcs12 或 jks。
包类型 --packageType 默认值:调试为 apk,发布为 bundle
指定是构建 APK 还是AAB (Android App Bundle) 文件。
可接受的值:apkbundle

在使用Cordova CLI buildrun 命令时,可以将以上参数指定为参数。

注意:您应该使用双 -- 来指示这些是特定于平台的参数。

示例

cordova run android --release -- --keystore=../my-release-key.keystore --storePassword=password --alias=alias_name --password=password --packageType=bundle.

使用 build.json

或者,您可以在构建配置文件 (build.json) 中指定签名参数。

默认情况下,如果 build.json 文件存在于项目的根目录中,它将自动被检测到并使用。如果该文件未位于项目的根目录中或有多个配置文件,则必须使用指向该文件路径的命令行参数 --buildConfig

示例 build.json 配置文件:

{
    "android": {
        "debug": {
            "keystore": "../android.keystore",
            "storePassword": "android",
            "alias": "mykey1",
            "password" : "password",
            "keystoreType": "",
            "packageType": "apk"
        },
        "release": {
            "keystore": "../android.keystore",
            "storePassword": "",
            "alias": "mykey2",
            "password" : "password",
            "keystoreType": "",
            "packageType": "bundle"
        }
    }
}

还支持混合和匹配命令行参数和 build.json 中的参数。命令行参数中的值优先。这对于在命令行中指定密码非常有用。

使用 Gradle

您还可以通过包含 .properties 文件并使用 cdvReleaseSigningPropertiesFilecdvDebugSigningPropertiesFile Gradle 属性指向该文件来指定签名属性(请参阅设置 Gradle 属性)。

示例文件内容:

storeFile=relative/path/to/keystore.p12
storePassword=SECRET1
storeType=pkcs12
keyAlias=DebugSigningKey
keyPassword=SECRET2

自动化签名需要 storePasswordkeyPassword 属性。

调试

有关 Android SDK 附带的调试工具的详细信息,请参阅Android 开发者文档中的调试。此外,Android 开发者文档中的调试 Web 应用提供了在 Webview 中调试应用程序运行部分内容的介绍。

在 Android Studio 中打开项目

可以在Android Studio中打开 Cordova-Android 项目。如果您希望使用 Android Studio 的内置 Android 调试和分析工具或您正在开发 Android 插件,这将很有用。

注意: 在 Android Studio 中打开项目时,建议不要在 IDE 中编辑代码。在 Android Studio 中编辑将编辑项目 platforms 目录中的代码。它不会更新项目根目录 www)目录中的代码。这些更改很容易被覆盖。相反,请编辑 www 文件夹并通过运行 cordova prepare 来复制您的更改。

希望在 Android Studio 中编辑其原生代码的插件开发人员应该在使用 cordova plugin add 将其插件添加到项目时使用 --link 标志。这将在插件源目录和项目的 platforms 目录之间创建一个插件文件的符号链接。

在 Android Studio 中打开 Cordova-Android 项目:

  1. 启动 Android Studio
  2. 单击 打开 按钮 欢迎来到 Android Studio
  3. 导航到项目的 Android 平台目录:(<project-root>/platforms/android
  4. 单击 打开

导入完成后,您应该可以直接从 Android Studio 构建和运行该应用。

有关更多资源,请参阅:

Hello Cordova MainActivity

升级

有关升级您的 cordova-android 版本的说明,请参阅本文

生命周期指南

Cordova 和 Android

原生 Android 应用通常由用户与之交互的一系列活动组成。可以将活动视为构成应用程序的各个屏幕;应用程序中的不同任务通常都有其自己的活动。每个活动都有自己的生命周期,该生命周期在活动进入和离开用户设备的前台时被维护。

相反,Android 平台上的 Cordova 应用程序在嵌入在单个 Android 活动中的 Webview 中执行。此活动的生命周期通过触发的文档事件暴露给您的应用程序。事件不保证与 Android 的生命周期保持一致,但它们可以为保存和恢复状态提供指导。这些事件大致映射到以下 Android 回调:

Cordova 事件 大致对应的 Android 事件 含义
deviceready onCreate() 应用程序正在启动(不是从后台启动)
pause onPause() 应用程序正在移动到后台
resume onResume() 应用程序正在返回到前台

大多数其他 Cordova 平台都有类似的生命周期概念,并且当用户的设备上发生类似的操作时,应该触发相同的事件。但是,由于原生 Activity 生命周期,Android 带来了一些独特的挑战,有时可能会显现出来。

Android 有什么不同?

在 Android 中,如果设备内存不足,操作系统可以选择杀死后台活动以释放资源。不幸的是,当持有你的应用程序的活动被杀死时,你的应用程序所在的 Webview 也会被销毁。在这种情况下,你的应用程序所维护的任何状态都将丢失。当用户导航回到你的应用程序时,操作系统将重新创建 Activity 和 Webview,但你的 Cordova 应用程序的状态不会自动恢复。因此,你的应用程序必须意识到触发的生命周期事件,并维护适当的状态,以确保用户离开应用程序时,他们在应用程序中的上下文不会丢失。

这种情况何时会发生?

只要你的应用程序离开用户的视线,就有可能被操作系统销毁。主要有两种情况会导致这种情况。第一种也是最明显的情况是当用户按下 Home 键或切换到另一个应用程序时。

然而,还有第二种(也是更微妙的)情况,某些插件可能会引入。如上所述,Cordova 应用程序通常被限制在包含 Webview 的单个活动中。但是,在某些情况下,其他活动可能会被插件启动,并临时将 Cordova 活动推到后台。这些其他活动通常是为了使用设备上安装的本机应用程序执行特定任务而启动的。例如,Cordova 相机插件会启动设备上本机安装的任何相机活动来拍照。以这种方式重用已安装的相机应用程序会让你的应用程序在用户尝试拍照时感觉更像是一个本机应用程序。不幸的是,当本机活动将你的应用程序推到后台时,操作系统有可能将其杀死。

为了更清楚地理解第二种情况,让我们通过一个使用相机插件的示例来说明。假设你的应用程序需要用户拍摄个人资料照片。如果一切按计划进行,应用程序中的事件流程将如下所示:

  1. 用户正在与你的应用程序交互,需要拍照
  2. 相机插件启动本机相机活动
    • Cordova 活动被推到后台(触发 pause 事件)
  3. 用户拍照
  4. 相机活动结束
    • Cordova 活动被移到前台(触发 resume 事件)
  5. 用户返回到他们离开的应用程序

但是,如果设备内存不足,此事件流程可能会被打乱。如果 Activity 被操作系统杀死,则上述事件序列将如下进行:

  1. 用户正在与你的应用程序交互,需要拍照
  2. 相机插件启动本机相机活动
    • 操作系统销毁 Cordova 活动(触发 pause 事件)
  3. 用户拍照
  4. 相机活动结束
    • 操作系统重新创建 Cordova 活动(触发 deviceready 和 resume 事件)
  5. 用户会感到困惑,为什么他们突然回到应用程序的登录屏幕

在这种情况下,操作系统在后台杀死了应用程序,并且应用程序没有将其状态维护为生命周期的一部分。当用户返回到应用程序时,Webview 被重新创建,应用程序看起来像是从头开始重新启动(因此用户感到困惑)。此事件序列与按下 Home 键或用户切换应用程序时发生的情况相同。防止上述体验的关键是订阅事件并在活动生命周期中正确维护状态。

尊重生命周期

在上面的示例中,触发的 javascript 事件以斜体表示。这些事件是你保存和恢复应用程序状态的机会。你应在应用程序的 bindEvents 函数中注册回调,通过保存状态来响应生命周期事件。你要保存哪些信息以及如何保存这些信息由你自行决定,但你应该确保保存足够的信息,以便在用户返回到你的应用程序时,你可以将用户恢复到他们离开时的确切位置。

在上面的示例中,还有一个附加因素仅适用于第二种讨论的情况(即,当插件启动外部活动时)。当用户完成拍照时,不仅应用程序的状态丢失了,用户拍摄的照片也丢失了。通常,该照片将通过在相机插件中注册的回调传递到你的应用程序。但是,当 Webview 被销毁时,该回调将永远丢失。幸运的是,cordova-android 5.1.0 及更高版本提供了一种在你的应用程序恢复时获取该插件调用结果的方法。

检索插件回调结果 (cordova-android 5.1.0+)

当操作系统销毁被插件推到后台的 Cordova 活动时,任何挂起的回调也会丢失。这意味着如果你将回调传递给启动新活动的插件(例如,相机插件),则在重新创建应用程序时,将不会触发该回调。但是,从 cordova-android 5.1.0 开始,resume 事件的有效负载将包含在活动被销毁之前,启动外部活动的插件请求中的任何挂起插件结果。

resume 事件的有效负载遵循以下格式:

{
    action: "resume",
    pendingResult: {
        pluginServiceName: string,
        pluginStatus: string,
        result: any
    }
}

该有效负载的字段定义如下:

  • pluginServiceName:返回结果的插件的名称(例如,“Camera”)。这可以在插件的 plugin.xml 文件的 <name> 标签中找到
  • pluginStatus:插件调用的状态(请参见下文)
  • result:插件调用的结果

pendingResult 字段中 pluginStatus 的可能值包括以下内容:

  • "OK" - 插件调用成功
  • "No Result" - 插件调用结束,没有结果
  • "Error" - 插件调用导致一些常规错误
  • 其他各种错误
    • "找不到类"
    • "非法访问"
    • "实例化错误"
    • "格式错误的 URL"
    • "I/O 错误"
    • "无效操作"
    • "JSON 错误"

注意: result 字段中包含什么以及返回的 pluginStatus 的含义由插件决定。请参考插件的 API 文档,了解预期结果以及如何使用这些值。

示例

以下是一个简短的示例应用程序,该应用程序使用 resumepause 事件来管理状态。它使用 Apache 相机插件作为如何从 resume 事件有效负载中检索插件调用结果的示例。处理 resumeevent.pendingResult 对象的那部分代码需要 cordova-android 5.1.0+

// This state represents the state of our application and will be saved and
// restored by onResume() and onPause()
var appState = {
    takingPicture: true,
    imageUri: ""
};

var APP_STORAGE_KEY = "exampleAppState";

var app = {
    initialize: function() {
        this.bindEvents();
    },
    bindEvents: function() {
        // Here we register our callbacks for the lifecycle events we care about
        document.addEventListener('deviceready', this.onDeviceReady, false);
        document.addEventListener('pause', this.onPause, false);
        document.addEventListener('resume', this.onResume, false);
    },
    onDeviceReady: function() {
        document.getElementById("take-picture-button").addEventListener("click", function() {
            // Because the camera plugin method launches an external Activity,
            // there is a chance that our application will be killed before the
            // success or failure callbacks are called. See onPause() and
            // onResume() where we save and restore our state to handle this case
            appState.takingPicture = true;

            navigator.camera.getPicture(cameraSuccessCallback, cameraFailureCallback,
                {
                    sourceType: Camera.PictureSourceType.CAMERA,
                    destinationType: Camera.DestinationType.FILE_URI,
                    targetWidth: 250,
                    targetHeight: 250
                }
            );
        });
    },
    onPause: function() {
        // Here, we check to see if we are in the middle of taking a picture. If
        // so, we want to save our state so that we can properly retrieve the
        // plugin result in onResume(). We also save if we have already fetched
        // an image URI
        if(appState.takingPicture || appState.imageUri) {
            window.localStorage.setItem(APP_STORAGE_KEY, JSON.stringify(appState));
        }
    },
    onResume: function(event) {
        // Here we check for stored state and restore it if necessary. In your
        // application, it's up to you to keep track of where any pending plugin
        // results are coming from (i.e. what part of your code made the call)
        // and what arguments you provided to the plugin if relevant
        var storedState = window.localStorage.getItem(APP_STORAGE_KEY);

        if(storedState) {
            appState = JSON.parse(storedState);
        }

        // Check to see if we need to restore an image we took
        if(!appState.takingPicture && appState.imageUri) {
            document.getElementById("get-picture-result").src = appState.imageUri;
        }
        // Now we can check if there is a plugin result in the event object.
        // This requires cordova-android 5.1.0+
        else if(appState.takingPicture && event.pendingResult) {
            // Figure out whether or not the plugin call was successful and call
            // the relevant callback. For the camera plugin, "OK" means a
            // successful result and all other statuses mean error
            if(event.pendingResult.pluginStatus === "OK") {
                // The camera plugin places the same result in the resume object
                // as it passes to the success callback passed to getPicture(),
                // thus we can pass it to the same callback. Other plugins may
                // return something else. Consult the documentation for
                // whatever plugin you are using to learn how to interpret the
                // result field
                cameraSuccessCallback(event.pendingResult.result);
            } else {
                cameraFailureCallback(event.pendingResult.result);
            }
        }
    }
}

// Here are the callbacks we pass to getPicture()
function cameraSuccessCallback(imageUri) {
    appState.takingPicture = false;
    appState.imageUri = imageUri;
    document.getElementById("get-picture-result").src = imageUri;
}

function cameraFailureCallback(error) {
    appState.takingPicture = false;
    console.log(error);
}

app.initialize();

对应的 html

<!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 *">
        <meta name="format-detection" content="telephone=no">
        <meta name="msapplication-tap-highlight" content="no">
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
        <link rel="stylesheet" type="text/css" href="css/index.css">
        <title>Cordova Android Lifecycle Example</title>
    </head>
    <body>
        <div class="app">
            <div>
                <img id="get-picture-result" />
            </div>
            <Button id="take-picture-button">Take Picture</button>
        </div>
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
    </body>
</html>

Android 怪癖

Cordova-Android 平台中的默认 API 级别已升级。在 Android 9 设备上,默认情况下禁用明文通信。

默认情况下,HTTP 和 FTP 等将拒绝应用程序使用明文流量的请求。避免明文流量的关键原因是缺乏机密性、真实性和防止篡改的保护;网络攻击者可以窃听传输的数据,也可以在不被检测到的情况下修改数据。你可以在Android 开发人员的文档中了解有关 android:usesCleartextTraffic 或任何其他 Android 应用程序元素设置的更多信息。

要再次允许明文通信,请在 config.xml 文件中的应用程序标记上将 android:usesCleartextTraffic 设置为 true

<platform name="android">
  <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
      <application android:usesCleartextTraffic="true" />
  </edit-config>
</platform>

并且还需要在同一个 config.xml 文件中的 widget 标记中添加 Android XML 命名空间 xmlns:android="http://schemas.android.com/apk/res/android"

示例

<widget id="io.cordova.hellocordova" version="0.0.1" android-versionCode="13" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="https://cordova.net.cn/ns/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
</widget>

Android 清单信息

你可以在Android 开发人员的文档中了解有关 Android 清单信息的更多信息。

测试活动生命周期

Android 提供了一个开发人员设置,用于测试低内存时的活动销毁。在设备或模拟器上的开发者选项菜单中启用“不保留活动”设置,以模拟低内存场景。你应该始终在启用此设置的情况下进行一些测试,以确保你的应用程序能够正确维护状态。