映射

在本节中,我们将展示 6.x 版本的主要功能如何映射到 7.0 版本。

引擎

创建引擎

6.x

Engine 不是公共 API 的一部分。它是在应用程序中创建第一个 Browser 实例时在内部创建的。在应用程序中只能创建和使用一个 Engine

7.0

现在,Engine 是公共 API 的一部分。您可以在应用程序中创建和使用多个 Engine 实例。要使用所需选项创建 Engine 实例,请使用以下代码:

Engine engine = Engine.newInstance(
        EngineOptions.newBuilder(RenderingMode.OFF_SCREEN)
                // 默认错误页面和 GUI 使用的语言。
                .language(Language.ENGLISH_US)
                // 存储数据的绝对路径,
                // 例如缓存、Cookie、历史记录、GPU 缓存、本地存储、
                // 已访问链接、网页数据、拼写检查字典文件等。
                .userDataDir(Paths.get("/Users/Me/JxBrowser/UserData"))
                .build());
val engine = Engine.newInstance(
        EngineOptions.newBuilder(RenderingMode.OFF_SCREEN) 
            // 默认错误页面和 GUI 使用的语言。
            .language(Language.ENGLISH_US)
            // 存储数据的绝对路径,
            // 例如缓存、Cookie、历史记录、GPU 缓存、本地存储、 
            // 已访问链接、网页数据、拼写检查字典文件等。
            .userDataDir(Path("/Users/Me/JxBrowser/UserData"))
            .build()
)

Engine 运行一个单独的本地进程,在该进程中创建并初始化带有提供选项的 Chromium。本地进程通过进程间通信(IPC)桥与 Java 进程通信。如果本地进程因崩溃而意外终止,Java 进程将继续运行。

您可以使用以下通知来了解 Engine 何时意外终止,以便您可以重新创建引擎并恢复 Browser 实例:

engine.on(EngineCrashed.class, event -> {
   // 清除所有已分配的资源并重新创建引擎。
});
engine.on(EngineCrashed::class.java) { event ->
    // 清除所有已分配的资源并重新创建引擎。
}

关闭引擎

6.x

当应用程序中的最后一个 Browser 实例关闭时,Engine 会自动关闭。

7.0

当不再需要引擎时,应通过 close() 方法手动关闭 Engine

engine.close();
engine.close()

当您关闭 Engine 时,所有其 Browser 实例都将自动关闭。任何尝试使用已关闭的 Engine 的操作都会导致异常。

要了解 Engine 何时关闭,请使用以下通知:

engine.on(EngineClosed.class, event -> {});
engine.on(EngineClosed::class.java) { event -> }

浏览器

创建浏览器

6.x

Browser browser = new Browser();
val browser = Browser()

7.0

Browser browser = engine.newBrowser();
val browser = engine.newBrowser()

使用选项创建浏览器

6.x

BrowserContextParams browserContextParams =
        new BrowserContextParams("Users/Me/JxBrowser/Data");
browserContextParams.setStorageType(StorageType.MEMORY);
BrowserContext browserContext = new BrowserContext(browserContextParams);
Browser browser = new Browser(BrowserType.HEAVYWEIGHT, browserContext);
val browserContextParams = BrowserContextParams("Users/Me/JxBrowser/Data")
browserContextParams.setStorageType(StorageType.MEMORY)
val browserContext = BrowserContext(browserContextParams)
val browser = Browser(BrowserType.HEAVYWEIGHT, browserContext)

7.0

BrowserContext 功能已经移至 Engine。因此,应将相同的代码替换为:

Engine engine = Engine.newInstance(EngineOptions.newBuilder(HARDWARE_ACCELERATED)
        .userDataDir(Paths.get("/Users/Me/JxBrowser/UserData"))
        .enableIncognito()
        .build());
Browser browser = engine.newBrowser();
val engine = Engine.newInstance(EngineOptions.newBuilder(HARDWARE_ACCELERATED)
        .userDataDir(Path("/Users/Me/JxBrowser/UserData"))
        .enableIncognito()
        .build()
) 
val browser = engine.newBrowser()

关闭浏览器

6.x

browser.dispose();
browser.dispose()

7.0

browser.close();
browser.close()

响应/无响应

6.x

browser.addRenderListener(new RenderAdapter() {
    @Override
    public void onRenderUnresponsive(RenderEvent event) {}

    @Override
    public void onRenderResponsive(RenderEvent event) {}
});
browser.addRenderListener(object: RenderAdapter {
    override fun onRenderUnresponsive(event: RenderEvent) {}
    override fun onRenderResponsive(event: RenderEvent) {}
})

7.0

browser.on(BrowserBecameResponsive.class, event -> {});
browser.on(BrowserBecameUnresponsive.class, event -> {});
browser.on(BrowserBecameResponsive::class.java) { event -> }
browser.on(BrowserBecameUnresponsive::class.java) { event -> }

