一、JXBrowser调用js方法
JxBrowser是一个Java和Chromium之间的桥梁库,允许开发人员在应用程序中引入Chromium浏览器的功能。要在JxBrowser中调用JavaScript函数,您可以使用JxBrowser的
JSObject
类提供的方法。
以下是一个简单的示例,演示如何在JxBrowser中调用JavaScript函数:
import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.engine.EngineOptions;
import com.teamdev.jxbrowser.view.swing.BrowserView;
import java.awt.*;
import java.util.concurrent.ExecutionException;
import static com.teamdev.jxbrowser.engine.RenderingMode.OFF_SCREEN;
import static com.teamdev.jxbrowser.engine.RenderingMode.HARDWARE_ACCELERATED;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Engine engine = Engine.newInstance(OFF_SCREEN); //创建渲染模式为OFF_SCREEN的引擎
Browser browser = engine.newBrowser();
BrowserView view = BrowserView.newInstance(browser);
JFrame frame = new JFrame("JxBrowser example");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(view, BorderLayout.CENTER);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//等待加载完成
browser.navigation().loadUrlAndWait("https://example.com/");
//调用js函数
JSObject window = browser.mainFrame().executeJavaScriptAndReturnValue("window").asObject();
window.invoke("myFunction", "hello world!");
}
}
在以上代码中,首先使用JxBrowser的Engine
类创建一个渲染模式为OFF_SCREEN的引擎,创建一个浏览器实例,并使用BrowserView
将浏览器添加到Swing界面中。
接着,加载一个包含JavaScript函数 myFunction()
的示例页面,并将字符串“hello world”作为参数传递给它。使用executeJavaScriptAndReturnValue()
和asObject()
方法获取浏览器窗口对象Window
,并使用invoke()
方法调用其myFunction()
函数,将字符串作为参数传入。
需要注意的是,此示例仅适用于渲染模式为OFF_SCREEN。如果使用的是HARDWARE_ACCELERATED渲染模式,需要在使用
Engine
类创建引擎时将渲染模式设置为HARDWARE_ACCELERATED
。另外,如果想从JavaScript代码中获取Java对象,可以在JavaScript中使用Java对象的引用,例如:// create a Java object var myObject = Java.type('com.example.MyObject').new(); // call a method on that object var result = myObject.myMethod('hello', 'world');
然后通过
JSObject
对象调用JavaScript代码:JSObject window = browser.mainFrame().executeJavaScriptAndReturnValue("window").asObject(); window.setMember("MyJavaObject", myJavaObject); Object result = window.invoke("MyJavaObject.myMethod", "hello", "world");
在JxBrowser中,可以使用
setMember()
方法设置任何类型的Java对象,这些对象都可以在JavaScript中访问和使用。
二、JavaScript调用JAVA方法
当将 java.lang.Object
作为属性值传递,或者在调用 JavaScript 函数时作为参数传递时,Java 对象将自动包装到 JavaScript 对象中。
它允许将 Java 对象注入 JavaScript 并从 JavaScript 调用其公共方法和字段。
出于安全原因,只有用
@JsAccessible
注释的或用@JsAccessible
注释的类中声明的公共非静态方法和字段可以从 JavaScript 中访问。 带注释受保护的、私有的或包私有的方法和字
段,或者在类中使用此类修饰符声明的方法和字段,在 JavaScript 中仍然不可访问。
要将 Java 对象注入 JavaScript,可以定义 Java 对象类并使用 @JsAccessible
标记可从 JavaScript 访问的公共方法:
public final class JavaObject {
@JsAccessible
public String sayHelloTo(String firstName) {
return "Hello " + firstName + "!";
}
}
在加载的网页上执行 JavaScript 之前,向 JavaScript 中注入一个 Java 对象的实例:
browser.set(InjectJsCallback.class, params -> {
JsObject window = params.frame().executeJavaScript("window");
window.putProperty("java", new JavaObject());
return InjectJsCallback.Response.proceed();
});
然后从 JavaScript 引用该对象并调用其方法:
window.java.sayHelloTo("John");
三、注释规则
@JsAccessible
注解允许将注入的 Java 对象的方法和字段暴露给 JavaScript。
可以只允许公共类型、方法和字段成为可访问对象。 受支持案例的完整列表如下:
- 顶级类或接口
- 嵌套的静态类或接口
- 类或接口的非静态方法
- 类的非静态字段
注释不能应用于非公共类型、方法和字段。 非公共类型的公共方法和字段被认为是非公共的。 当注释一个类型时,它的所有公共方法和字段都可供 JavaScript 访问。 当注释一个方法或一个未注释类型的字段时,只有注释的成员可以被 JavaScript 访问。
可访问的方法在子类中被重写时仍然如此。 这意味着可以使接口可访问并将其任何实现传递给 JavaScript:接口中声明的所有方法都可以从 JavaScript 访问。 在实现类中声明的其他方法和字段将保持不可访问,除非使用此注释显式标记它们或整个类型。
另一种使类型可从 JavaScript 访问的方法是使用 JsAccessibleTypes
。如果想要核心 Java 类型之一(例如 java.util.List
)可访问,或者无法使用此注释访问第三方库中的类型时,这特别有用。
示例:
1、公共顶级类的注释方法和字段可以访问:
public final class TopClass {
@JsAccessible
public Object accessibleField;
@JsAccessible
public void accessibleMethod() {}
}
2、公共静态嵌套类的注释方法和字段是可访问的:
public final class TopClass {
public static class NestedClass {
@JsAccessible
public Object accessibleField;
@JsAccessible
public void accessibleMethod() {}
}
}
3、带注释类的未注释方法和字段是可访问的:
@JsAccessible
public final class TopClass {
public Object accessibleField;
public void accessibleMethod() {}
}
4、基本注释类的方法和字段可以从继承者访问:
public final class TopClass {
@JsAccessible
public static class BaseNestedClass {
public Object accessibleFieldFromInheritor;
public void accessibleMethodFromInheritor() {}
}
public static class NestedClass extends BaseNestedClass {
public Object inaccessibleField;
public void inaccessibleMethod() {}
}
}
5、如果继承的方法和字段或它们所声明的类没有被注释,则无法访问:
public final class TopClass {
public static class BaseNestedClass {
public Object inaccessibleField;
public void inaccessibleMethod() {}
}
@JsAccessible
public static class NestedClass extends BaseNestedClass {
public Object accessibleField;
public void accessibleMethod() {}
}
}
6、覆盖类的方法是可访问的:
public final class TopClass {
public static class BaseNestedClass {
@JsAccessible
public void method() {}
}
public static class NestedClass extends BaseNestedClass {
@Override
public void method() {} // accessible
}
}
7、已实现的接口方法是可访问的:
public static class TopClass {
public interface NestedInterface {
@JsAccessible
void method();
}
public static class AccessibleImplementor implements NestedInterface {
@Override
public void method() { } // accessible
}
}
如果可访问的 Java 方法的签名具有原始数字参数,则将检查从 JavaScript 传输的数字是否有可能转换为 Java 参数类型。 如果可以在不丢失数据的情况下执行转换并且没有找到其他合适的重载方法,则将调用该方法。
如果确实存在不止一种可以接受传递参数的方法,JavaScript 会抛出一个异常,表明所请求的方法调用不明确,无法执行。
如果找不到与请求的名称对应的方法或字段,JavaScript 将抛出异常,指示请求的成员不存在。
如果 JavaScript 请求的同名方法和字段都存在,则 JavaScript 抛出异常,表示请求的成员不明确,无法访问。