Android 使用 Rhino JS 解析引擎執(zhí)行JS代碼

Rhino 簡介

官方示例

Android】不使用WebView來執(zhí)行Javascript腳本(Rhino)

Rhino 是一個由 Java 實現(xiàn)的 JS 解析引擎倦春,可以很容易的接入到 Java 項目中姚糊,對于現(xiàn)在的大前端的趨向中,可以利用 Rhino 來實現(xiàn)相關(guān)的跨平臺渲染功能港谊。

個人理解相比于現(xiàn)在更主流的 chrome v8 引擎,Rhino 的優(yōu)勢在于在 Java 項目容易使用,同時不需要去踩交叉編譯的坑。但是缺點也在于只適用于 Java 項目键俱,v8 在功能等方面應該是更勝一籌兰绣。

但是如果說只是自己或者小范圍使用的話世分,rhino 可以做為一個很好的選擇。

關(guān)于 JS 引擎的選擇可以參考

在 Android 中使用 Rhino

首先要去下載一個 rhino 的包
下載鏈接

我下的是 1.7.9 版本的缀辩,將 rhino 的包放到如下位置臭埋。


image.png

同時在gradle文件中引用這個包。

    implementation files('libs/rhino-1.7.9.jar')

JS 代碼運行時回調(diào)給 Java

接下來就可以開始使用 rhino 了臀玄,現(xiàn)寫一個 JS 代碼瓢阴,做為測試可以將代碼做為字符串傳入,我這里貼出來方便查看健无。

//通過反射獲取對應 Java類中名為 rhino_test(String) 的方法
var method_Api_rhino_test = ScriptAPI.getMethod("rhino_test",[java.lang.String])
function rhino_test() {
    var str = "jzy666";
    //執(zhí)行反射獲取的方法荣恐,并傳入字符串參數(shù)
    method_Api_rhino_test .invoke(javaContext,str);
}
rhino_test();

創(chuàng)建一個 JsEngine 類

public class JsEngine{
    private Class clazz;
    private org.mozilla.javascript.Context rhino;
    private Scriptable scope;

    private String jsCode = "";
    private String testCode =
            "var method_Api_rhino_test = ScriptAPI.getMethod(\"rhino_test\",[java.lang.String])\n" +
            "function rhino_test() {\n" +
            "    var str = \"jzy666\";\n" +
            "    method_Api_rhino_test.invoke(javaContext,str);\n" +
            "}" +
            "rhino_test()";
    public JsEngine(){
        this.clazz = JsEngine.class;
        initJsEngine();
    }

    private void initJsEngine(){
        jsCode = "var ScriptAPI = java.lang.Class.forName(\"" + JsEngine.class.getName() + "\", true, javaLoader);\n"
                + testCode;
    }

    public void request(){
        rhino = org.mozilla.javascript.Context.enter();
        rhino.setOptimizationLevel(-1);
        try{
            scope = rhino.initStandardObjects();
            // 這兩句是設置當前的類做為上下文以及獲取當前的類加載器,以便于 rhino 通過反射獲取檔期類
            ScriptableObject.putProperty(scope,"javaContext", org.mozilla.javascript.Context.javaToJS(this,scope));
            ScriptableObject.putProperty(scope,"javaLoader", org.mozilla.javascript.Context.javaToJS(clazz.getClassLoader(),scope));
            //執(zhí)行 js 代碼
            Object x = rhino.evaluateString(scope, jsCode, clazz.getSimpleName(), 1, null);
        }finally {
            //退出
            org.mozilla.javascript.Context.exit();
        }
    }
    // 對應類中需要需要被調(diào)用的方法,可以做為 JS 代碼執(zhí)行時的回調(diào)
    public void rhino_test(String str){
        Log.i("jzy111","rhino_test: " + str);
    }
}

我們先執(zhí)行一下叠穆,直接在 Activity 中使用少漆。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        JsEngine jsEngine = new JsEngine();
        jsEngine.request();
    }
}  

運行程序后,可以在 logcat 中看到這樣一條打印

2019-02-19 01:21:44.164 15751-15751/com.example.jzycc.rhino I/jzy111: rhino_test: jzy666

正是我們在上面 JsEngine 類中 rhino_test() 方法中寫的打印語句打印的內(nèi)容硼被, 具體的內(nèi)容就是 JS 代碼執(zhí)行時示损,通過反射調(diào)用 JsEngine 類中的 rhino_test() 并且傳入需要的參數(shù)。

Java 調(diào)用 JS 代碼

如果我們需要在 Java 中調(diào)用 JS 代碼嚷硫,則添加如下方法

    public void callFunction(String functionName,Object[] functionParams){
        Function function = (Function) scope.get(functionName,scope);
        function.call(rhino,scope,scope,functionParams);
    }

在使用這個方法前检访,我們先修改一下 JS 代碼

