JavaScript
Android
iOS
Cordova
monaca

Cordova Pluginの基本事項

イントロダクション

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": "helloworldplugin",
  "version": "1.0.0"
}

ここまでのサンプルコード

プラグイン開発用のディレクトリを作成し(ここでは【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でも構いません。

iOSの場合

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

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

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

featureタグもandroidの時とほぼ同様です。valueでは、Androidではjavaなのでパッケージ名付きでクラスを指定していましたが、iOSではObjective-Cなので、クラス名のみを記述します。

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

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

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

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

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メソッドで呼び出すことが出来るようになります。

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

... TODO

dependency

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