List icon 目录

常见问题

本指南将介绍如何解决一些常见问题。

Windows 上的启动失败

如果 JxBrowser 在 Windows 上无法启动,请确保环境满足系统要求并且没有杀毒软件干扰。

JxBrowser 在单独的本机进程中运行 Chromium。有时杀毒软件或本地安全策略不允许本机进程启动。即使 JxBrowser 可执行文件使用有效且受信任的签名进行签名,杀毒软件仍可能不允许运行不在其白名单中的程序。

如果上述操作没有帮助,请启用日志记录,重现问题,并向我们提供收集的日志消息。

Linux 上的启动失败

如果 JxBrowser 在 Linux 上无法启动,请确保环境满足系统要求并具有必要的系统库。

在一些 Linux 发行版中,由于缺少系统库,Chromium 进程可能无法启动。当发生这种情况时,库会将详细信息写入日志。

启用日志记录并检查日志消息是否包含如下错误:

java.lang.UnsatisfiedLinkError: /tmp/JxBrowser/VERSION/libbrowsercore_toolkit.so:
    libgobject-2.0.so.0: cannot open shared object file: No such file or directory

要解决此问题,请安装缺少的库。

如果没有帮助,请启用日志记录,重现问题,并向我们提供收集的日志消息以及您的 Linux 发行版的名称和版本。

启动缓慢

启动时间取决于环境、硬件性能和安装的杀毒软件。

JxBrowser 启动过程包括几个步骤。首先,它提取存储在 JAR 文件中的 Chromium 二进制文件。然后启动主 Chromium 进程,并建立 Java 和 Chromium 进程之间的连接。

通常情况下,Chromium 二进制文件的提取只会在环境中发生一次。此步骤可能会明显减慢启动速度。例如,在 i7/16GB RAM/512GB SSD 机器上大概额外需要 3 秒。点击此处了解如何跳过此步骤。

杀毒软件可能会在允许 JxBrowser 启动库二进制文件之前检查它们。这会对启动时间产生负面影响。请尝试禁用杀毒软件,看看是否有所帮助。

如果没有帮助,请启用日志记录,重现问题,并向我们提供收集的日志消息和有关您硬件的详细信息。

Chromium 进程崩溃

JxBrowser 在单独的本机进程中运行 Chromium。此进程中的错误可能会导致进程意外终止。发生这种情况时,库会生成一个或多个崩溃转储文件。这些文件对于了解崩溃原因至关重要。

如果 Chromium 进程意外终止,并且您收到 EngineCrashed 事件,请报告该问题并附上生成的崩溃转储文件。

在 Java 应用程序中冻结

如果您的 Java 应用程序挂起,并且您认为它是由于 JxBrowser 而导致的,请按照以下步骤操作:

  1. 启用日志记录
  2. 重现问题。
  3. 当应用程序被冻结时,进行线程转储
  4. 报告问题并附上收集的线程转储和日志消息。

视频无法播放

JxBrowser 可能不支持您尝试播放的视频格式。请查看支持的视频和音频格式的列表

如果其中一种支持的视频格式无法播放,请报告问题。

JMenu 重叠

硬件加速渲染模式下,BrowserView 将覆盖菜单栏:

JMenuBar Overlapping Issue

出现此问题的原因在于混合了轻量级的弹出菜单和重量级的 BrowserView。要解决此问题,请禁用 Swing 弹出窗口的轻量级模式:

Java
Kotlin
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
JPopupMenu.setDefaultLightWeightPopupEnabled(false)

此代码强制所有 Swing 弹出菜单变为重量级。

在 Java 9+ 中使用 JxBrowser

在某些情况下,JxBrowser 需要访问非公共 API。在 Java 9+ 中,您必须显式授予对 JxBrowser 的访问权限。在本节中,我们列出了此类案例。

嵌入到 Swing 中

在 Windows 和 Linux 上的 HARWARE_ACCELERATED 渲染模式下,该库使用内部 JDK API 正确遍历 Java 和 Chromium 窗口之间的输入焦点。

如果您的应用程序是 non-modular 的,需要将所需的程序包导出到未命名的模块:

--add-exports java.desktop/sun.awt=ALL-UNNAMED

如果应用程序是 modular 的,则需要将所需的包导出到 JxBrowser 模块:

--add-exports java.desktop/sun.awt=jxbrowser.swing

嵌入到 JFXPanel

如果将 BrowserView 嵌入到 JFXPanel 内部的 JavaFX 中,该库将需要访问 JavaFX 的内部 API 以获取应用程序窗口的本机句柄。

如果您的应用程序是 non-modular 的,需要将所需的包导出到未命名的模块:

--add-opens javafx.swing/javafx.embed.swing=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.javafx.stage=ALL-UNNAMED
--add-exports javafx.graphics/com.sun.javafx.stage=ALL-UNNAMED
--add-exports javafx.controls/com.sun.javafx.scene.control=ALL-UNNAMED

如果应用程序是 modular 的,则需要将所需的包导出到 JxBrowser 模块:

--add-opens javafx.swing/javafx.embed.swing=jxbrowser
--add-opens javafx.graphics/com.sun.javafx.stage=jxbrowser
--add-exports javafx.graphics/com.sun.javafx.stage=jxbrowser
--add-exports javafx.controls/com.sun.javafx.scene.control=jxbrowser

