如何在 javascriptcore 中为 android 使用 Object.defineProperty
How to use Object.defineProperty in javascriptcore for android
我正在使用此库 运行 java android 上的一些脚本 - https://github.com/LiquidPlayer/LiquidCore/wiki/LiquidCore-as-a-Native-Javascript-Engine
我有一些对象可以暴露给 java 脚本没问题,但我想将一些函数绑定到 class 作为真实的 getter/setter 属性。
在 java 脚本中执行此操作的语法是:
Object.defineProperty(viewWrapper, 'width', {
get: function () {
return viewWrapper.view.width();
}
});
我找到了这个 class:http://ericwlange.github.io/org/liquidplayer/webkit/javascriptcore/JSObjectPropertiesMap.html
我在苹果文档中看到了这个参考:https://developer.apple.com/documentation/javascriptcore/jsvalue/1451542-defineproperty
我这样做的原因是为了完美地遮蔽现有对象,所以我必须能够复制 getter/setter 样式。我可以在 java 脚本层完成工作,但我正在尝试编写尽可能少的代码,并从 java 端公开完全形成的对象。
我在这个页面上试过了,但它最终只是绑定了函数本身。
还有另一种方法,虽然没有很好的记录,但要优雅得多。您可以在 JSObject
.
上使用 @jsexport
属性
private class Foo extends JSObject {
Foo(JSContext ctx) { super(ctx); }
@jsexport(type = Integer.class)
Property<Integer> x;
@jsexport(type = String.class)
Property<String> y;
@jsexport(attributes = JSPropertyAttributeReadOnly)
Property<String> read_only;
@SuppressWarnings("unused")
@jsexport(attributes = JSPropertyAttributeReadOnly | JSPropertyAttributeDontDelete)
int incr(int x) {
return x+1;
}
}
然后你可以在Java和Java脚本中使用getter/setter方法:
Foo foo = new Foo(ctx);
ctx.property("foo", foo);
ctx.evaluateScript("foo.x = 5; foo.y = 'test';");
assertEquals((Integer)5, foo.x.get());
assertEquals("test", foo.y.get());
foo.x.set(6);
foo.y.set("test2");
assertEquals(6, foo.property("x").toNumber().intValue());
assertEquals("test2", foo.property("y").toString());
assertEquals(6, ctx.evaluateScript("foo.x").toNumber().intValue());
assertEquals("test2",
ctx.evaluateScript("foo.y").toString());
ctx.evaluateScript("foo.x = 11");
assertEquals((Integer)11, foo.x.get());
assertEquals(21,
ctx.evaluateScript("foo.incr(20)").toNumber().intValue());
foo.read_only.set("Ok!");
assertEquals("Ok!", foo.read_only.get());
foo.read_only.set("Not Ok!");
assertEquals("Ok!", foo.read_only.get());
ctx.evaluateScript("foo.read_only = 'boo';");
assertEquals("Ok!", foo.read_only.get());
我正在使用此库 运行 java android 上的一些脚本 - https://github.com/LiquidPlayer/LiquidCore/wiki/LiquidCore-as-a-Native-Javascript-Engine
我有一些对象可以暴露给 java 脚本没问题,但我想将一些函数绑定到 class 作为真实的 getter/setter 属性。
在 java 脚本中执行此操作的语法是:
Object.defineProperty(viewWrapper, 'width', {
get: function () {
return viewWrapper.view.width();
}
});
我找到了这个 class:http://ericwlange.github.io/org/liquidplayer/webkit/javascriptcore/JSObjectPropertiesMap.html
我在苹果文档中看到了这个参考:https://developer.apple.com/documentation/javascriptcore/jsvalue/1451542-defineproperty
我这样做的原因是为了完美地遮蔽现有对象,所以我必须能够复制 getter/setter 样式。我可以在 java 脚本层完成工作,但我正在尝试编写尽可能少的代码,并从 java 端公开完全形成的对象。
我在这个页面上试过了,但它最终只是绑定了函数本身。
还有另一种方法,虽然没有很好的记录,但要优雅得多。您可以在 JSObject
.
@jsexport
属性
private class Foo extends JSObject {
Foo(JSContext ctx) { super(ctx); }
@jsexport(type = Integer.class)
Property<Integer> x;
@jsexport(type = String.class)
Property<String> y;
@jsexport(attributes = JSPropertyAttributeReadOnly)
Property<String> read_only;
@SuppressWarnings("unused")
@jsexport(attributes = JSPropertyAttributeReadOnly | JSPropertyAttributeDontDelete)
int incr(int x) {
return x+1;
}
}
然后你可以在Java和Java脚本中使用getter/setter方法:
Foo foo = new Foo(ctx);
ctx.property("foo", foo);
ctx.evaluateScript("foo.x = 5; foo.y = 'test';");
assertEquals((Integer)5, foo.x.get());
assertEquals("test", foo.y.get());
foo.x.set(6);
foo.y.set("test2");
assertEquals(6, foo.property("x").toNumber().intValue());
assertEquals("test2", foo.property("y").toString());
assertEquals(6, ctx.evaluateScript("foo.x").toNumber().intValue());
assertEquals("test2",
ctx.evaluateScript("foo.y").toString());
ctx.evaluateScript("foo.x = 11");
assertEquals((Integer)11, foo.x.get());
assertEquals(21,
ctx.evaluateScript("foo.incr(20)").toNumber().intValue());
foo.read_only.set("Ok!");
assertEquals("Ok!", foo.read_only.get());
foo.read_only.set("Not Ok!");
assertEquals("Ok!", foo.read_only.get());
ctx.evaluateScript("foo.read_only = 'boo';");
assertEquals("Ok!", foo.read_only.get());