BrowserView

创建 Swing BrowserView

6.x

import com.teamdev.jxbrowser.chromium.swing.BrowserView;
...
BrowserView view = new BrowserView(browser);
import com.teamdev.jxbrowser.chromium.swing.BrowserView
...
val view = BrowserView(browser)

7.0

import com.teamdev.jxbrowser.view.swing.BrowserView;
...
BrowserView view = BrowserView.newInstance(browser);
import com.teamdev.jxbrowser.view.swing.BrowserView
...
val view = BrowserView.newInstance(browser)

创建 JavaFX BrowserView

6.x

import com.teamdev.jxbrowser.chromium.javafx.BrowserView;
...
BrowserView view = new BrowserView(browser);
import com.teamdev.jxbrowser.chromium.javafx.BrowserView
...
val view = BrowserView(browser)

7.0

import com.teamdev.jxbrowser.view.javafx.BrowserView;
...
BrowserView view = BrowserView.newInstance(browser);
import com.teamdev.jxbrowser.view.javafx.BrowserView
...
val view = BrowserView.newInstance(browser)

框架

与框架交互

6.x

一个网页可能包含一个主框架,该框架可能包含多个子框架。要对某个框架执行操作,您需要将框架的标识符传递给对应的方法。例如:

// 获取主框架的 HTML。
browser.getHTML();

// 获取所有框架的 HTML。
for (Long frameId : browser.getFramesIds()) {
    String html = browser.getHTML(frameId);
}
// 获取主框架的 HTML。
browser.html

// 获取所有框架的 HTML。
for (frameId in browser.framesIds) {
    val html = browser.getHTML(frameId)
}

7.0

Frame 现在是公共 API 的一部分。您可以通过 Frame 实例与框架进行交互。例如:

// 如果主框架存在,则获取其 HTML。
browser.mainFrame().ifPresent(Frame::getHtml);

// 获取所有框架的 HTML。
browser.frames().forEach(frame -> {
    String html = frame.html();
});
// 如果主框架存在,则获取其 HTML。
browser.mainFrame().ifPresent(Frame::getHtml)

// 获取所有框架的 HTML。
browser.frames().forEach { frame ->
    val html = frame.html()
}

导航

加载 URL

6.x

browser.loadURL("https://www.google.com");
browser.loadURL("https://www.google.com")

7.0

browser.navigation().loadUrl("https://www.google.com");
browser.navigation().loadUrl("https://www.google.com")

加载 HTML

6.x

browser.loadHTML("<html><body></body></html>");
browser.loadHTML("<html><body></body></html>")

7.0

browser.mainFrame().ifPresent(frame ->
        frame.loadHtml("<html><body></body></html>"));
browser.mainFrame().ifPresent { frame -> 
        frame.loadHtml("<html><body></body></html>") }

过滤 URL

6.x

browser.setLoadHandler(new DefaultLoadHandler() {
    @Override
    public boolean onLoad(LoadParams params) {
        if (params.getURL().startsWith("mailto:")) {
            return true; // 取消加载
        }
        return false; // 继续加载
    }
});
browser.setLoadHandler(object: DefaultLoadHandler {
        override fun onLoad(params: LoadParams): Boolean {
            return if (params.getURL().startsWith("mailto:")) {
                true // 取消加载
            } else false // 继续加载
        }
})

7.0

navigation.set(StartNavigationCallback.class, params -> {
    if (params.url().startsWith("mailto:")) {
        return Response.ignore();
    }
    return Response.start();
});
navigation.set(StartNavigationCallback::class.java,
    StartNavigationCallback { params ->
        if (params.url().startsWith("mailto:")) Response.ignore() else Response.start()
    }
)

导航事件

开始加载

6.x

browser.addLoadListener(new LoadAdapter() {
    @Override
    public void onStartLoadingFrame(StartLoadingEvent event) {
        String url = event.getValidatedURL();
    }
});
browser.addLoadListener(object: LoadAdapter {
    override fun onStartLoadingFrame(event: StartLoadingEvent) {
        val url = event.validatedURL
    }
})

7.0

browser.navigation().on(NavigationStarted.class, event -> {
    String url = event.url();
});
browser.navigation().on(NavigationStarted::class.java) { event -> 
    val url = event.url()
}

加载完成

6.x

browser.addLoadListener(new LoadAdapter() {
    @Override
    public void onFinishLoadingFrame(FinishLoadingEvent event) {
        String html = browser.getHTML(event.getFrameId());
    }
});
browser.addLoadListener(object: LoadAdapter {
    override fun onFinishLoadingFrame(event: FinishLoadingEvent) {
        val html = browser.getHTML(event.frameId)
    }
})

7.0

