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 可以做為一個很好的選擇。
在 Android 中使用 Rhino
首先要去下載一個 rhino 的包
下載鏈接
我下的是 1.7.9 版本的缀辩,將 rhino 的包放到如下位置臭埋。
同時在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 本地交互的方法做個展示村斟。