JavaアプリでJavaScriptを使う

Java
1. JavaアプリでJavaScriptを使う

 AndroidなどJavaを使っているソフトウェアでJavascriptを利用したいことがありませんか?
設定ファイルとして手軽に処理を変えたいとき、簡単に計算方法を変えたいときなど、Javaはコンパイルする必要がありますが、Javascriptならスクリプトファイルを任意のタイミングで読み込み計算結果を取り込むことができます。

2. 必要なパッケージ

 MozillaプロジェクトのRhino(リーノ)を使います。現在はGitHubがメインのようですが、自分でコンパイルする必要があります。下記のページはメンテナンスがされていませんが、コンパイル済みのバイナリを配布していますので、こちらからダウンロードしてください。

 https://developer.mozilla.org/ja/docs/Rhino/Download_Rhino

バージョンは1.7.12 MPL2.0ライセンスの下で使用可能です。

Githubでは1.7.13を配布しています。今後はこちらが主流のようです。

 https://github.com/mozilla/rhino

3. JavaScriptを使った結果を得る

Javascript内の関数を呼び出し戻り値を得るサンプルです。

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException; 

public class JavaScriptTest {
    private String script;
    //コンストラクタで読み込みスクリプトファイルを指定する。
    public JavaScriptTest(String script_file_path){
            try {
                //Javascriptファイルパスを設定
                String path = script_file_path;
                BufferedReader br = new BufferedReader(new FileReader(path));
                StringBuffer stb = new StringBuffer();
                String str;
                //nullが出るまでファイルを読み込み
                while((str = br.readLine()) != null){
                    stb.append(str+ "\r\n");
                }
           //scriptのテキストデータを保存
                script = stb.toString();
                br.close();
            }catch(IOException ex){
                ex.printStackTrace();
           }
    }
    private int execute_script(String[] script_args){
        Context cx = Context.enter();
        int ret = 0;
        //interpreterモードで使用する場合は-1を設定
        cx.setOptimizationLevel(-1);
        try {
            Scriptable scope = cx.initStandardObjects();
            //evaluateString(Scriptableオブジェクト, スクリプト文字列, "ファイル名のような識別名",開始行, セキュリティドメイン基本はnullでOK)
            cx.evaluateString(scope, script, "<cmd>", 1, null);
            //scope.get(スクリプト中の関数名, Scriptableオブジェクト)を指定
            //関数はオブジェクトととして返ってくる
            Object fObj = scope.get("functionName", scope);
            if (!(fObj instanceof Function)) {
                Log.d("functionName"," is undefined or not a function.");
            }
            //JavascriptのFunctionとしてキャスト
            Function f = (Function) fObj;

            //Javascriptに渡す引数はObjectの配列として渡す。
            Object[] functionArgs = script_args;
            //関数の呼び出し。一つ目のscopeはgetParentScope()によって返される値。
            //2番目のscopeはJavascriptのthisオブジェクトに相当する部分。
            //上位のスコープはないので同じ変数を設定している。
            //関数の戻り値はobjectとして返されるので適宜キャストする。 
            Object result = f.call(cx, scope, scope, functionArgs);
           
            ret =(int) Double.parseDouble(Context.toString(result));
        } catch(Exception ex){
            ex.printStackTrace();
        } finally {
            cx.exit();
            return ret;
        }
    }
}

コメント

タイトルとURLをコピーしました