钩子

简介

Cordova 钩子代表特殊的脚本,可以由应用程序和插件开发人员甚至您自己的构建系统添加,以自定义 Cordova 命令。

Cordova 钩子允许您在 Cordova 命令周围执行特殊活动。例如,您可能有一个自定义工具来检查 JavaScript 文件中的代码格式。并且,您希望在每次构建之前运行此工具。在这种情况下,您可以使用“before_build”钩子,并指示 Cordova 运行时在每次构建之前调用自定义工具。

钩子可能与您的应用程序活动相关,例如 before_buildafter_build 等。或者,它们可能与您的应用程序的插件相关。例如,before_plugin_addafter_plugin_add 等钩子适用于与插件相关的活动。这些钩子可以与应用程序中的所有插件关联,也可以仅与一个插件关联。

Cordova 支持以下钩子类型

钩子类型 关联的 Cordova 命令 描述
before_platform_add cordova platform add 在添加平台之前和之后执行。
after_platform_add
before_platform_rm cordova platform rm 在删除平台之前和之后执行。
after_platform_rm
before_platform_ls cordova platform ls 在列出已安装和可用的平台之前和之后执行。
after_platform_ls
before_prepare cordova prepare
cordova platform add
cordova build
cordova run
在准备应用程序之前和之后执行。
after_prepare
before_compile cordova compile
cordova build
在编译应用程序之前和之后执行。
after_compile
before_deploy cordova emulate
cordova run
在部署应用程序之前执行。
before_build cordova build 在构建应用程序之前和之后执行。
after_build
before_emulate cordova emulate 在模拟应用程序之前和之后执行。
after_emulate
before_run cordova run 在运行应用程序之前和之后执行。
after_run
before_serve cordova serve 在提供应用程序之前和之后执行。
after_serve
before_clean cordova clean 在清理应用程序之前和之后执行。
after_clean
before_plugin_add cordova plugin add 在添加插件之前和之后执行。
after_plugin_add
before_plugin_rm cordova plugin rm 在删除插件之前和之后执行。
after_plugin_rm
before_plugin_ls cordova plugin ls 在列出应用程序中的插件之前和之后执行。
after_plugin_ls
before_plugin_install cordova plugin add 在安装插件(到平台)之前和之后执行。plugin.xml 中的插件钩子仅在安装插件时执行
after_plugin_install
before_plugin_uninstall cordova plugin rm 在卸载插件(从平台)之前执行。plugin.xml 中的插件钩子仅在安装插件时执行

定义钩子的方法

Config.xml

钩子可以在项目的 config.xml 中使用 <hook> 元素定义,例如

<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" />

<platform name="android">
    <hook type="before_build" src="scripts/android/appAndroidBeforeBuild.bat" />
    <hook type="before_build" src="scripts/android/appAndroidBeforeBuild.js" />
    <hook type="before_plugin_install" src="scripts/android/appAndroidBeforePluginInstall.js" />
    ...
</platform>

插件钩子 (plugin.xml)

作为插件开发人员,您可以使用 plugin.xml 中的 <hook> 元素定义钩子脚本,如下所示

<hook type="before_plugin_install" src="scripts/beforeInstall.js" />
<hook type="after_build" src="scripts/afterBuild.js" />

<platform name="android">
    <hook type="before_plugin_install" src="scripts/androidBeforeInstall.js" />
    <hook type="before_build" src="scripts/androidBeforeBuild.js" />
    ...
</platform>

before_plugin_installafter_plugin_installbefore_plugin_uninstall 插件钩子将专门针对正在安装/卸载的插件触发。

钩子执行顺序

基于钩子定义

一个给定钩子的钩子脚本按它们在文件中的出现顺序串行运行,其中来自 config.xml 的应用程序钩子在来自 plugins/.../plugin.xml 的插件钩子之前运行。

基于内部执行顺序

钩子的内部执行顺序是固定的。

示例 1 (cordova platform add)

如果存在与 before_platform_addafter_platform_addbefore_prepareafter_preparebefore_plugin_installafter_plugin_install 关联的钩子(并假设您在项目中安装了一个插件),添加新平台将按以下顺序执行钩子

before_platform_add
    before_prepare
    after_prepare
    before_plugin_install
    after_plugin_install
after_platform_add
示例 2 (cordova build)

如果存在与 before_prepareafter_preparebefore_compileafter_compilebefore_buildafter_build 关联的钩子 - 运行构建命令将按以下顺序执行钩子