browser.navigation().on(FrameLoadFinished.class, event -> {
    String html = event.frame().html();
});
browser.navigation().on(FrameLoadFinished::class.java) { event -> 
    val html = event.frame().html()
}

加载失败

6.x

browser.addLoadListener(new LoadAdapter() {
    @Override
    public void onFailLoadingFrame(FailLoadingEvent event) {
        NetError errorCode = event.getErrorCode();
    }
});
browser.addLoadListener(object: LoadAdapter {
    override fun onFailLoadingFrame(event: FailLoadingEvent) {
        val errorCode = event.errorCode
    }
})

7.0

browser.navigation().on(FrameLoadFailed.class, event -> {
    NetError error = event.error();
});
browser.navigation().on(FrameLoadFailed::class.java) { event -> 
    val error = event.error()
}

or

browser.navigation().on(NavigationFinished.class, event -> {
    NetError errorCode = event.error();
});
browser.navigation().on(NavigationFinished::class.java) { event -> 
    val errorCode = event.error()
}

网络

配置用户代理

6.x

BrowserPreferences.setUserAgent("My User-Agent");
BrowserPreferences.setUserAgent("My User-Agent")

7.0

Engine engine = Engine.newInstance(EngineOptions.newBuilder(...)
        .userAgent("My User-Agent")
        .build());
val engine = Engine.newInstance(EngineOptions.newBuilder(...)
        .userAgent("My User-Agent")
        .build())

配置接受语言

6.x

browserContext.setAcceptLanguage("fr, en-gb;q=0.8, en;q=0.7");
browserContext.setAcceptLanguage("fr, en-gb;q=0.8, en;q=0.7")

7.0

engine.network().acceptLanguage("fr, en-gb;q=0.8, en;q=0.7");
engine.network().acceptLanguage("fr, en-gb;q=0.8, en;q=0.7")

配置代理

6.x

ProxyService proxyService = browserContext.getProxyService();
proxyService.setProxyConfig(new CustomProxyConfig("http-proxy-server:80"));
val proxyService = browserContext.proxyService
proxyService.setProxyConfig(CustomProxyConfig("http-proxy-server:80"))

7.0

engine.proxy().config(CustomProxyConfig.newInstance("http-proxy-server:80"));
engine.proxy().config(CustomProxyConfig.newInstance("http-proxy-server:80"))

重定向 URL 请求

6.x

browserContext.getNetworkService().setNetworkDelegate(new NetworkDelegate() {
    @Override
    public void onBeforeURLRequest(BeforeURLRequestParams params) {
        params.setURL("https://www.google.com");
    }
});
browserContext.networkService.setNetworkDelegate(object: NetworkDelegate {
    override fun onBeforeURLRequest(params: BeforeURLRequestParams) {
        params.setURL("https://www.google.com")
    }
})

7.0

engine.network().set(BeforeUrlRequestCallback.class, (params) -> 
        Response.redirect("https://www.google.com"));
engine.network().set(BeforeUrlRequestCallback::class.java,
    BeforeUrlRequestCallback { params ->
        Response.redirect("https://www.google.com")
    }
)

覆盖 HTTP 标头

6.x

browserContext.getNetworkService().setNetworkDelegate(new NetworkDelegate() {
    ...
    @Override
    public void onBeforeSendHeaders(BeforeSendHeadersParams params) {
        HttpHeadersEx headers = params.getHeadersEx();
        headers.setHeader("User-Agent", "MyUserAgent");
        headers.setHeader("Content-Type", "text/html");
    }
});
browserContext.networkService.setNetworkDelegate(object: NetworkDelegate {
    override fun onBeforeSendHeaders(params: BeforeSendHeadersParams) {
        val headers = params.headersEx
        headers.setHeader("User-Agent", "MyUserAgent")
        headers.setHeader("Content-Type", "text/html")
    }
})

7.0

engine.network().set(BeforeSendHeadersCallback.class, (params) ->
        Response.override(Arrays.asList(
                HttpHeader.of("User-Agent", "MyUserAgent"),
                HttpHeader.of("Content-Type", "text/html"))));
engine.network().set(BeforeSendHeadersCallback::class.java,
    BeforeSendHeadersCallback { params ->
        Response.override(listOf(
                HttpHeader.of("User-Agent", "MyUserAgent"),
                HttpHeader.of("Content-Type", "text/html")))
    }
)

拦截 URL 请求

6.x

BrowserContext browserContext = browser.getContext();
ProtocolService protocolService = browserContext.getProtocolService();
protocolService.setProtocolHandler("https", new ProtocolHandler() {
    @Override
    public URLResponse onRequest(URLRequest request) {
        URLResponse response = new URLResponse();
        String html = "<html><body><p>你好呀!</p></body></html>";
        response.setData(html.getBytes());
        response.getHeaders().setHeader("Content-Type", "text/html");
        return response;
    }
});
val browserContext = browser.context
val protocolService = browserContext.protocolService
protocolService.setProtocolHandler("https", object: ProtocolHandler {
    override fun onRequest(request: URLRequest): URLResponse {
        val response = URLResponse()
        val html = "<html><body><p>你好呀!</p></body></html>"
        response.setData(html.toByteArray())
        response.headers.setHeader("Content-Type", "text/html")
        return response
    }
});

