Help us understand the problem. What is going on with this article?

Cordova Pluginの基本事項

More than 1 year has passed since last update.

イントロダクション

Cordova Pluginを実装する場合の基本事項についてまとめました。

Cordovaプラグインについての記事

必須ファイル

cordova 6.5以前は、plugin.xmlだけが必須でした。
cordova 7.0以後は、plugin.xmlのほか、package.jsonも必須となります。

ミニマムなプラグイン構成

Cordova 7.0以後を想定して、ミニマムなプラグインを構成するplugin.xmlとpackage.jsonを考えています。

ミニマムなplugin.xml

ミニマムなplugin.xmlファイルは次のようになります。ここでは、プラグイン名をhello-world-pluginとしています。

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="hello-world-plugin" version="0.0.1" >

  <name>HelloWorldPlugin</name>
  <description>HelloWorldPlugin</description>
  <author>Ken Naito</author>
  <license>MIT</license>
  <engines>
    <engine name="cordova" version=">=6.5.0" />
  </engines>

</plugin>

 この中で重要なのは、pluginディレクティブと、そのid属性、version属性です。これらは省略することが出来ません。

idは、英数字とハイフンで区切るのが一般的です。これは、nodeのパッケージ名と同じになるようにしているからです。
id名は、必ずしもnodeのパッケージ名と一致させる必要はありませんが、cordova 7.1以前では、nodeのパッケージ名と合っていないと正常に動作しない不具合があります。
 また、多くの公開されているプラグインのプラグインidは、「cordova-plugin-」という形になっているものが多いです。cordovaで公式に公開しているプラグインもすべてこの形式になります。

version名は、semver形式で、メジャーバージョン、マイナーバージョン、パッチバージョンをピリオドでつないだものを指定して下さい。

enginesは省略することも可能ですが、基本的には記述しておいた方が良いです。特に、古いcordovaだとうまく組み込めない可能性があります。現状では、6.5や7.0以上としておけば問題ないでしょう。

name, description, author, lisenceも省略することが可能ですが、一般的に何か記述しておいた方が良いでしょう。

ミニマムなpackage.json

package.jsonファイルは、cordova 7.0以後は必須となりました。最低限、nameとversionが記載されていれば利用可能です。

ミニマムなpackage.jsonファイルは次のようになります。

{
  "name": "hello-world-plugin",
  "version": "1.0.0"
}

先にも述べた様に、package.jsonのnameは、plugin.xmlのwidgetタグのid属性と同じにした方が良いです。
また、versionは、plugin.xmlのversionと同じにして下さい。

ここまでのサンプルコードのプラグインを、プロジェクトに組み込む

プラグイン開発用のディレクトリを作成し(ここでは【plugin_dir】とします)、上記のplugin.xmlとpackage.jsonを配置してください。

【plugin_dir】
 ┣ package.json
 ┗ plugin.xml

 これで、ミニマムなプラグイン hello-world-pluginが出来ました。
以下のようにして、プラグインをプロジェクトに組み込んでみましょう。

$ cordova create sampleDevelopPlugin   // サンプルプロジェクトの作成
$ cd sampleDevelopPlugin
$ cordova platform add android
$ cordova platform add ios
$ cordova plugin add 【plugin_dir】     // プラグインの組み込み

成功しましたでしょうか? 以下のコマンドで、正常に組み込まれたかどうかが分かります。

$ cordova plugin ls

また、次のコマンドでプラグインを解除することが出来ます。

$ cordova plugin rm hello-world-plugin

なお、このプラグインは何も機能を持っていないので、組み込んでも何もすることが出来ません。

ネイティブコードの記述

それでは、いよいよプラグインからネイティブコードを利用する方法へ進みましょう。

プラグインでネイティブコードを利用したい場合、plugin.xmlを編集し、プラットフォームごとに platform ディレクティブで記述していく必要があります。

Androidの場合

platformディレクティブに、name属性をandroidとして設定します。

