Rhino 简介
Android】不使用WebView来执行Javascript脚本(Rhino)
Rhino 是一个由 Java 实现的 JS 解析引擎,可以很容易的接入到 Java 项目中,对于现在的大前端的趋向中,可以利用 Rhino 来实现相关的跨平台渲染功能。
个人理解相比于现在更主流的 chrome v8 引擎,Rhino 的优势在于在 Java 项目容易使用,同时不需要去踩交叉编译的坑。但是缺点也在于只适用于 Java 项目,v8 在功能等方面应该是更胜一筹。
但是如果说只是自己或者小范围使用的话,rhino 可以做为一个很好的选择。
在 Android 中使用 Rhino
首先要去下载一个 rhino 的包
下载链接
我下的是 1.7.9 版本的,将 rhino 的包放到如下位置。
同时在gradle文件中引用这个包。
implementation files('libs/rhino-1.7.9.jar')
JS 代码运行时回调给 Java
接下来就可以开始使用 rhino 了,现写一个 JS 代码,做为测试可以将代码做为字符串传入,我这里贴出来方便查看。
//通过反射获取对应 Java类中名为 rhino_test(String) 的方法
var method_Api_rhino_test = ScriptAPI.getMethod("rhino_test",[java.lang.String])
function rhino_test() {
var str = "jzy666";
//执行反射获取的方法,并传入字符串参数
method_Api_rhino_test .invoke(javaContext,str);
}
rhino_test();
创建一个 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));
//执行 js 代码
Object x = rhino.evaluateString(scope, jsCode, clazz.getSimpleName(), 1, null);
}finally {
//退出
org.mozilla.javascript.Context.exit();
}
}
// 对应类中需要需要被调用的方法,可以做为 JS 代码执行时的回调
public void rhino_test(String str){
Log.i("jzy111","rhino_test: " + str);
}
}
我们先执行一下,直接在 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() 方法中写的打印语句打印的内容, 具体的内容就是 JS 代码执行时,通过反射调用 JsEngine 类中的 rhino_test() 并且传入需要的参数。
Java 调用 JS 代码
如果我们需要在 Java 中调用 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])
// 这里设置了传入参数
function rhino_test(str) {
//var str = "jzy666";
//执行反射获取的方法,并传入字符串参数
method_Api_rhino_test .invoke(javaContext,str);
}
//我们将执行方法的语句去掉
//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));
//执行 js 代码
Object x = rhino.evaluateString(scope, jsCode, clazz.getSimpleName(), 1, null);
//js 代码执行后,我们来调用需要调用的方法
callFunction("rhino_test",new Object[]{"我调用了方法"});
}finally {
//退出
org.mozilla.javascript.Context.exit();
}
}
这里我们在 JS 代码执行后调用之前添加的 callFunction() 方法,再重新运行程序可以看到如下输出
2019-02-19 01:43:10.210 16761-16761/com.example.jzycc.rhino I/jzy111: rhino_test: 我调用了方法
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])
// 这里设置了传入参数
function rhino_test(str) {
//var str = "jzy666";
//执行反射获取的方法,并传入 getJavaValue() 的值
method_Api_rhino_test .invoke(javaContext,getJavaValue());
}
//我们将执行方法的语句去掉
//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 中的基本用法就是这么简单,具体如何使用应该还是要根据使用场景来设计,我这里只是将最基本的 JS 与 JAVA 本地交互的方法做个展示。