7.0

Network network = engine.network();
network.set(InterceptRequestCallback.class, params -> {
    UrlRequest urlRequest = params.urlRequest();
    if (urlRequest.url().startsWith("https")) {
        Options options = UrlRequestJob.Options
                .newBuilder(urlRequest.id(), HttpStatus.OK)
                .addHttpHeader(HttpHeader.of("Content-Type", "text/html"))
                .build();
        UrlRequestJob urlRequestJob = network.newUrlRequestJob(options);
        String html = "<html><body><p>你好呀!</p></body></html>";
        urlRequestJob.write(html.getBytes(UTF_8));
        urlRequestJob.complete();
        return Response.intercept(urlRequestJob);
    }
    return Response.proceed();
});
val network = engine.network()
network.set(InterceptRequestCallback::class.java, InterceptRequestCallback { params ->
    val urlRequest = params.urlRequest()
    if (urlRequest.url().startsWith("https")) {
        val options = UrlRequestJob.Options
            .newBuilder(urlRequest.id(), HttpStatus.OK)
            .addHttpHeader(HttpHeader.of("Content-Type", "text/html"))
            .build()
        val urlRequestJob = network.newUrlRequestJob(options)
        val html = "<html><body><p>你好呀!</p></body></html>"
        urlRequestJob.write(html.toByteArray(UTF_8))
        urlRequestJob.complete()
        Response.intercept(urlRequestJob)
    } else {
        Response.proceed()
    }
})

认证

代理认证、基本认证、摘要认证、NTLM 认证

6.x

NetworkService networkService = browserContext.getNetworkService();
networkService.setNetworkDelegate(new NetworkDelegate() {
    ...
    @Override
    public boolean onAuthRequired(AuthRequiredParams params) {
        if (params.isProxy()) {
            params.setUsername("用户");
            params.setPassword("密码");
            return false;
        }
        return true; // 取消认证请求
    }
});
val networkService = browser.networkService
networkService.setNetworkDelegate(object: NetworkDelegate {
    ...
    override fun onAuthRequired(params: AuthRequiredParams): Boolean {
        return if (params.isProxy()) {
            params.setUsername("用户")
            params.setPassword("密码")
            false
        } else true // 取消认证请求
    }
});

7.0

engine.network().set(AuthenticateCallback.class, (params, tell) -> {
    if (params.isProxy()) {
        tell.authenticate("用户", "密码");
    } else {
        tell.cancel();
    }
});
engine.network().set(AuthenticateCallback::class.java, 
    AuthenticateCallback { params, tell ->
        if (params.isProxy) {
            tell.authenticate("用户", "密码")
        } else {
            tell.cancel()
        }
    }
)

HTTPS 客户端证书

6.x

browser.setDialogHandler(new DialogHandler() {
    ...
    @Override
    public CloseStatus onSelectCertificate(CertificatesDialogParams params) {
        List<Certificate> certificates = params.getCertificates();
        if (certificates.isEmpty()) {
            return CloseStatus.CANCEL;
        } else {
            params.setSelectedCertificate(certificates.get(certificates.size() - 1));
            return CloseStatus.OK;
        }
    }
});
browser.setDialogHandler(object: DialogHandler {
    ...
    override fun onSelectCertificate(params: CertificatesDialogParams): CloseStatus {
        val certificates = params.certificates
        return if (certificates.isEmpty()) {
            CloseStatus.CANCEL
        } else {
            params.setSelectedCertificate(certificates[certificates.size - 1])
            CloseStatus.OK
        }
    }
});

7.0

browser.set(SelectClientCertificateCallback.class, (params, tell) -> {
    List<Certificate> certificates = params.certificates();
    if (certificates.isEmpty()) {
        tell.cancel();
    } else {
        tell.select(certificates.size() - 1);
    }
});
browser.set(SelectClientCertificateCallback::class.java,
    SelectClientCertificateCallback { params, tell ->
        val certificates = params.certificates()
        if (certificates.isEmpty()) {
            tell.cancel()
        } else {
            tell.select(certificates.size - 1)
        }
    }
)

插件

过滤插件

6.x

browser.getPluginManager().setPluginFilter(new PluginFilter() {
    @Override
    public boolean isPluginAllowed(PluginInfo pluginInfo) {
        return true;
    }
});
browser.pluginManager.setPluginFilter(object: PluginFilter {
    override fun isPluginAllowed(pluginInfo: PluginInfo): Boolean {
        return true
    }
})

7.0

