Monacaアプリ、ひいてはCordovaアプリを開発していて避けては通れないのが、「Cordovaプラグイン」の存在です。
スマートフォンの機能(例えば、カメラのエフェクト、アプリ内課金など)を使おうと思った時、Web技術だけでは限界があります。そうした時にWeb技術とネイティブの橋渡しをしてくれるのが、「Cordovaプラグイン」になります。
「Cordovaプラグイン」は、すでに数千種類も作成されているので、大抵の場合はこの中から選べば十分でしょう。しかし、AndroidやiOSのバージョンアップによって動かなくなったり、新しい機能がまだプラグインがない場合もあります。そうした時に備え、自分でプラグインの作り方を学んでおくのは大事です。
この記事では、最も基礎的なプラグイン作成法を紹介します。
このプラグインでは、バッテリーの残量を取得するという処理を行っています。
基本形
まず最初にディレクトリを作成します。
$ mkdir my-cordova-plugin
この中に package.json
と plugin.xml
というファイルを作成します。
さらに、 src
と www
というディレクトを作ります。
そして、 src
の中に android
、ios
というディレクトリを作成します。
構造は、次のようになります。
$ tree
.
├── package.json
├── plugin.xml
├── src
│ ├── android
│ └── ios
└── www
package.json
と plugin.xml
は、Cordovaプラグインに必要な情報です。元々は plugin.xml
だけでしたが、最近は npm(Node.jsのパッケージ管理) でインストールできるようになったので、package.json
が追加されています。
src
は、ソースコードが入るディレクトリです。 androidはAndroid用、iosはiOS用のソースコードが入ります。
package.json について
例えば、package.json
は次のようになります。プラグインに関する説明が殆どです。
{
"version": "0.0.1",
"name": "cordova-plugin-battery",
"description": "Cordova Battery Plugin",
"cordova": {
"id": "cordova-plugin-battery",
"platforms": [
"android",
"ios"
]
},
"keywords": [
"cordova",
"battery",
"cordova-android",
"cordova-ios"
],
"engines": []
}
plugin.xmlについて
plugin.xml
では、各プラットフォーム(Android/iOS)ごとに設定を記述します。対象のファイルであったり、Androidであれば必要な権限を記述します。詳しくは、コメントを参考にしてください。
<?xml version="1.0" encoding="UTF-8"?>
<!-- プラグインのIDを記述。バージョンをpackage.jsonと合わせておく -->
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="io.monaca.plugin.battery"
version="0.0.1">
<!-- プラグイン全体に関する設定 -->
<name>BatteryPlugin</name>
<!-- プラグインの説明 -->
<description>Battery Plugin</description>
<!-- プラグイン作成者 -->
<author>Atsushi Nakatsugawa</author>
<!-- ライセンス -->
<license>MIT License</license>
<!-- 対応Cordovaのバージョン -->
<engines>
<engine name="cordova" version=">=3.5.0" />
</engines>
<!-- アプリ側で呼び出すJavaScriptファイル名 -->
<js-module src="www/battery.js" name="battery">
<clobbers target="Battery" />
</js-module>
<!-- iOS用の設定 -->
<platform name="ios">
<!-- config.xmlに対する設定があればここに記述 -->
<config-file target="config.xml" parent="/*">
<feature name="CVBatteryPlugin">
<param name="ios-package" value="CVBatteryPlugin"/>
</feature>
</config-file>
<!-- 対象のソースコード -->
<source-file src="src/ios/CVBatteryPlugin.swift" target-dir="src/ios" />
</platform>
<!-- Android用の設定 -->
<platform name="android">
<!-- config.xmlに対する設定があればここに記述 -->
<config-file target="res/xml/config.xml" parent="/*">
<feature name="CVBatteryPlugin">
<param name="android-package" value="io.monaca.plugin.CVBatteryPlugin"/>
</feature>
</config-file>
<!-- AndroidManifest.xmlに対する設定があればここに記述 -->
<!-- 主に権限に関する設定を記述します -->
<config-file target="AndroidManifest.xml" parent="/*">
<uses-permission android:name="android.permission.BATTERY_STATS" />
</config-file>
<!-- 対象のソースコード -->
<source-file src="src/android/io/monaca/plugin/CVBatteryPlugin.java" target-dir="src/io/monaca/plugin" />
</platform>
</plugin>
iOS側のコード
iOSでは、 Swift が使えるようになったので、これまでのように .h/.m ファイルで分ける必要がなくなりました。今回の例のように、バッテリー残量を取る場合、次のようなコードになります。
import Foundation
import UIKit
@objc(CVBatteryPlugin) class CVBatteryPlugin: CDVPlugin {
// JavaScriptに公開する関数名を記述
@objc(status:)
func status(command: CDVInvokedUrlCommand) {
// バッテリーの残量を取得
UIDevice.current.isBatteryMonitoringEnabled = true
let bLevel:Float = UIDevice.current.batteryLevel
// 返却するレスポンスを作成
let result = CDVPluginResult(status: CDVCommandStatus_OK,
messageAs: String(bLevel))
// コールバック形式でレスポンスを返却
self.commandDelegate!.send(result, callbackId: command.callbackId)
}
}
Android側のコード
Androidでは、従来通り Java を使います。工夫すると Kotlin が使えるようですが、 Java を使う方が簡単でしょう。
Javaの場合、 src/android/io/monaca/plugin/CVBatteryPlugin.java
といった具合にディレクトリを作成してコードを置くのが基本になるでしょう。
package io.monaca.plugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import android.content.IntentFilter;
import android.content.Intent;
import android.os.BatteryManager;
import android.content.Context;
public class CVBatteryPlugin extends CordovaPlugin {
// Androidは必ずexecuteが呼び出されます
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
// actionにJavaScriptで呼び出したメソッド名が入るので、必要に応じて処理分岐します
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
// バッテリーの残量の取得
Context context = this.cordova.getActivity().getApplicationContext();
Intent batteryStatus = context.registerReceiver(null, ifilter);
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float bLevel = level / (float)scale;
// コールバック形式でレスポンスを返却
callbackContext.success(String.valueOf(bLevel));
return true;
}
}
JavaScriptについて
アプリから呼び出すJavaScriptは、 www/battery.js
として作成します。これは plugin.xml
で指定したパスになります。 cordova.exec
を使うのは基本ですが、その呼び出し方は自由です。例えば、以下はコールバック形式での例です。
const Battery = function() {};
Battery.prototype.status = function(success, fail, args) {
cordova.exec(success, fail, "CVBatteryPlugin","status", args);
};
const battery = new Battery();
module.exports = battery;
アプリから呼び出す際には、次のようになるでしょう。
Battery.status(level => {/* バッテリーの残量*/}, err => { /* エラー */ })
使い方について
Cordovaプラグインができあがったら、Cordovaプラグインの管理からアップロードします。
方法としては、2つあります。
- プラグイン全体をZip圧縮
- アップロードしたファイルのURLを指定
後は、Monaca上でアプリをビルドすれば使えるようになります。
テストについて
開発時のテストは、ローカルコンピュータにCordovaコマンドをインストールし、ローカルで実行しながら行うのがいいでしょう。その場合、XcodeやAndroid Studioのブレークポイントが利用できます。
まとめ
自分でCordovaプラグインを作るか否かに関わらず、仕組みを知っておけば、動作を掘り下げて調べる時にも役立ちます。ネイティブの言語を知る必要はありますが、小さなプラグインであれば、コードリーディングもそれほど大変ではないはずです。
プラグインを使うことで、皆さんのアプリがより魅力的になるでしょう。ぜひプラグイン開発にもトライしてみてください。