[*Cordova*] プラグインを自作する（Android）

# はじめに
プラグインの作り方メモ。

# 手順
## ディレクトリ構成
必要なファイルやディレクトリを作成。

```bash
$ mkdir cordova-plugin-helloworld
$ cd cordova-plugin-helloworld
$ mkdir -p src/android
$ mkdir www
$ touch plugin.xml src/android/HelloWorld.java www/helloworld.js
```

構成としてはこんな感じになる。

```
cordova-plugin-helloworld
  src/
    android/
      HelloWorld.java　 ・・・ネイティブの処理を書いたり
  www/
    helloworld.js　・・・ネイティブと画面側の橋渡し
  plugin.xml　・・・プラグインの設定ファイル
```

## plugin.xmlの編集

```xml:plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- id: プラグインの識別子、version: プラグインのバージョン -->
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
  xmlns:android="http://schemas.android.com/apk/res/android"
  id="cordova-plugin-helloworld"
  version="1.0.0">

  <!-- プラグイン名 -->
  <name>HelloWorld</name>
  <!-- プラグインの説明 -->
  <description>This is a first plugin !!</description>
  <!-- 作者 -->
  <author>cigalecigales</author>
  <!-- キーワード -->
  <keywords>hello, world</keywords>
  <!-- ライセンス -->
  <license>Sample License</license>
  <!-- プラグインがサポートするCordovaのバージョン -->
  <engines>
    <engine name="cordova-android" version=">5.0.0"/>
  </engines>
  <!-- JSの場所指定。name: モジュール名 -->
  <js-module src="www/helloworld.js" name="hello">
    <clobbers target="hello"/>
  </js-module>

  <!-- Android用の設定 -->
  <platform name="android">
    <!-- Androidのconfig.xmlはここ→project/platform/android/res/xml/config.xmlにあるのでそこに反映するように -->
    <config-file target="res/xml/config.xml" parent="/*">
      <!-- Cordovaはfeatureタグをみて、どのプラグインが有効か見る。以下の情報が上記のファイルに追加される。 -->
      <feature name="helloworld">
        <param name="android-package" value="plugin.helloworld.HelloWorld"/>
      </feature>
    </config-file>
    <!-- Javaのソースファイル。 target-dir: ファイルがコンパイルされるべき場所 -->
    <!-- 以下だとproject/platform/android/src/plugin/helloworld/以下になる -->
    <source-file src="src/android/HelloWorld.java" target-dir="src/plugin/helloworld/"/>
  </platform>
</plugin>
```

## HelloWorld.javaの編集

```java:HelloWorld.java
// featureのparamのvalueで指定したやつ
package plugin.helloworld;

import org.apache.cordova.*;
import org.json.JSONArray;
import org.json.JSONException;

public class HelloWorld extends CordovaPlugin {

    @Override
    public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {

        if (action.equals("sayHello")) {
            String name = data.getString(0);
            String message = "Hello, World !!! " + "Hello, " + name;
            callbackContext.success(message);
            return true;
        } else {
            return false;
        }
    }
}
```

## helloworld.jsの編集

```js:helloworld.js
module.exports = {
  sayHello: function(name, successCallback, errorCallback) {
    // 第1引数: 成功時に呼び出す関数
    // 第2引数: エラー時に呼び出す関数
    // 第3引数: プラグインの名前（plugin.xmlのfeatureのnameに設定したもの）
    // 第4引数: HelloWorld.javaの第1引数に渡る名前
    // 第5引数: HelloWorld.javaの第2引数に渡る値
    cordova.exec(successCallback, errorCallback, "helloworld", "sayHello", [name]);
  }
};
```

## Githubにpushする
ローカルに置いておいてそれをプロジェクトに追加することもできるが、なんとなくリポジトリから追加したほうがテンション上がるのでGithubに上げる。

## プラグインをプロジェクトに追加
プロジェクトを作成する。

