JavaScript

本指南介绍如何在已加载的网页上访问 JavaScript、执行 JavaScript 代码、注入 Java 对象以便从 JavaScript 调用 Java 等。

执行 JavaScript 

Fuzio 允许在已加载的网页上访问并执行 JavaScript 代码。

要访问 JavaScript,请确保网页已完全加载,并且 JavaScript 已启用

要执行 JavaScript 代码,请使用 Frame.executeJavaScript(String) 方法。该方法会阻塞当前线程,直到给定的代码执行完毕。该方法返回一个 java.lang.Object,表示执行结果。如果执行结果为 nullundefined,则该方法返回 null

以下示例执行一段返回 document 以下示例执行一段返回:

Java
Kotlin
String title = frame.executeJavaScript("document.title");
val title = frame.executeJavaScript<String>("document.title")

你可以执行任意 JavaScript 代码:

Java
Kotlin
double number = frame.executeJavaScript("123");
boolean bool = frame.executeJavaScript("true");
String string = frame.executeJavaScript("'Hello'");
JsFunction alert = frame.executeJavaScript("window.alert");
JsObject window = frame.executeJavaScript("window");
Element body = frame.executeJavaScript("document.body");
JsPromise promise = frame.executeJavaScript("Promise.resolve('Success')");
JsArray array = frame.executeJavaScript("['Apple', 'Banana']");
JsArrayBuffer arrayBuffer = frame.executeJavaScript("new ArrayBuffer(8)");
JsSet set = frame.executeJavaScript("new Set([1, 2, 3, 4])");
JsMap map = frame.executeJavaScript("new Map([['John', '32'], ['Mary', '26']])");
val number = frame.executeJavaScript<Double>("123")
val bool = frame.executeJavaScript<Boolean>("true")
val string = frame.executeJavaScript<String>("'Hello'")
val alert = frame.executeJavaScript<JsFunction>("window.alert")
val window = frame.executeJavaScript<JsObject>("window")
val body = frame.executeJavaScript<Element>("document.body")
val promise = frame.executeJavaScript<JsPromise>("Promise.resolve('Success')")
val array = frame.executeJavaScript<JsArray>("['Apple', 'Banana']")
val arrayBuffer = frame.executeJavaScript<JsArrayBuffer>("new ArrayBuffer(8)")
val set = frame.executeJavaScript<JsSet>("new Set([1, 2, 3, 4])")
val map = frame.executeJavaScript<JsMap>("new Map([['John', '32'], ['Mary', '26']])")

如果你不希望阻塞当前线程执行,则可以使用 Frame.executeJavaScript(String javaScript, Consumer<?> callback) 方法。该方法会异步执行给定的 JavaScript 代码,并通过给定的 callback 提供执行结果:

Java
Kotlin
frame.executeJavaScript("document.body", (Consumer<Element>) body -> {
    var html = body.innerHtml();
});
frame.executeJavaScript("document.body", Consumer<Element> { body ->
    val html = body.innerHtml()
})

类型转换 

JavaScript 与 Java 使用不同的基本类型。Fuzio 实现了 JavaScript 与 Java 之间的自动类型转换(双向)。

JavaScript 转 Java 

以下规则用于将 JavaScript 转换为 Java 类型:

  • JavaScript 数值转换为java.lang.Double
  • JavaScript string 转换为 java.lang.String
  • JavaScript boolean 转换为 java.lang.Boolean
  • JavaScript nullundefined 转换为 null
  • JavaScript Promise 转换为 JsPromise
  • JavaScript BigInt 转换为 java.math.BigInteger
  • JavaScript 对象被包装为 JsObject
  • JavaScript 函数被包装为 JsFunction
  • JavaScript DOM Node 对象被包装为 JsObjectEventTarget
  • JavaScript ArrayBuffer 被包装为 JsArrayBuffer
  • JavaScript Array 被包装为 JsArray
  • JavaScript Set 被包装为 JsSet
  • JavaScript Map 被包装为 JsMap
  • JavaScript Symbol 被包装为 JsSymbol