//通過反射獲取對應 Java類中名為 rhino_test(String) 的方法
var method_Api_rhino_test = ScriptAPI.getMethod("rhino_test",[java.lang.String])
// 這里設置了傳入?yún)?shù)
function rhino_test(str) {
   //var str = "jzy666";
   //執(zhí)行反射獲取的方法,并傳入字符串參數(shù)
   method_Api_rhino_test .invoke(javaContext,str);
}
//我們將執(zhí)行方法的語句去掉
//rhino_test();

修改 request() 方法

    public void request(){
        rhino = org.mozilla.javascript.Context.enter();
        rhino.setOptimizationLevel(-1);
        try{
            scope = rhino.initStandardObjects();
            // 這兩句是設置當前的類做為上下文以及獲取當前的類加載器仔掸,以便于 rhino 通過反射獲取檔期類
            ScriptableObject.putProperty(scope,"javaContext", org.mozilla.javascript.Context.javaToJS(this,scope));
            ScriptableObject.putProperty(scope,"javaLoader", org.mozilla.javascript.Context.javaToJS(clazz.getClassLoader(),scope));
            //執(zhí)行 js 代碼
            Object x = rhino.evaluateString(scope, jsCode, clazz.getSimpleName(), 1, null);
            //js 代碼執(zhí)行后脆贵,我們來調(diào)用需要調(diào)用的方法
            callFunction("rhino_test",new Object[]{"我調(diào)用了方法"});
        }finally {
            //退出
            org.mozilla.javascript.Context.exit();
        }
    }

這里我們在 JS 代碼執(zhí)行后調(diào)用之前添加的 callFunction() 方法,再重新運行程序可以看到如下輸出

2019-02-19 01:43:10.210 16761-16761/com.example.jzycc.rhino I/jzy111: rhino_test: 我調(diào)用了方法

JS 獲取 Java 傳入的值

如果說 JS 需要 我們本地計算好的值起暮,可以這樣使用丹禀。

還是先修改下 JS 代碼。

  //  這里添加一個 getJavaValue() 方法鞋怀, 同樣需要在對應的 Java 類中添加一個方法
var method_Api_getJavaValue = ScriptAPI.getMethod("getJavaValue")
function getJavaValue(){
     return method_Api_getJavaValue.invoke(javaContext);
}

//通過反射獲取對應 Java類中名為 rhino_test(String) 的方法
var method_Api_rhino_test = ScriptAPI.getMethod("rhino_test",[java.lang.String])
// 這里設置了傳入?yún)?shù)
function rhino_test(str) {
    //var str = "jzy666";
    //執(zhí)行反射獲取的方法双泪,并傳入 getJavaValue() 的值
    method_Api_rhino_test .invoke(javaContext,getJavaValue());
}
//我們將執(zhí)行方法的語句去掉
//rhino_test();

修改 JsEngine 代碼,在其中加入如下方法密似。

    public String getJavaValue(){
        return "這里是 Java ~~~~";
    }

重新運行程序焙矛,打印如下

2019-02-19 01:51:12.279 17111-17111/com.example.jzycc.rhino I/jzy111: rhino_test: 這里是 Java ~~~~

最后

Rhino Js 引擎在 Android 中的基本用法就是這么簡單,具體如何使用應該還是要根據(jù)使用場景來設計残腌,我這里只是將最基本的 JS 與 JAVA 本地交互的方法做個展示村斟。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市抛猫,隨后出現(xiàn)的幾起案子蟆盹,更是在濱河造成了極大的恐慌,老刑警劉巖闺金,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逾滥,死亡現(xiàn)場離奇詭異,居然都是意外死亡败匹,警方通過查閱死者的電腦和手機寨昙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掀亩,“玉大人舔哪,你說我怎么就攤上這事〔酃鳎” “怎么了捉蚤?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵抬驴,是天一觀的道長。 經(jīng)常有香客問我缆巧,道長怎爵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任盅蝗,我火速辦了婚禮鳖链,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘墩莫。我一直安慰自己芙委,他們只是感情好,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布狂秦。 她就那樣靜靜地躺著灌侣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裂问。 梳的紋絲不亂的頭發(fā)上侧啼,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音堪簿,去河邊找鬼痊乾。 笑死,一個胖子當著我的面吹牛椭更,可吹牛的內(nèi)容都是我干的哪审。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼虑瀑,長吁一口氣:“原來是場噩夢啊……” “哼湿滓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起舌狗,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤叽奥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后痛侍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朝氓,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年恋日,在試婚紗的時候發(fā)現(xiàn)自己被綠了膀篮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嘹狞。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡岂膳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出磅网,到底是詐尸還是另有隱情谈截,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站簸喂,受9級特大地震影響毙死,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喻鳄,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一扼倘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧除呵,春花似錦再菊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泛豪,卻和暖如春稠诲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诡曙。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工臀叙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人价卤。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓匹耕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親荠雕。 傳聞我的和親對象是個殘疾皇子稳其,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容