engine.plugins().set(AllowPluginCallback.class, params -> Response.allow());
engine.plugins().set(AllowPluginCallback::class.java,
    AllowPluginCallback { Response.allow() })

DOM

访问文档

6.x

DOMDocument document = browser.getDocument();
if (document != null) {
    String baseURI = document.getBaseURI();
}
val document = browser.document
val baseURI = document?.baseURI

7.0

browser.mainFrame().ifPresent(frame ->
        frame.document().ifPresent(document -> {
            String baseUri = document.baseUri();
        }));
browser.mainFrame().ifPresent { frame ->
    frame.document().ifPresent { document ->
        val baseUri = document.baseUri()
    }
}

DOM 事件

处理事件

6.x

element.addEventListener(DOMEventType.OnClick, new DOMEventListener() {
    @Override
    public void handleEvent(DOMEvent event) {
        DOMEventTarget eventTarget = event.getTarget();
        if (eventTarget != null) {
            ...
        }
    }
}, false);
element.addEventListener(DOMEventType.OnClick, object: DOMEventListener {
    override fun handleEvent(event: DOMEvent) {
        val eventTarget = event.target
        if (eventTarget != null) {
            ...
        }
    }
})

7.0

element.addEventListener(EventType.CLICK, event ->
        event.target().ifPresent(eventTarget -> {
            ...
        }), false);
element.addEventListener(EventType.CLICK, { event ->
    event.target().ifPresent { eventTarget ->
        ...
    }
}, false)

CSS

注入 CSS

6.x

browser.setCustomStyleSheet("body { background-color: orange; }");
browser.setCustomStyleSheet("body { background-color: orange; }")

7.0

browser.set(InjectCssCallback.class, params -> 
        Response.inject("body { background-color: orange; }"));
browser.set(InjectCssCallback::class.java,
        InjectCssCallback { Response.inject("body { background-color: orange; }") })

JavaScript

从 Java 调用 JavaScript

6.x

String string = browser.executeJavaScriptAndReturnValue("'Hello'")
        .asString().getValue();
double number = browser.executeJavaScriptAndReturnValue("123")
        .asNumber().getValue();
boolean bool = browser.executeJavaScriptAndReturnValue("true")
        .asBoolean().getValue();
JSObject window = browser.executeJavaScriptAndReturnValue("window")
        .asObject();
val string = browser.executeJavaScriptAndReturnValue("'你好'")
        .asString().value
val number = browser.executeJavaScriptAndReturnValue("123")
        .asNumber().value
val bool = browser.executeJavaScriptAndReturnValue("true")
        .asBoolean().value
val window = browser.executeJavaScriptAndReturnValue("window")
        .asObject()

7.0

JSValue 类已被移除。现在类型转换是自动完成的。您可以选择同步执行 JavaScript 来阻塞当前线程,或者选择异步执行:

browser.mainFrame().ifPresent(frame -> {
    String string = frame.executeJavaScript("'你好'");
    Double number = frame.executeJavaScript("123");
    Boolean bool = frame.executeJavaScript("true");
    JsObject window = frame.executeJavaScript("window");

    frame.executeJavaScript("document", (Consumer<Document>) document -> {
        String baseUri = document.baseUri();
    });
});
browser.mainFrame().ifPresent { frame: Frame ->
    val string = frame.executeJavaScript<String>("'你好'")
    val number = frame.executeJavaScript<Double>("123")
    val bool = frame.executeJavaScript<Boolean>("true")
    val window = frame.executeJavaScript<JsObject>("window")
    
    frame.executeJavaScript("document", Consumer<Document> { document ->
        val baseUri = document.baseUri()
    })
}

从 JavaScript 调用 Java

6.x

在 Java 代码中:

public class JavaObject {
    public void foo(String text) {}
}

JSValue window = browser.executeJavaScriptAndReturnValue("window");
if (window.isObject()) {
    window.asObject().setProperty("java", new JavaObject());
}
class JavaObject {
    fun foo(text String) {}
}

val window = browser.executeJavaScriptAndReturnValue("window")
if (window.isObject()) {
    window.asObject().setProperty("java", JavaObject())
}

In JavaScript code:

window.java.foo("你好");

7.0

出于安全考虑,只有使用 @JsAccessible 注解标记的公共方法可以从 JavaScript 中访问。

在 Java 代码中:

public class JavaObject {
    @JsAccessible
    public void foo(String text) {}
}

JsObject window = frame.executeJavaScript("window");
window.putProperty("java", new JavaObject());
class JavaObject {
    @JsAccessible
    fun foo(text: String) {}
}

val window = frame.executeJavaScript<JsObject>("window")
window?.putProperty("java", JavaObject())

In JavaScript code:

window.java.foo("你好");

注入 JavaScript

6.x