before_build
    before_prepare
    after_prepare
    before_compile
    after_compile
after_build

脚本接口

Javascript

如果您使用 Node.js 编写钩子,则应使用以下模块定义

module.exports = function(context) {
    ...
}

以下示例展示了 context 对象的内容

{
  // The type of hook being run
  hook: 'before_plugin_install',

  // Absolute path to the hook script that is currently executing
  scriptLocation: '/foo/scripts/appBeforePluginInstall.js',

  // The CLI command that lead to this hook being executed
  cmdLine: 'cordova plugin add plugin-withhooks',

  // The options associated with the current operation.
  // WARNING: The contents of this object vary among the different
  // operations and are currently not documented anywhere.
  opts: {
    projectRoot: '/foo',

    cordova: {
      platforms: ['android'],
      plugins: ['plugin-withhooks'],
      version: '0.21.7-dev'
    },

    // Information about the plugin currently operated on.
    // This object will only be passed to plugin hooks scripts.
    plugin: {
      id: 'plugin-withhooks',
      pluginInfo: { /* ... */ },
      platform: 'android',
      dir: '/foo/plugins/plugin-withhooks'
    }
  },

  // A reference to Cordova's API
  cordova: { /* ... */ }
}

您还可以使用 context.requireCordovaModule 以以下方式在脚本中要求其他 Cordova 模块

const cordovaCommon = context.requireCordovaModule('cordova-common');

您可以使用 Promises 使脚本异步。以下示例只等待一秒钟,然后打印等待的毫秒数

module.exports = context => {
    return new Promise(resolve => {
        const start = Date.now();
        setTimeout(() => resolve(Date.now() - start), 1000);
    }).then(msWaited => {
        console.log(`${context.scriptLocation} waited ${msWaited} ms`);
    });
};

非 JavaScript

非 JavaScript 脚本通过项目根目录的 Node child_process spawn 运行,并将根目录作为第一个参数传递。所有其他选项都使用环境变量传递给脚本

环境变量名称 描述
CORDOVA_VERSION Cordova-CLI 的版本。
CORDOVA_PLATFORMS 命令适用的平台的逗号分隔列表(例如:android、ios)。
CORDOVA_PLUGINS 命令适用的插件 ID 的逗号分隔列表(例如:cordova-plugin-file-transfer、cordova-plugin-file)。
CORDOVA_HOOK 正在执行的钩子的路径。
CORDOVA_CMDLINE 传递给 cordova 的确切命令行参数(例如:cordova run ios --emulate)。

如果脚本返回非零退出代码,则父 cordova 命令将被中止。

注意:我们强烈建议使用 Node.js 编写钩子,以便它们是跨平台的,请参阅上面的 Javascript 部分。

Windows 特性

如果您在 Windows 上工作,并且您的钩子脚本不是 *.bat 文件,则 Cordova CLI 将期望脚本的第一行为 shebang 行。这样它就知道需要使用哪个解释器来启动脚本。Python 脚本的 shebang 行可能如下所示

#!/usr/bin/env python

示例用法

此示例演示了 Cordova 钩子的用法,以跟踪生成的 .apk 文件的大小以供 Android 平台使用。

创建空白 Cordova 应用程序,并将以下定义添加到 config.xml 中,以告诉 Cordova 在每次平台构建后运行 afterBuild.js 脚本。

<hook type="after_build" src="scripts/afterBuild.js" />

创建 scripts/afterBuild.js 文件并添加以下实现。我们使用 fs.stat 方法的异步版本来演示如何在钩子中使用异步函数。

const fs = require('fs');
const util = require('util');
const stat = util.promisify(fs.stat);

module.exports = function(ctx) {
    // Make sure android platform is part of build
    if (!ctx.opts.platforms.includes('android')) return;

    const platformRoot = path.join(ctx.opts.projectRoot, 'platforms/android');
    const apkFileLocation = path.join(platformRoot, 'build/outputs/apk/android-debug.apk');

    return stat(apkFileLocation).then(stats => {
      console.log(`Size of ${apkFileLocation} is ${stats.size} bytes`);
    });
};

上面的示例中的参数 ctx 由 Cordova 传递,代表执行上下文,例如脚本完整路径、目标平台、命令行参数等,并公开额外的辅助功能。有关更多详细信息,请参阅上面的 脚本接口 部分。

您现在可以添加 Android 平台并执行构建。

cordova platform add android
..
cordova build
..
Size of path\to\app\platforms\android\build\outputs\apk\android-debug.apk is 1821193 bytes