在上面的示例中,我们知道 document.title 是字符串,因此将返回值设为 java.lang.String

Java 转 JavaScript 

以下规则用于将 Java 转换为 JavaScript 类型:

  • java.lang.Double 转换为 JavaScript Number
  • java.lang.String 转换为 JavaScript string
  • java.lang.Boolean 转换为 JavaScript boolean
  • Java null 转换为 JavaScript null
  • JsObject 转换为相应的 JavaScript 对象
  • JsPromise 转换为 JavaScript Promise
  • java.util.concurrent.CompletableFuture 转换为 Promise
  • EventTarget 转换为相应的 JavaScript DOM Node 对象
  • java.math.BigInteger 转换为 BigInt
  • java.lang.Object 将被包装为 JavaScript 代理对象
  • java.util.List<?> 转换为 JavaScript Array 或代理对象
  • JsArray 转换为 JavaScript Array
  • java.util.Set<?> 转换为 JavaScript Set 或代理对象
  • JsSet 转换为 JavaScript Set
  • java.util.Map<?,?> 转换为 JavaScript Map 或代理对象
  • JsMap 转换为 JavaScript Map
  • byte[] 转换为 JavaScript ArrayBuffer
  • JsArrayBuffer 转换为 JavaScript ArrayBuffer
  • JsSymbol 转换为 JavaScript Symbol

如果将非原始类型的 Java 对象传递给 JavaScript,它将被转换为代理对象。对该代理对象的方法和属性调用将被委托给 Java 对象。出于安全考虑,JavaScript 只能访问注入的 Java 对象中显式标记为可访问的方法和字段,这些方法和字段可以通过 @JsAccessible 注解或 JsAccessibleTypes 类进行访问。

未使用 @JsAccessible 注解或 JsAccessibleTypes 类标记为可访问的 Java 集合将被转换为 JavaScript 集合。转换后的集合内容是 Java 集合的深拷贝。在 JavaScript 中修改转换后的集合不会影响 Java 中的集合。

使用 @JsAccessible 注解或 JsAccessibleTypes 类标记为可访问的 Java 集合将被包装为 JavaScript 代理对象。此类代理对象可用于修改 Java 中的集合。

DOM 包装器 

按照自动类型转换规则,JavaScript 的 DOM 对象会同时被包装为 JsObjectEventTarget。这使你能够通过 Fuzio 的 DOM API 处理 JavaScript DOM 对象。

下面示例中,我们返回代表 JavaScript DOM 对象的 document。在这种情况下,返回值可以设置为 JsObjectDocument

Java
Kotlin
Document document = frame.executeJavaScript("document");
val document = frame.executeJavaScript<Document>("document")
Java
Kotlin
JsObject document = frame.executeJavaScript("document");
val document = frame.executeJavaScript<JsObject>("document")

使用 JsObject 

要从 Java 代码中操作 JavaScript 对象,请使用 JsObject 类。它允许你操作对象属性并调用其函数。

属性 

要获取 JavaScript 对象的属性名称,包括其原型对象上的属性,请使用 propertyNames() 方法:

Java
Kotlin
var propertyNames = jsObject.propertyNames();
val propertyNames = jsObject.propertyNames()

要检查 JavaScript 对象是否包含指定属性,请使用 hasProperty(String) 方法:

Java
Kotlin
var has = jsObject.hasProperty("<property-name>");
val has = jsObject.hasProperty("<property-name>")

要通过属性名获取 JavaScript 对象属性的值,请使用 property(String)。例如:

Java
Kotlin
JsObject document = frame.executeJavaScript("document");
document.property("title").ifPresent(title -> {});
val document = frame.executeJavaScript<JsObject>("document")!!
document.property<String>("title").ifPresent { title -> }

返回值表示 java.lang.Object,可以设置为所需类型。请参阅类型转换

你可以使用以下方式移除属性:

Java
Kotlin
var success = jsObject.removeProperty("<property-name>");
val success = jsObject.removeProperty("<property-name>")

函数 

要调用指定名称并传入参数的函数,请使用 call(String methodName, Object... args) 方法。以下示例演示如何调用 JavaScript 函数 document.getElementById()

Java
Kotlin
JsObject element = document.call("getElementById", "elementId");
val element: JsObject = document.call("getElementById", "elementId")

这等价于以下 JavaScript 代码:

var element = document.getElementById("demo");

如果函数执行期间发生错误,该方法会抛出 JsException

关闭 

拥有 JsObject 对应项的 V8 对象不受 V8 垃圾回收机制管理。默认情况下,我们会将这些对象保留在内存中,直到页面被卸载。

为了优化内存使用,你可以按对象启用垃圾回收:

Java
Kotlin
jsObject.close();
jsObject.close()

关闭 JsObject 会将对应的 V8 对象标记为可回收,但不会立即释放对象。调用 close() 后,继续使用 JsObject 将导致 ObjectClosedException

JsFunctionCallback 

从 JavaScript 调用 Java 的另一种方式是使用 JsFunctionCallback

JavaScript-Java 桥接允许你将 JsFunctionCallback 关联到某个 JavaScript 属性上,使其被当作一个可在 JavaScript 中调用的函数。

例如,你可以使用以下代码注册一个与 JsFunctionCallback 实例关联的 JavaScript 函数:

Java
Kotlin
JsObject window = frame.executeJavaScript("window");
if (window != null) {
    window.putProperty("sayHello", (JsFunctionCallback) args ->
            "Hello, " + args[0]);
}
val window = frame.executeJavaScript<JsObject>("window")
window?.putProperty("sayHello", JsFunctionCallback { args -> "Hello, ${args[0]}" })

现在,在 JavaScript 中,你可以通过以下方式调用该函数:

window.sayHello('John');

JsFunction 

你可以直接在从 Java 中操作 JavaScript 函数,也可以将函数引用从 JavaScript 传递给 Java。例如:

Java
Kotlin
JsObject window = frame.executeJavaScript("window");
if (window != null) {
    JsFunction alert = frame.executeJavaScript("window.alert");
    if (alert != null) {
        alert.invoke(window, "Hello world!");
    }
}
val window = frame.executeJavaScript<JsObject>("window")
if (window != null) {
    val alert = frame.executeJavaScript<JsFunction>("window.alert")
    alert?.invoke<Any>(window, "Hello world!")
}

JsPromise 

你可以直接在 Java 代码中操作 JavaScript 的 Promises。例如:

Java
Kotlin
JsPromise promise = frame.executeJavaScript(
        "new Promise(function(resolve, reject) {\n"
                + "    setTimeout(function() {\n"
                + "        resolve('Hello Java!');\n"
                + "    }, 2000);"
                + "})"
);
promise.then(results -> {
    System.out.println(results[0]);
    return promise;
}).then(results -> {
    System.out.println(results[0]);
    return promise;
}).catchError(errors -> {
    System.out.println(errors[0]);
    return promise;
});
val promise = frame.executeJavaScript<JsPromise>(
    """new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('Hello Java!');
        }, 2000);
    })
"""
)!!
promise.then { results ->
    println(results[0])
    promise
}.then { results ->
    println(results[0])
    promise
}.catchError { errors ->
    println(errors[0])
    promise
}

此外,Fuzio 会自动将 CompletableFuture 转换为 JavaScript 的 Promise

Java
Kotlin
var future = CompletableFuture.supplyAsync(() -> "Hello world");
window.putProperty("myPromise", future);
frame.executeJavaScript("""
    myPromise
        .then((result) => console.log(result))
        .catch((error) => console.log(error))
""");
val future = CompletableFuture.supplyAsync {
    "Hello world"
}
window.putProperty("myPromise", future)
frame.executeJavaScript<Any>("""
        myPromise
            .then((result) => console.log(result))
            .catch((error) => console.log(error))
""")