```bash
$ cordova create [プロジェクト名]
$ cd [プロジェクト名]
$ cordova platform add android
```

プロジェクトに作成したプラグインを追加する。

```bash
$ cordova plugin add https://github.com/cigalecigales/cordova-plugin-helloworld.git
```

## 変更内容を見る
プロジェクトにプラグイン追加後に変わったファイルの一部を見ていく。

### fetch.json
追加したcordova-plugin-helloworldプラグインの情報が増えている。

```json:plugins/fetch.json
{
    "cordova-plugin-whitelist": {
        "source": {
            "type": "registry",
            "id": "cordova-plugin-whitelist@1"
        },
        "is_top_level": true,
        "variables": {}
    },
    "cordova-plugin-helloworld": {
        "source": {
            "type": "git",
            "url": "https://github.com/cigalecigales/cordova-plugin-helloworld.git",
            "subdir": "."
        },
        "is_top_level": true,
        "variables": {}
    }
}
```

ちなみに、以下のようにローカルのを追加した場合はこんな感じになる。

```bash
$ cordova plugin add ../cordova-plugin-helloworld
```

```json:plugins/fetch.json
{
    "cordova-plugin-helloworld": {
        "source": {
            "type": "local",
            "path": "../cordova-plugin-helloworld"
        },
        "is_top_level": true,
        "variables": {}
    }
}
```

### android.json

```json:plugins/android.json
{
    "prepare_queue": {
        "installed": [],
        "uninstalled": []
    },
    "config_munge": {
        "files": {}
    },
    "installed_plugins": {
        "cordova-plugin-whitelist": {
            "PACKAGE_NAME": "io.cordova.hellocordova"
        },
        "cordova-plugin-helloworld": {
            "PACKAGE_NAME": "io.cordova.hellocordova"
        }
    },
    "dependent_plugins": {}
}
```

### plugins/cordova-plugin-helloworld
作ったプラグインが追加されてます。

### config.xml
helloworldプラグインが追加されているのを確認。

```xml:platforms/android/res/xml/config.xml
<?xml version='1.0' encoding='utf-8'?>
<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <preference name="loglevel" value="DEBUG" />
    <feature name="Whitelist">
        <param name="android-package" value="org.apache.cordova.whitelist.WhitelistPlugin" />
        <param name="onload" value="true" />
    </feature>
    <feature name="helloworld">
        <param name="android-package" value="plugin.helloworld.HelloWorld" />
    </feature>
    <allow-intent href="market:*" />
    <name>HelloCordova</name>
    <description>
        A sample Apache Cordova application that responds to the deviceready event.
    </description>
    <author email="dev@cordova.apache.org" href="http://cordova.io">
        Apache Cordova Team
    </author>
    <content src="index.html" />
    <access origin="*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="tel:*" />
    <allow-intent href="sms:*" />
    <allow-intent href="mailto:*" />
    <allow-intent href="geo:*" />
</widget>
```

## index.jsで呼び出し
追加したプラグインがちゃんと動くか確認するため、呼び出す。

```js:index.js
document.addEventListener("deviceready", function() {
  var success = function(message) {
    alert(message);
  }

  var failure = function() {
    alert("Plugin error...");
  }

  // [js-moduleのname].[helloworld.jsで指定した名前]
  hello.sayHello("SAMPLE NAME", success, failure);
});
```

## 実行

```bash
$ cordova run android
```

動いた！
![スクリーンショット 2016-03-25 16.27.32.png](https://qiita-image-store.s3.amazonaws.com/0/48912/45b4b982-0099-9e73-38e9-7184578d45ab.png)

# 参考
* [Android向けのCordovaプラグインを実装する](http://www.buildinsider.net/mobile/bookhtml5hybrid/0406)
* [Plugin Development Guide](https://cordova.apache.org/docs/en/6.x/guide/hybrid/plugins/index.html)