例えば、最も簡単なプラグインの例として、ハローワールドプラグインでは、次のように記述しています。

  <platform name="android">
    <config-file target="res/xml/config.xml" parent="/*">
      <feature name="HelloWorldPlugin">
        <param name="android-package" value="com.example.plugin.HelloWorldPlugin"/>
      </feature>
    </config-file>
    <source-file src="src/android/HelloWorldPlugin.java" target-dir="src/com/example/plugin" />
  </platform>

source-file ディレクティブで、組み込む必要のあるjavaコードを記述しています。src属性で、プラグイン内の相対アドレスで、ファイルを指定します。target-dir属性で、配置先をプロジェクトのplatforms/androidからの相対パスを指定します。(cordova-android のversion 7.0以後の場合は、platforms/android/app/src/main/javaからの相対パスに配置されます)

config-file ディレクティブで、javascriptの cordova.execメソッドでの呼び出し方を指定しています。config-filetarget 属性と parent 属性は、常にこの値となります。
featureディレクティブで、呼び出し方を1つ指定します。feature タグのname属性は、cordova.execメソッドで呼び出す場合の参照名を定義しています。

 また、paramディレクティブの value属性で、呼び出されるjavaクラスを指定します。この例では、com.example.plugin.HelloWorldPluginクラスが指定されています。このjavaクラスは、CordovaPluginクラスを継承している必要があります。paramディレクティブのnameは、androidの場合は、固定でandroid-pacakgeとします。

 なお、paramディレクティブとして追加で次のように書くことも出来ます。

<param name="onload" value="true" />

この指定をすると、アプリ起動後にplugin (のネイティブコード)が初期化されます。この指定がないと、JavaScriptから最初の呼び出しが行われるまで、pluginの初期化が実行されません。

 なお、この例で実際に呼び出されるのは、com.example.plugin.HelloWorldPluginexecuteメソッドとなります。

 cordova.execによる呼び出し方は

cordova.exec( success, fail, "HelloWorldPlugin", メソッド名, パラメータ);

となります。successは成功コールバック、failは失敗コールバックです。
 第三引数の"HelloWorldPlugin"は、上述の featureタグのname属性で指定した文字列です。
第四引数のメソッド名は、Androidの場合文字列であれば何でも良いですが、iOSとの整合性を考えると、なるべくキャメルケースの文字列にした方が良いでしょう。これが、ネイティブ側のexecuteメソッドの第一引数として渡されます。
 第五引数のパラメータは、かならず配列とします。一つしかパラメータがない場合、長さ1の配列とします。また、配列の要素は文字列でも数値でもJsonでも構いません。

 なお、cordova.execを直接アプリケーションから呼ぶことも出来ますが、通常はそうではなく、プラグイン内のjavascriptからcordova.execを呼び出すようにします。そして、アプリケーションから呼び出すのは、プラグイン内のjavascriptだけにする方が良いです。
 プラグインのjavascriptについては、JavaScript部分の実装を参照。

ネイティブコードの実装

ごく簡単に、「HelloWorldPlugin」という文字列を返すだけのプラグインとした場合、Androidのネイティブ部分の実装は次のようになります。

package com.example.plugin;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;

public class HelloWorldPlugin extends CordovaPlugin {

  @Override
  public boolean execute(String action, JSONArray args,
            CallbackContext callbackContext) throws JSONException {
    if ("message".equals(action)) {
      callbackContext.success("HelloWorld");
      return true;
    }
  }

}

ここでは詳しくは説明しませんが、メソッド名としてmessageを呼び出した時に、"HelloWorld"という文字列を返す処理をしています。
パラメータは何も受け付けていません。

サンプル:プラグインとしての構成

上記をまとめると、プラグインとしては次のようになります。

【plugin_dir】
 ┣ src
 ┃  ┗ android
 ┃     ┗ com/example/plugin/HelloCordovaPlugin.java
 ┣ package.json
 ┗ plugin.xml

サンプル:アプリケーションからの呼び出し方

プラグイン内に、呼び出し用のjavascriptを用意していないので、ここでは
deviceready後に、次のように直接cordova.execを使って呼び出します。

var success = function (x) { alert(x); };
var fail = function () { alert("error!"); };
cordova.exec( success, fail, "HelloWorldPlugin", "message", []);

iOSの場合