browser.addScriptContextListener(new ScriptContextAdapter() {
    @Override
    public void onScriptContextCreated(ScriptContextEvent event) {
        JSValue window = browser.executeJavaScriptAndReturnValue(
                event.getJSContext().getFrameId(), "window");
    }
});
browser.addScriptContextListener(object: ScriptContextAdapter {
    override fun onScriptContextCreated(event: ScriptContextEvent) {
        val window = browser.executeJavaScriptAndReturnValue(
                event.jsContext.frameId, "window")
    }
})

7.0

browser.set(InjectJsCallback.class, params -> {
    JsObject window = params.frame().executeJavaScript("window");
    return Response.proceed();
});
browser.set(InjectJsCallback::class.java, InjectJsCallback { params ->
    val window = params.frame().executeJavaScript<JsObject>("window")
    Response.proceed()
})

控制台事件

6.x

browser.addConsoleListener(new ConsoleListener() {
    @Override
    public void onMessage(ConsoleEvent event) {
        String message = event.getMessage();
    }
});
browser.addConsoleListener(object: ConsoleListener {
    override fun onMessage(event: ConsoleEvent) {
        val message = event.message
    }
})

7.0

browser.on(ConsoleMessageReceived.class, event -> {
    String message = event.consoleMessage().message();
});
browser.on(ConsoleMessageReceived::class.java) { event ->
    val message = event.consoleMessage().message()
}

弹出窗口

抑制弹出窗口

6.x

browser.setPopupHandler(new PopupHandler() {
    @Override
    public PopupContainer handlePopup(PopupParams params) {
        return null;
    }
});
browser.setPopupHandler(object: PopupHandler {
    override fun handlePopup(params: PopupParams): PopupContainer? {
        return null
    }
})

7.0

browser.set(CreatePopupCallback.class, (params) -> Response.suppress());
browser.set(CreatePopupCallback::class.java, CreatePopupCallback { Response.suppress() })

打开弹出窗口

6.x

browser.setPopupHandler(new PopupHandler() {
    @Override
    public PopupContainer handlePopup(PopupParams params) {
        return new PopupContainer() {
            @Override
            public void insertBrowser(Browser popupBrowser, Rectangle initialBounds) {}
        };
    }
});
browser.setPopupHandler(object: PopupHandler {
    override fun handlePopup(params: PopupParams): PopupContainer {
        return object: PopupContainer {
            override fun insertBrowser(popupBrowser: Browser, initialBounds: Rectangle) {}
        }
    }
})

7.0

browser.set(CreatePopupCallback.class, (params) -> Response.create());
browser.set(OpenPopupCallback.class, (params) -> {
    Browser popup = params.popupBrowser();
    return OpenPopupCallback.Response.proceed();
});
browser.set(CreatePopupCallback::class.java, CreatePopupCallback { Response.create() })
browser.set(OpenPopupCallback::class.java, OpenPopupCallback { params -> 
    val popup = params.popupBrowser()
    OpenPopupCallback.Response.proceed()
})

对话框

JavaScript 对话框

6.x

browser.setDialogHandler(new DialogHandler() {
    @Override
    public void onAlert(DialogParams params) {
    }

    @Override
    public CloseStatus onConfirmation(DialogParams params) {
        return CloseStatus.CANCEL;
    }

    @Override
    public CloseStatus onPrompt(PromptDialogParams params) {
        params.setPromptText("Text");
        return CloseStatus.OK;
    }
    ...
});
browser.setDialogHandler(object: DialogHandler {
    override fun onAlert(params: DialogParams) {}
    override fun onConfirmation(params: DialogParams): CloseStatus =
        CloseStatus.CANCEL
    override fun onPrompt(params: PromptDialogParams): CloseStatus {
        params.setPromptText("Text")
        return CloseStatus.OK
    }  
})

7.0

browser.set(AlertCallback.class, (params, tell) -> tell.ok());
browser.set(ConfirmCallback.class, (params, tell) -> tell.cancel());
browser.set(PromptCallback.class, (params, tell) -> tell.ok("Text"));
browser.set(AlertCallback::class.java, AlertCallback { params, tell -> tell.ok() })
browser.set(ConfirmCallback::class.java, ConfirmCallback { params, tell -> tell.cancel() })
browser.set(PromptCallback::class.java, PromptCallback { params, tell -> tell.ok("Text") })

文件对话框

6.x

browser.setDialogHandler(new DialogHandler() {
    @Override
    public CloseStatus onFileChooser(FileChooserParams params) {
        FileChooserMode mode = params.getMode();
        if (mode == FileChooserMode.Open) {
            params.setSelectedFiles(new File(params.getDefaultFileName()));
        }
        if (mode == FileChooserMode.OpenMultiple) {
            params.setSelectedFiles(new File("file1.txt"), new File("file2.txt"));
        }
        return CloseStatus.OK;
    }
    ...
});
browser.setDialogHandler(object: DialogHandler {
    override fun onFileChooser(params: FileChooserParams): CloseStatus {
        val mode = params.mode
        if (mode == FileChooserMode.Open) {
            params.setSelectedFiles(File(params.defaultFileName))
        }
        if (mode == FileChooserMode.OpenMultiple) {
            params.setSelectedFiles(File("file1.txt"), File("file2.txt"))
        }
        return CloseStatus.OK
    }
})

