フック

はじめに

Cordovaフックは、アプリケーションやプラグイン開発者、あるいは独自のビルドシステムによって追加できる特別なスクリプトであり、Cordovaコマンドをカスタマイズするために使用できます。

Cordovaフックを使用すると、Cordovaコマンドの周囲で特別なアクティビティを実行できます。たとえば、JavaScriptファイルのコードフォーマットをチェックするカスタムツールがあるとします。そして、このツールをビルドごとに実行したいとします。そのような場合、「before_build」フックを使用し、Cordovaランタイムに指示して、ビルドごとにカスタムツールを呼び出すことができます。

フックは、`before_build`、`after_build`など、アプリケーションのアクティビティに関連している場合があります。あるいは、アプリケーションのプラグインに関連している場合があります。たとえば、`before_plugin_add`、`after_plugin_add`などのフックは、プラグイン関連のアクティビティに適用されます。これらのフックは、アプリケーション内のすべてのプラグインに関連付けることも、1つのプラグインのみに関連付けることもできます。

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 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 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_install`、`after_plugin_install`、`before_plugin_uninstall`プラグインフックは、インストール/アンインストールされるプラグインに対してのみ実行されます。

フックの実行順序

フックの定義に基づく

特定のフックに対するフックスクリプトは、`config.xml`からのアプリケーションフックが`plugins/.../plugin.xml`からのプラグインフックの前に実行されるというファイル内の出現順に直列に実行されます。

内部実行順序に基づく

フックの内部実行順序は固定されています。

例1 (cordova platform add)

`before_platform_add`、`after_platform_add`、`before_prepare`、`after_prepare`、`before_plugin_install`、`after_plugin_install`に関連付けられたフックがあり(プロジェクトに1つのプラグインがインストールされていると仮定)、新しいプラットフォームを追加すると、フックは次の順序で実行されます。

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

`before_prepare`、`after_prepare`、`before_compile`、`after_compile`、`before_build`、`after_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');

Promiseを使用してスクリプトを非同期にすることができます。これは、1秒間待機してから、待機に費やされたミリ秒数を印刷する例です。

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はスクリプトの最初の行にシバン行を期待します。これにより、スクリプトの起動に使用するインタープリターがわかります。Pythonスクリプトのシバン行は次のようになります。

#!/usr/bin/env python

使用例

この例では、Cordovaフックを使用して、生成された.apkファイルのサイズをAndroidプラットフォームのコンソール出力にトレースする方法を示します。

空のCordovaアプリを作成し、各プラットフォームのビルド後に`afterBuild.js`スクリプトを実行するようにCordovaに指示する次の定義を`config.xml`に追加します。

<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