我的博客原文地址
本文译自Getting Started With J2V8,并加入了自己的一些理解。
概述
J2V8 是对 Google 的目前非常流行的 JavaScript 引擎 V8 的 Java 封装,J2V8 的开发使 Android 高效执行 JavaScript 带来了可能。 就是基于 J2V8 开发的一款移动端 App。J2V8 可以运行在 Windows,Linux 以及 Mac OS 上面。这篇入门教程主要来介绍如何使用J2V8来在Android上面运行JavaScript脚本。
Github源码地址
J2V8 非常注重性能和内存的消耗,为了达到这些目的在设计的时候做了很大的努力。
如果一段 Javascript 代码的执行结果是一个32位整数,那么它可以直接作为一个原始类型被访问,而不必转化为一个包装类的实例。这对于64位的浮点数(doubles)和布尔类型的数据来说同样是适用的。
J2V8 使用了一套“懒加载”技术,也就是说,一个 JavaScript 只有在它被需要使用的时候才会通过 JNI 复制到 Java 中,如果 Javascript 返回了一个大型的数组,这个数组的内容直到数组中的元素的被需要的时候才会被加载到 Java 中。
J2V8 仅仅是对 V8 的 Java 封装并暴露出来一系列的接口供 Java 调用,V8 引擎是用 C++ 写的,为了使用 V8,就需要使用JNI来进行调用。C++ 中需要开发者进行内存管理,有申请就需要有对应的释放。V8 的垃圾回收器会帮助我们做一些工作,但是一些 Native 的一些句柄对象如果不再使用的时候仍然需要我们调用 release()
去释放它们。
如果有内存泄漏,当程序运行结束时会有一些报告,比如会有一些打印和异常抛出。
J2V8的使用
J2V8目前支持的平台
- j2v8
- j2v8_android
- j2v8_android_armv7l
- j2v8_android_x86
- j2v8_linux_x86_64
- j2v8_macosx_x86_64
- j2v8_win32_x86
- j2v8_win32_x86_64
仅介绍在 Android 环境下的使用。
添加依赖
在中添加依赖:
dependencies {
compile '.j2v8:j2v8:4.5.0@aar'
}
Hello World
运行下面一段 Hello World 代码,这段脚本将两个字符串连接起来并且返回了结果字符串的长度:
var hello = 'hello, ';
var world = 'world!';
(world).length;
要使用J2V8,首先你必须创建一个运行时环境,J2V8为此提供了一个静态工厂方法。在创建一个运行时环境时,同时也会加载J2V8的本地库。
V8 runtime = V8.createV8Runtime();
int result = (""
+ "var hello = 'hello, ';\n"
+ "var world = 'world!';\n"
+ "(world).length;\n");
("Test","JS result = "+result);
();
会打印:
JS result = 13
为了执行脚本,它提供了多个基于不同返回值的执行方法。在这个例子里,我们使用了 executeIntegerScript()
这个方法,因为脚本执行的结果是一个int类型的整数,并且不需要任何的类型转换和包装。当应用结束时,运行时环境必须被释放。
稍微改动一下:
V8 runtime = V8.createV8Runtime();
String result = (""
+ "var hello = 'hello, ';\n"
+ "var world = 'world!';\n"
+ "(world);\n");
("Test","JS result = "+result);
();
会打印:
JS result = hello, world!
这里我们使用 executeStringScript()
方法返回的是一个 String
的对象。
获取Javascript对象
使用J2V8你可以从Java中获取javascript对象的句柄,下面用一段代码来演示:
private void testJ2V8(){
V8 runtime = V8.createV8Runtime();
(""
+ "var person = {};\n"
+ "var hockeyTeam = {name : 'WolfPack'};\n"
+ " = 'Ian';\n"
+ "person['last'] = 'Bull';\n"
+ " = hockeyTeam;\n");
V8Object person = ("person");
V8Object hockeyTeam = ("hockeyTeam");
("Test"," JS result name = "+("name"));
();
();
();
结果:
JS result name = WolfPack
因为 V8Object
是底层 Javascript 对象的引用,那么我们也可以对这个对象进行操作,比如现在为Javascript增加新的属性,比如 ("captain", person);
在进行了这一步操作之后,新添加的属性 captain
可以在Javascript中立刻被访问到。以下代码可以验证这一点:
("captain", person);
("Test"," JS result "+("person === "));
结果:
JS result true
V8Array
V8Array
继承自 V8Object
,因此提供了相同的存取器方法(accessor / mutator methods,相当于setter / getter方法)。除此之外,V8Array
的元素也可以通过索引来进行访问。V8Object
和 V8Array
都遵循了流式编程模型 ,这使得创建新的JavaScript对象变得非常简单。
V8Object player1 = new V8Object(runtime).add("name", "John");
V8Object player2 = new V8Object(runtime).add("name", "Chris");
V8Array players = new V8Array(runtime).push(player1).push(player2);
("players", players);
();
();
();
调用JavaScript函数
除了执行JavaScript脚本,也可以使用J2V8来调用JavaScript函数。既可以返回一个结果,也可以没有返回值。请看以下javascript函数:
var hockeyTeam = {
name : 'WolfPack',
players : [],
addPlayer : function(player) {
this.(player);
return this.;
}
}
为了在Java中调用上述对象中的函数,我们仅仅只需要一个 hockeyTeam
的句柄。通过这个对象句柄,我们可以向执行脚本一样执行函数。不同与脚本的是,可以传递给函数一个 V8Array
作为它的参数。
V8 runtime = V8.createV8Runtime();
(""
+ "var hockeyTeam = {\n"
+ "name : 'WolfPack',\n"
+ "players : [],\n"
+ "addPlayer : function(player) {\n"
+ " (player);\n"
+ " return ;\n"
+ "}\n"
+ "}\n");
V8Object hockeyTeam = ("hockeyTeam");
V8Object player1 = new V8Object(runtime).add("name", "John");
V8Array parameters = new V8Array(runtime).push(player1);
int size = ("addPlayer", parameters);
("Test", "JS result size = "+size);
();
();
();
();
结果:
JS result size = 1
参数数组的元素被映射为 JavaSscrip t函数的参数。参数数组元素的数量和在函数中声明的参数的数量不必相符,undefined
会被作为默认的值。