7.0

browser.set(OpenFileCallback.class, (params, tell) ->
        tell.open(Paths.get(params.defaultFileName())));
browser.set(OpenFilesCallback.class, (params, callback) ->
        callback.open(Paths.get("file1.txt"), Paths.get("file2.txt")));
browser.set(OpenFileCallback::class.java, 
    OpenFileCallback { params, tell -> 
        tell.open(Path(params.defaultFileName()))
    }
)
browser.set(OpenFilesCallback::class.java, 
    OpenFilesCallback { _, callback -> 
        callback.open(Path("file1.txt"), Path("file2.txt"))
    }
)

颜色对话框

6.x

browser.setDialogHandler(new DialogHandler() {
    @Override
    public CloseStatus onColorChooser(ColorChooserParams params) {
        params.setColor(params.getColor());
        return CloseStatus.OK;
    }
    ...
});
browser.setDialogHandler(object: DialogHandler {
    override fun onColorChooser(params: ColorChooserParams): CloseStatus {
        params.setColor(params.сolor)
        return CloseStatus.OK
    }
})

7.0

browser.set(SelectColorCallback.class, (params, tell) ->
        tell.select(params.defaultColor()));
browser.set(SelectColorCallback::class.java, 
    SelectColorCallback { params, tell -> 
        tell.select(params.defaultColor())
    }
)

SSL 证书对话框

6.x

browser.setDialogHandler(new DialogHandler() {
    @Override
    public CloseStatus onSelectCertificate(CertificatesDialogParams params) {
        X509Certificate x509Certificate = ...;
        PrivateKey privateKey = ...;
        params.setSelectedCertificate(new Certificate(x509Certificate, privateKey));
        return CloseStatus.OK;
    }
    ...
});
browser.setDialogHandler(object: DialogHandler {
    override fun onSelectCertificate(params: CertificatesDialogParams): CloseStatus {
        val x509Certificate: X509Certificate = ...
        val privateKey: PrivateKey = ...
        params.setSelectedCertificate(Certificate(x509Certificate, privateKey))
        return CloseStatus.OK
    }
    ...
})

7.0

private static final Path CLIENT_CERT_FILE = Paths.get("<cert-file>.p12");
private static final String CLIENT_CERT_PASSWORD = "<cert-password>";
...
browser.set(SelectClientCertificateCallback.class, (params, tell) ->
        tell.select(ClientCertificate.of(CLIENT_CERT_FILE,
                CLIENT_CERT_PASSWORD, KeyStoreType.PKCS12)));
private val certFile = Path("<cert-file>.p12")
private val certPassword = "<cert-password>"
...
browser.set(SelectClientCertificateCallback::class.java, 
    SelectClientCertificateCallback { params, tell -> 
        tell.select(ClientCertificate.of(certFile,
                certPassword, KeyStoreType.PKCS12))
    }
)

上下文菜单

处理上下文菜单

6.x

browser.setContextMenuHandler(new ContextMenuHandler() {
    @Override
    public void showContextMenu(ContextMenuParams params) {
    }
});
browser.setContextMenuHandler(object: ContextMenuHandler {
    override fun showContextMenu(params: ContextMenuParams) {
    }
})

7.0

browser.set(ShowContextMenuCallback.class, (params, tell) -> {
    tell.close();
});
browser.set(ShowContextMenuCallback::class.java,
    ShowContextMenuCallback { params, tell -> tell.close() }
)

了解更多关于上下文菜单的处理方法。

打印

配置打印

6.x

browser.setPrintHandler(new PrintHandler() {
    @Override
    public PrintStatus onPrint(PrintJob printJob) {
        PrintSettings printSettings = printJob.getPrintSettings();
        printSettings.setPrinterName("Microsoft XPS Document Writer");
        printSettings.setLandscape(true);
        printSettings.setPrintBackgrounds(true);
        ...
        return PrintStatus.CONTINUE;
    }
});
browser.setPrintHandler(object: PrintHandler {
    override fun onPrint(printJob: PrintJob): PrintStatus {
        val printSettings = printJob.printSettings
        printSettings.setPrinterName("Microsoft XPS Document Writer")
        printSettings.setLandscape(true)
        printSettings.setPrintBackgrounds(true)
        ...
        return PrintStatus.CONTINUE
    }
})

7.0

原本用于配置打印的功能已被移除,取而代之的是标准的打印预览对话框,您可以在其中设置所需的参数。

