[Monaca] Cordovaプラグインを作ってみる

Monacaでは、Cordovaプラグインを組み込むことができます。
今回は、Monacaに組み込むことができるCordovaプラグインを作ってみたいと思います。

Monacaで提供しているCameraプラグインで撮影した写真は、撮影後、端末にインストールされているギャラリーアプリには反映されません。

今回は、ギャラリーアプリに画像を反映させるCordovaプラグインを作ってみたいと思います。
今回作成するCordovaプラグインは、Android版です。

自作のCordovaプラグインをMonacaに組み込む場合は、Goldプラン以上が必要になります。

Cordovaプラグインの開発環境は、いろいろとあると思いますが、
今回は、

- Plugman
- Cordova
- Android Studio

を利用して作っていきたいと思います。
開発環境は、Macを想定しています。
Windowsの場合は、適宜読み替えてください。

#Cordovaプラグインの雛形を作成する

###Plugmanをインストールします。

```sudo npm install -g plugman```

###ターミナルで下記のコマンドを実行します。

```
plugman create --name MediaScanner --plugin_id cordova-plugin-mediascanner --plugin_version 0.0.1
```

このコマンドを実行すると、Monacaに組み込むCordovaプラグインの雛形が作成されます。
作成された雛形で使用するファイルは、こんな感じに作成されています。

```xml:plugin.xml
<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova-plugin-mediascanner" version="0.0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
    <name>MediaScanner</name>
    <js-module name="MediaScanner" src="www/MediaScanner.js">
        <clobbers target="cordova.plugins.MediaScanner" />
    </js-module>
</plugin>
```

```js:MediaScanner.js
var exec = require('cordova/exec');

exports.coolMethod = function(arg0, success, error) {
    exec(success, error, "MediaScanner", "coolMethod", [arg0]);
};
```

###MediaScanner/plugin.xml にプラグインの定義を記述します。

```xml:plugin.xml
<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova-plugin-mediascanner" version="0.0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
    <name>MediaScanner</name>
    <js-module name="MediaScanner" src="www/MediaScanner.js">
        <clobbers target="mediaScanner" />
    </js-module>

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

`<clobbers target="mediaScanner" />`で設定した値が、JavaScriptからアクセスできる名前になります。
`param name="android-package"`は、Android Studioで作成するMediaScannerクラス名までのパスになります。

###MediaScanner/www/MediaScanner.js にMonacaプロジェクトから呼び出すメソッドを定義します。

```js:MediaScanner.js
var exec = require('cordova/exec');

function MediaScanner() {
}

MediaScanner.prototype.scanFile = function(filePath, successCallback, errorCallback) {
    exec(successCallback, errorCallback, "MediaScanner", "scanFile", [filePath]);
};

module.exports = new MediaScanner();
```

`scanFile`が、Monacaプロジェクトで使用できるメソッド名になります。


#Android Studioで開発するためのプロジェクトを作成する
Android Studioは、事前にインストールしてください。

###Cordovaをインストールします。

```sudo npm install -g cordova```

###Cordovaプロジェクトを作成します。

```cordova create MediaScanner com.example.media.scanner MediaScanner```

###ディレクトリを移動します。

```cd MediaScanner```

###Androidプラットフォームの追加します。

```cordova platform add android```

###ビルドします。

```cordova build android```

MediaScanner/platforms/androidをAndroid Studioで開きます。

「The project is using an old version of Android Gargle plugin」
が、表示された場合は「Update」をクリックしてGargle pluginをアップデートしてください。

MediaScanner/src/com.example.media.scannerにMediaScannerクラスを作成し、下記を入力します。

```java:MediaScanner
package com.example.media.scanner;

public class MediaScanner extends CordovaPlugin implements MediaScannerConnection.MediaScannerConnectionClient {

    private MediaScannerConnection mMediaScannerConnection;
    private String mFilePath;

    public MediaScanner() {
    }

    @Override
    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
        if ("scanFile".equals(action)) {
            mFilePath = args.getString(0).replace("file://", "");
            return scanFile(callbackContext);
        }
    }

    private boolean scanFile(CallbackContext callbackContext) {
        mMediaScannerConnection = new MediaScannerConnection(cordova.getActivity().getApplicationContext(), this);
        mMediaScannerConnection.connect();
        String successMsg = "scanFile Success";
        callbackContext.success(successMsg);
        return true;
    }

    @Override
    public void onMediaScannerConnected() {
        String mimeType = getMimeTypeForExtension(mFilePath);
        mMediaScannerConnection.scanFile(mFilePath, mimeType);
    }

    @Override
    public void onScanCompleted(String s, Uri uri) {
        mMediaScannerConnection.disconnect();
    }

    /**
     * MimeTypeを取得します。
     *
     * @param path File Path
     * @return String
     */
    public static String getMimeTypeForExtension(String path) {
        String extension = path;
        int lastDot = extension.lastIndexOf('.');
        if (lastDot != -1) {
            extension = extension.substring(lastDot + 1);
        }
        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }
}
```

MainActivityに下記を入力することで、簡単な動作確認をすることができます。

```java:MainActivity
public class MainActivity extends CordovaActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        jsonArray = new JSONArray();
        jsonArray.put("ファイルパス");

        MediaScanner mediaScanner = new MediaScanner();
        try {
            mediaScanner.execute("scanFile", jsonArray, null);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}
```

これで必要なファイルは整いました。

Android Studioで作成したMediaScannerクラス（MediaScanner.java）をCordovaプラグインの雛形で作成した`MediaScanner/src/android/com/example/media/scanner`にコピーします。

MediaScanner.javaのコピーが終わったら、雛形で作成したMediaScannerフォルダーをzipで圧縮します。

これで、Cordovaプラグイン「MediaScanner」の完成です。
MediaScannerプラグインをMonacaのプロジェクトに組み込むことで使用することができます。

ギャラリーアプリに画像を反映させる場合、キャッシュフォルダーにあるファイルは、ギャラリーに反映させることができません。Cameraアプリで撮影したファイルはキャッシュフォルダーに保存されるので、ファイルを移動させる必要があります。

Fileプラグインのファイルの移動については、[[Monaca] Fileプラグインについて](http://qiita.com/keeey/items/cf7222b8d9dddebb3443)を参照してください。

Fileプラグインを使用して、ファイルを`cordova.file.externalRootDirectory`等に移動後、今回作成したMediaScannerプラグインを実行してみてください。ギャラリーアプリに画像が反映されているはずです。

```js:sample
var movePath = cordova.file.externalRootDirectory;

//destinationType : Camera.DestinationType.FILE_URI
navigator.camera.getPicture(onSuccess, onFail, options);
function onSuccess(imageData) {
    window.resolveLocalFileSystemURL(imageData, onResolveSuccess, onResolveFail);
}
function onFail(message) {
    alert('Error : ' + message);
}

function onResolveSuccess(fileEntry) {
    fileEntry.moveTo(movePathEntry, fileEntry.name, moveToSuccess, moveToFail);
    function moveToSuccess(fileEntry) {
        var filePath = fileEntry.toURL();
        mediaScanner.scanFile(filePath, successHandler, errorHandler);
        
    }
    function moveToFail(error) {
        console.log("moveToFail: " + error.code);
    }
}

function successHandler (result) {
    alert("SUCCESS: " + result);
}
function errorHandler (error) {
    alert("ERROR: " + error );
}
```

みなさんもCordovaプラグインの作成にチャレンジしてみてください。