不支持将 Promise 再转换回CompletableFuture

JsSymbol 

你可以使用 JsSymbol 接口在 Java 中直接操作 JavaScript Symbol 对象。例如:

Java
Kotlin
JsSymbol symbol = frame.executeJavaScript("Symbol('bacf2f')");
symbol.description().ifPresent(description -> {
    System.out.println(description);
});
val symbol = frame.executeJavaScript<JsSymbol>("Symbol('bacf2f')")!!
symbol.description().ifPresent { description ->
    println(description)
}

JavaScript 集合 

你可以直接从 Java 代码中操作 JavaScript 的 arrayssetsmaps。当这些 JavaScript 数据结构实例被传递到 Java 时,Fuzio 会自动将其转换为特殊的包装类型:

Java
Kotlin
JsMap map = frame.executeJavaScript("new Map([['key', 'value']]);");
JsSet set = frame.executeJavaScript("new Set(['item'])");
JsArray array = frame.executeJavaScript("['foo', 'bar']");
val map: JsMap? = frame.executeJavaScript<JsMap>("new Map([['key', 'value']]);")
val set: JsSet? = frame.executeJavaScript<JsSet>("new Set(['item'])")
val array: JsArray? = frame.executeJavaScript<JsArray>("['foo', 'bar']")

JsMapJsSetJsArray 类会直接操作底层 V8 数据结构,除非你显式请求,否则不会拷贝数据。这些类的方法接受基本类型、任意 Java 对象以及 JsObject 实例,并会按照 Java 转 JavaScript 的转换规则进行转换。

Map 

要向 map 中添加元素,请使用 JsMap.add(Object key, Object value) 方法:

Java
Kotlin
map.set("key", "value");
map["key"] = "value"

要从 map 中获取元素,请使用 JsMap.get(Object) 方法:

Java
Kotlin
var value = map.get("key");
val value: Any = map["key"]

要检查 map 中是否存在某个 key,请使用 JsMap.has(Object) 方法:

Java
Kotlin
var hasKey = map.has("key");
val hasKey = map.has("key")

要从 map 中删除元素,请使用 JsMap.delete(Object) 方法:

Java
Kotlin
map.delete("key");
map.delete("key")

要获取 map 的大小,请使用 JsMap.size() 方法:

Java
Kotlin
long size = map.size();
val size = map.size()

要移除 map 中所有元素,请使用 JsMap.clear() 方法:

Java
Kotlin
map.clear();
map.clear()

要将 JavaScript map 转换为 java.uti.Map,请使用 JsMap.toMap() 方法,该方法会拷贝数据

Java
Kotlin
Map<Object, Object> javaMap = map.toMap();
Map<String, JsObject> typedJavaMap = map.toMap(String.class, JsObject.class);
val javaMap = map.toMap()
val typedJavaMap = map.toMap(String::class.java, JsObject::class.java)

Set 

要向 set 中添加元素,请使用 JsSet.add(Object)

Java
Kotlin
set.add("item");
set.add("item")

要从 set 中删除元素,请使用 JsSet.delete(Object)

Java
Kotlin
set.delete("item");
set.delete("item")

要删除 set 中所有元素,请使用 JsSet.clear() 方法:

Java
Kotlin
set.clear();
set.clear()

要检查 set 中是否存在某个元素,请使用 JsSet.has(Object)

Java
Kotlin
var hasItem = set.has("item");
val hasItem = set.has("item")

要读取 set 的大小,请使用 JsSet.size() 方法:

Java
Kotlin
var size = set.size();
val size = set.size()

要将 JavaScript set 转换为 java.util.Set,请使用 JsSet.toSet() 方法,该方法会拷贝数据

Java
Kotlin
Set<Object> javaSet = set.toSet();
Set<String> typedJavaSet = set.toSet(String.class);
val javaSet: Set<Any> = set.toSet()
val typedJavaSet: Set<String> = set.toSet(String::class.java)