androidの場合と同様に、platformディレクティブを使い、name属性としてiosを設定します。

    <platform name="ios">
        <config-file target="config.xml" parent="/*">
            <feature name="HelloWorldPlugin">
                <param name="ios-package" value="CDVHelloWorldPlugin"/>
            </feature>
        </config-file>
        <header-file src="src/ios/CDVHelloWorldPlugin.h" />
        <source-file src="src/ios/CDVHelloWorldPlugin.m" />
    </platform>

config-fileディレクティブもandroidの時と同様です。target属性の指定の仕方がやや異なります。iOSでは、プラットフォームのrootにconfig.xmlファイルがあるためです。

featureタグもandroidの時とほぼ同様です。valueでは、Androidではjavaなのでパッケージ名付きでクラスを指定していましたが、iOSではObjective-Cなので、クラス名のみを記述します。パッケージ名がない分、他のライブラリとファイル名が重ならないように、クラス名にプラグイン固有のプレフィックスをつけることが普通です。ここでは、CDVをつけて、CDVHelloWorldPluginとしました。

header-fileディレクティブと、source-fileディレクティブで、Objective-Cのヘッダファイル、ソースファイルを指定します。Androidの時と異なり、target-dirを指定することは出来ません。

cordova.execでの呼び出し方は、androidと共通です。

cordova.exec( success, fail, "HelloWorldPlugin", メソッド名, パラメータ);

このコードで呼び出されるネイティブコードは、CDVHelloWorldPluginクラスの、【メソッド名】メソッドです。すなわち、cordova.execから直接Objective-Cのメソッドが呼びだされることになります。なお、CDVHelloWorldPluginクラスは、
CDVPluginクラスを継承している必要があります。

 Androidの時と同様ですが、cordova.execを直接アプリケーションから呼ぶことも出来ますが、通常はそうではなく、プラグイン内のjavascriptからcordova.execを呼び出すようにします。そして、アプリケーションから呼び出すのは、プラグイン内のjavascriptだけにする方が良いです。
 プラグインのjavascriptについては、JavaScript部分の実装を参照。

Windowsの場合

Windowsの場合はちょっと特殊です。そもそもWindowsの場合は、javascriptからデバイスの制御が全て行えるため、「ネイティブ」を呼び出す必要がありません。しかし、Android/iOSと呼び出し方を統一しておいた方が、アプリの実装を共通化出来るため好ましいです。そこで、Windowsの場合、デバイスを制御するようなjsコードをProxy形式(cordovaのproxyの仕様に従った形式のjavascript)で記述し、次のようにjs-moduleタグで指定するのが普通です。

    <platform name="windows">
        <js-module src="src/windows/HelloWorldPluginProxy.js" name="HelloWorldPlugin">
            <merges target="" />
        </js-module>
    </platform>

そして、HelloWorldPluginProxy.js内部で

require("cordova/exec/proxy").add("HelloWorldPlugin", module.exports);

のように定義することで、Android/iOSと同様に cordova.execメソッドで呼び出すことが出来るようになります。

plugin.xmlファイル、package.jsonファイルの補足事項

dependency

プラグインが別のプラグインに依存している場合、plugin.xmlに次のように記述することで、自動的に依存先プラグインをインストールすることが出来る様になります。

<dependency id="【依存先プラグインのプラグインID】" version="【バージョン】" />

例えば、phonegap-plugin-pushの2.1.3に依存するのであれば、次の様になります。

<dependency id="phonegap-plugin-push" version="2.1.3" />

plugin.xmlにdependencyが記述してある場合、package.jsonにもdependenciesを記載しておいた方が良いでしょう。

例: cordova-plugin-media の場合 https://github.com/apache/cordova-plugin-media
cordova-plugin-fileに依存しています。

 <dependency id="cordova-plugin-file" version="^6.0.0" />
KNaito
I love JavaScript, Html, PHP, Python, Java, Ruby, Perl, C, C++, Objective-C and Haskell. My stack overflow address is http://stackoverflow.com/users/3535002/knaito
http://d.hatena.ne.jp/knight_9999/
asial
開発中に体験した技術についての情報をつづります
http://www.asial.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away