无法登录 Google 账户

尝试登录 Google 账户可能会出现以下消息:

Google Account Sign In Error

出现此问题的原因可能是远程调试端口。配置端口后,Chromium 会阻止任何尝试登录其服务(例如 Gmail、YouTube)的行为。

Docker 内存不足

默认情况下,Docker 运行的容器 /dev/shm 共享内存空间为 64MB。这对于 Chromium 来说太少了,在渲染页面时会导致崩溃。

从 7.10 版本开始,JxBrowser 使用 /dev/shm 在离屏渲染模式下存储位图。它为每个网页分配额外的 ~10MB (1080p) 或 ~40MB (4k) 来存储位图。

要解决此问题,请使用 docker run --shm-size=1gb 命令运行 Docker 容器以增加 /dev/shm 的大小。

为新密钥环选择密码

在 Linux 上,Chromium 可能会创建一个新的密钥环,操作系统将显示此对话框:

Choose password for new keyring

为防止这种情况发生,请将 Chromium 配置为使用 BASIC 密码存储而不是系统密码存储:

Java
Kotlin
var engine = Engine.newInstance(
        EngineOptions.newBuilder(renderingMode)
                     .passwordStore(PasswordStore.BASIC)
                     .build());
val engine = Engine.newInstance(
        EngineOptions.newBuilder(renderingMode)
                     .passwordStore(PasswordStore.BASIC)
                     .build())

ObjectClosedException

API 库中的服务对象可能已关闭。尝试调用已关闭的对象会导致 ObjectClosedException 异常。

在本指南中,我们将解释服务对象可能被关闭的常见场景以及您可以采取的措施。

已关闭的 Engine

JxBrowser 中最顶层的对象是 Engine。它可能在以下两种情况下被关闭:

  • 调用了 Engine::close() 方法;
  • Main Chromium 进程发生错误。

如果您关闭 Engine,所有与之关联的对象(例如 Profiles、Browsers、Frames 等)都将自动关闭。因此,在关闭 Engine 后,无论出于何种原因,请确保不要使用与已关闭的 Engine 相关联的任何对象。

如果主 Chromium 进程发生错误,该进程将终止并关闭 Engine。当它发生时,库会生成崩溃转储文件并将它们存储在特定目录中。使用 EngineCrashed 事件在它发生时得到通知。

在这种情况下,请报告问题并附上崩溃转储文件

已删除的 Profile

可以通过调用 Profiles::delete() 方法删除 Profile。

如果您删除 Profile,所有与其关联的对象(例如 cookie 存储、浏览器、框架、DOM/JS 对象等)都会自动关闭。因此,在删除 Profile 后,请确保不要使用与已删除 Profile 相关联的任何对象。

已关闭的 Browser

有两种情况会导致 Browser 被关闭:

  • 调用了 Browser::close() 方法;
  • JavaScript 关闭了窗口。

如果关闭 Browser,所有与之关联的对象(例如导航、文本查找器、Frames、DOM/JS 等)都将自动关闭。因此,在 Browser 关闭后,请确保不要使用与已关闭 Browser 相关联的任何对象。

JavaScript 中的 window.close() 方法只能关闭由另一个脚本打开的 Browser。如果您预料到会发生这种情况,请考虑在使用前检查 Browser 状态。

请注意,当 JavaScript 关闭 Browser 时,Java 会稍微延迟发现它。如果 Browser 已经关闭,但 Java 尚未被通知,那么尝试使用关闭的 Browser 将导致 ObjectClosedException

已卸载的网页

每个加载的网页都有一个 main frame 和 child frames。当导航到一个网页时,Browser 会卸载之前加载的页面并删除其中的所有 Frame 和 DOM/JS 对象。

确保在网页卸载后不要使用 DOM 和 JavaScript 对象。使用导航事件来获得通知。

请注意,Java 接收导航事件时有轻微延迟。如果页面已经卸载,但 Java 尚未被通知,那么尝试使用已删除/关闭的对象将导致 ObjectClosedException

已终止的渲染进程

在 Chromium 中,Frames 驻留在渲染进程中。当渲染过程终止时,Frames 将被删除。当 Frame 被删除时,该网页、其 DOM 和 JavaScript 对象也会被删除并关闭。

使用 RenderProcessTerminated 事件在进程终止时获得通知。如果进程意外终止,请报告问题并附上生成的崩溃转储文件

如果它正常终止,则不需要任何操作。

Swing BrowserView 中的 InaccessibleObjectException

当 Swing BrowserView 获得焦点时,您可能会在控制台输出中看到以下异常:

Exception in thread "AWT-EventQueue-0" java.lang.reflect.InaccessibleObjectException: Unable to make static synchronized void java.awt.KeyboardFocusManager.setMostRecentFocusOwner(java.awt.Window,java.awt.Component) accessible: module java.desktop does not "opens java.awt" to unnamed module 
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
        at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
        at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)

这是因为 JxBrowser 使用了 java.awt 包中的私有 API,而 Java 17 及更高版本不允许从一个模块访问另一个模块的内部。为避免此异常,您应在 JVM 参数中使用 --add-opens 开关及对应的包:

--add-opens=java.desktop/java.awt=ALL-UNNAMED