Array 

要读取 array 中的元素,请使用 JsArray.get(long) 方法:

Java
Kotlin
var item = array.get(42);
val item: Any? = array[42]

要按索引设置元素,请使用 JsArray.set(long) 方法:

Java
Kotlin
array.set(42, "Item");
array[42] = "Item"

要读取 array 长度,请使用 JsArray.length() 方法:

Java
Kotlin
var length = array.length();
val length = array.length()

要将 JavaScript array 转换为 java.util.List,请使用 JsArray.toList() 方法,该方法会拷贝数据

Java
Kotlin
List<Object> javaList = array.toList();
List<JsObject> typedJavaList = array.toList(JsObject.class);
val javaList = array.toList()
val typedJavaList = array.toList(JsObject::class.java)

从 JavaScript 调用 Java 

当你将 java.lang.Object 作为属性值,或作为调用 JavaScript 函数时的参数传入时,该 Java 对象会自动被包装为 JavaScript 对象。

这使得你可以,或作为调用 JavaScript 函数时的参数传入时,该 Java 对象会自动被包装为 JavaScript 对象。

出于安全原因,只有带有 @JsAccessible 注解的公共非静态方法和字段,或声明在带有 @JsAccessible 注解类中的公共非静态方法和字段,才能从 JavaScript 访问。带有该注解但本身是受保护的、私有的或包私有的方法和字段,以及声明在具有这些访问级别的类中的方法和字段,仍然无法从 JavaScript 访问。

要将 Java 对象注入到 JavaScript 中,请先定义 Java 对象类,并使用 @JsAccessible 标记应允许 JavaScript 访问的公共方法:

Java
Kotlin
public final class JavaObject {
    @JsAccessible
    public String sayHelloTo(String firstName) {
        return "Hello " + firstName + "!";
    }
}
class JavaObject {
    @JsAccessible
    fun sayHelloTo(firstName: String) = "Hello $firstName!"
}

在已加载网页上的 JavaScript 执行之前,将 Java 对象实例注入到 JavaScript 中:

Java
Kotlin
browser.set(InjectJsCallback.class, params -> {
    JsObject window = params.frame().executeJavaScript("window");
    window.putProperty("java", new JavaObject());
    return InjectJsCallback.Response.proceed();
});
browser.register(InjectJsCallback { params ->
    val window = params.frame().executeJavaScript<JsObject>("window")
    window?.putProperty("java", JavaObject())
    InjectJsCallback.Response.proceed()
})

现在你可以在 JavaScript 中引用该对象并调用其方法:

window.java.sayHelloTo("John");

注解规则 

@JsAccessible 注解允许将注入的 Java 对象的方法与字段暴露给 JavaScript。

你只能使公共类型、方法和字段变为可访问。支持的完整情况如下:

  • 顶层类或接口
  • 嵌套静态类或接口
  • 类或接口的非静态方法
  • 嵌套静态类或接口

该注解不能应用于非公共类型、方法和字段。非公共类型中的公共方法和字段也被视为非公共。当你为一个类型添加注解时,该类型的所有公共方法和字段都将可从 JavaScript 访问。若你在一个未注解类型的方法或字段上添加注解,则只有被注解的成员可从 JavaScript 访问。

一个可访问的方法在子类中被重写后,仍然保持可访问。这意味着,你可以让一个接口变为可访问,并将其任意实现传递给 JavaScript:接口中声明的所有方法都可从 JavaScript 访问。实现类中声明的其他方法和字段则仍不可访问,除非你显式为它们或整个类型添加该注解。

另一种使类型可从 JavaScript 访问的方法是使用 JsAccessibleTypes。当您希望暴露某些 Java 核心类型(例如 java.util.List),或希望暴露某个无法使用该注解修改的第三方库类型时,这一点尤其有用。

示例:

公共顶级类中带注解的方法和字段是可访问的:

Java
Kotlin
public final class TopClassDemo {
    @JsAccessible
    public Object accessibleField;
    @JsAccessible
    public void accessibleMethod() {}
}
class TopClassDemo {
    @JsAccessible
    var accessibleField: Any? = null
    @JsAccessible
    fun accessibleMethod() {}
}

公共顶级类中带注解的方法和字段是可访问的:

Java
Kotlin
public final class TopClassWithNestedDemo {
    public static class NestedClass {
        @JsAccessible
        public Object accessibleField;
        @JsAccessible
        public void accessibleMethod() {}
    }
}
class TopClassWithNestedDemo {
    class NestedClass {
        @JsAccessible
        var accessibleField: Any? = null
        @JsAccessible
        fun accessibleMethod() {}
    }
}

公共静态嵌套类中带注解的方法和字段是可访问的:

Java
Kotlin
@JsAccessible
public final class ClassWithUnannotatedMembersDemo {
    public Object accessibleField;
    public void accessibleMethod() {}
}
@JsAccessible
class ClassWithUnannotatedMembersDemo {
    var accessibleField: Any? = null
    fun accessibleMethod() {}
}

带注解基类中的方法和字段,在继承类中也是可访问的:

Java
Kotlin
public final class AccessFromInheritorsDemo {
    @JsAccessible
    public static class BaseNestedClass {
        public Object accessibleFieldFromInheritor;
        public void accessibleMethodFromInheritor() {}
    }
    public static class NestedClass extends BaseNestedClass {
        public Object inaccessibleField;
        public void inaccessibleMethod() {}
    }
}
class AccessFromInheritorsDemo {
    @JsAccessible
    open class BaseNestedClass {
        var accessibleFieldFromInheritor: Any? = null
        fun accessibleMethodFromInheritor() {}
    }
    class NestedClass : BaseNestedClass() {
        var inaccessibleField: Any? = null
        fun inaccessibleMethod() {}
    }
}

如果继承的方法和字段或声明它们的类没有被注解,则无法访问继承的方法和字段:

Java
Kotlin
public final class UnannotatedClassAccessDemo {
    public static class BaseNestedClass {
        public Object inaccessibleField;
        public void inaccessibleMethod() {}
    }
    @JsAccessible
    public static class NestedClass extends BaseNestedClass {
        public Object accessibleField;
        public void accessibleMethod() {}
    }
}
class UnannotatedClassAccessDemo {
    open class BaseNestedClass {
        var inaccessibleField: Any? = null
        fun inaccessibleMethod() {}
    }
    @JsAccessible
    class NestedClass : BaseNestedClass() {
        var accessibleField: Any? = null
        fun accessibleMethod() {}
    }
}

重写的类方法是可访问的:

Java
Kotlin
public final class OverriddenMethodsAccessDemo {
    public static class BaseNestedClass {
        @JsAccessible
        public void method() {}
    }
    public static class NestedClass extends BaseNestedClass {
        @Override
        public void method() {} // 可访问。
    }
}
class OverriddenMethodsAccessDemo {
    open class BaseNestedClass {
        @JsAccessible
        open fun method() {
        }
    }
    class NestedClass : BaseNestedClass() {
        override fun method() {} // 可访问。
    }
}

实现接口的方法是可访问的:

Java
Kotlin
public final class ImplInterfaceMethodsAccessDemo {
    public interface NestedInterface {
        @JsAccessible
        void method();
    }
    public static class AccessibleImplementor implements NestedInterface {
        @Override
        public void method() { } // 可访问。
    }
}
class ImplInterfaceMethodsAccessDemo {
    interface NestedInterface {
        @JsAccessible
        fun method()
    }
    class AccessibleImplementor : NestedInterface {
        override fun method() {} // 可访问。
    }
}

如果可访问的 Java 方法签名中包含基本数值类型参数,那么从 JavaScript 传入的数值会先检查能否转换为对应的 Java 参数类型。若该转换可在不丢失数据的情况下完成,且没有其他更合适的重载方法,则会调用该方法。