browser.set(PrintCallback.class, (params, tell) -> tell.showPrintPreview());
browser.set(PrintCallback::class.java,
    PrintCallback { params, tell -> tell.showPrintPreview() }
)

抑制打印

6.x

browser.setPrintHandler(new PrintHandler() {
    @Override
    public PrintStatus onPrint(PrintJob printJob) {
        return PrintStatus.CANCEL;
    }
});
browser.setPrintHandler(object: PrintHandler {
    override fun onPrint(printJob: PrintJob): PrintStatus = 
        PrintStatus.CANCEL
})

7.0

browser.set(PrintCallback.class, (params, tell) -> tell.cancel());
browser.set(PrintCallback::class.java,
    PrintCallback { params, tell -> tell.cancel() }
)

缓存

清除 HTTP 缓存

6.x

browser.getCacheStorage().clearCache(new Callback() {
    @Override
    public void invoke() {
        // HTTP 磁盘缓存已清除。
    }
});
browser.cacheStorage.clearCache(object: Callback {
    override fun invoke() { 
        // HTTP 磁盘缓存已清除。
    }
})

7.0

engine.httpCache().clearDiskCache(() -> {
    // HTTP 磁盘缓存已清除。
});
engine.httpCache().clearDiskCache {
    // HTTP 磁盘缓存已清除。
}

Cookies

访问 cookies

6.x

List<Cookie> cookies = browser.getCookieStorage().getAllCookies();
val cookies = browser.cookieStorage.allCookies

7.0

List<Cookie> cookies = engine.cookieStore().cookies();
val cookies = engine.cookieStore().cookies()

渲染进程

启动/终止

6.x

browser.addRenderListener(new RenderAdapter() {
    @Override
    public void onRenderCreated(RenderEvent event) {}

    @Override
    public void onRenderGone(RenderEvent event) {
        TerminationStatus status = event.getTerminationStatus();
    }
});
browser.addRenderListener(object: RenderAdapter {
    override fun onRenderCreated(event: RenderEvent) {}
    override fun onRenderGone(event: RenderEvent) {
        val status: TerminationStatus = event.terminationStatus
    }
})

7.0

browser.on(RenderProcessStarted.class, event -> {});
browser.on(RenderProcessTerminated.class, event -> {
    TerminationStatus status = event.status();
});
browser.on(RenderProcessStarted::class.java) { event -> }
browser.on(RenderProcessTerminated::class.java) { event -> 
    val status = event.status()
}

Chromium

Switches(开关)

该库并不支持所有可能的 Chromium 开关。它允许使用开关来配置 Chromium,但我们不能保证传递的开关能够正确工作或者能够工作。因此,我们建议在使用前检查此功能。

6.x

BrowserPreferences.setChromiumSwitches(
        "--<switch_name>",
        "--<switch_name>=<switch_value>"
);
BrowserPreferences.setChromiumSwitches(
        "--<switch_name>",
        "--<switch_name>=<switch_value>"
)

7.0

Engine engine = Engine.newInstance(EngineOptions.newBuilder(...)
        .addSwitch("--<switch_name>")
        .addSwitch("--<switch_name>=<switch_value>")
        .build());
val engine = Engine.newInstance(EngineOptions.newBuilder(...)
        .addSwitch("--<switch_name>")
        .addSwitch("--<switch_name>=<switch_value>")
        .build())

API 密钥

6.x

BrowserPreferences.setChromiumVariable(
        "GOOGLE_API_KEY", "我的 API 密钥");
BrowserPreferences.setChromiumVariable(
        "GOOGLE_DEFAULT_CLIENT_ID", "我的客户端 ID");
BrowserPreferences.setChromiumVariable(
        "GOOGLE_DEFAULT_CLIENT_SECRET", "我的客户端密钥");
BrowserPreferences.setChromiumVariable(
        "GOOGLE_API_KEY", "我的 API 密钥")
BrowserPreferences.setChromiumVariable(
        "GOOGLE_DEFAULT_CLIENT_ID", "我的客户端 ID")
BrowserPreferences.setChromiumVariable(
        "GOOGLE_DEFAULT_CLIENT_SECRET", "我的客户端密钥")

7.0

Engine engine = Engine.newInstance(EngineOptions.newBuilder(...)
        .googleApiKey("我的 API 密钥")
        .googleDefaultClientId("我的客户端 ID")
        .googleDefaultClientSecret("我的客户端密钥")
        .build());
val engine = Engine.newInstance(EngineOptions.newBuilder(...)
        .googleApiKey("我的 API 密钥")
        .googleDefaultClientId("我的客户端 ID")
        .googleDefaultClientSecret("我的客户端密钥")
        .build())

日志记录

在新版本中,日志记录 API 已经简化。请查阅故障排除指南,了解更多关于如何配置日志记录的信息。

Go top