如果存在多个都可以接收传入参数的方法,JavaScript 会抛出异常,指出所请求的方法调用存在歧义,无法执行。

如果找不到与请求名称对应的方法或字段,JavaScript 会抛出异常,指出所请求的成员不存在。

如果 JavaScript 请求的同名方法和字段同时存在,JavaScript 会抛出异常,指出该成员存在歧义,无法访问。

自动类型转换 

在从 JavaScript 调用注入的 Java 对象公共方法时,JavaScript-Java 桥会提供自动类型转换功能。

库会自动将传入的 JavaScript Number 转换为所需的 Java 类型,前提是这种转换可行。如果检测到给定数值无法在不丢失数据的情况下转换为例如 Java byte,库就会抛出异常,并通知 JavaScript 没有合适的 Java 方法。如果该值可以无损转换,库就会执行转换并调用相应的方法。

例如,若你向 JavaScript 注入以下 Java 对象:

Java
Kotlin
public final class JavaObjectWithTypeConversion {
    @JsAccessible
    public int method(int intValue) {
        return intValue;
    }
}
class JavaObjectWithTypeConversion {
    @JsAccessible
    fun method(intValue: Int) = intValue
}

那么,你可以在 JavaScript 中调用它,并传入一个可无损转换为 Integer 的 JavaScript Number 值:

window.javaObject.method(123);

但如果你传入一个无法无损转换为 IntegerDouble 值,就会报错:

window.javaObject.method(3.14); // <- error

从库中调用 

注入到 JavaScript 的 Java 对象属于特殊对象。它们的行为与普通 JavaScript 对象不同,不建议直接将其传递给 JavaScript 库。

在将其用于 JavaScript 库之前,我们建议先用 Proxy 对其进行包装。在以下示例中,我们创建了一个实现对 JS 可访问成员只读访问的代理对象:

const proxy = new Proxy({__java: myJavaObject}, {
    get(target, prop, receiver) {
        for (let javaMemberName in target.__java) {
            if (prop === javaMemberName) {
                return target.__java[prop]
            }
        }
        return Reflect.get(...arguments);
    },
    ...
});

控制台消息 

Fuzio 允许接收通过 console.log() JavaScript 函数发送到控制台的所有输出消息。您可以监听以下级别的消息:

  • DEBUG
  • LOG
  • WARNING
  • ERROR

要在 Console 收到消息时得到通知,请使用 ConsoleMessageReceived 事件。例如:

Java
Kotlin
browser.on(ConsoleMessageReceived.class, event -> {
    var consoleMessage = event.consoleMessage();
    var level = consoleMessage.level();
    var message = consoleMessage.message();
});
browser.subscribe<ConsoleMessageReceived> { event ->
    val consoleMessage = event.consoleMessage()
    val level = consoleMessage.level()
    val message = consoleMessage.message()
}

JSON 

Fuzio 提供了一个辅助类,用于在 JavaScript 对象与 JSON 格式之间进行转换:

Java
Kotlin
Json json = frame.json();
val json = frame.json()

Json 类允许你在某个 frame 的 JavaScript 上下文中,根据 JSON 字符串创建对象。

Java
Kotlin
JsObject parsedObject = json.parse("{'name': 'John'}");
val parsedObject = frame.json().parse<JsObject>("{'name': 'John'}")

同样,你也可以将 JavaScript 对象转换为 JSON 字符串:

Java
Kotlin
JsObject myObject = frame.executeJavaScript("window.myobject");
String myObjectAsJson = frame.json().stringify(myObject);
val myObject = frame.executeJavaScript<JsObject>("window.myobject")
val myObjectAsJson = frame.json().stringify(myObject)

Json 的实现依赖 V8 的 JSON 函数,因此具有与 JavaScript 内置 JSON 命名空间相同的限制。

微信咨询

即库客服

微信公众号二维码

技术客服

微信公众号二维码