IntelliJ 平台插件 SDK Help

嵌入式浏览器 (JCEF)

JCEF(Java Chromium Embedded Framework)是 CEF 的 Java 版本。 它允许在 Swing 应用程序中嵌入 基于 Chromium 的浏览器

在 IDE 内嵌入浏览器组件可以用于:

  • 渲染 HTML 内容

  • 预览生成的 HTML(例如,来自 Markdown)

  • 创建自定义基于 Web 的组件(例如,图表预览、图片浏览器等)

建议使用默认的 IntelliJ 平台 UI 框架(Swing)来实现 UI。
只有在插件需要显示 HTML 文档,或者标准的 UI 创建方式无法满足需求时,才考虑使用 JCEF 方法。

JCEF 替代了过去在 IDE 中用来渲染 web 内容的 JavaFX。

启用 JCEF

自 2020.2 起,JCEF 可用并默认启用。 无需额外操作。

使用 JCEF 需要使用专用的 JetBrains Runtime 并在 IDE 注册表中启用 JCEF。

  1. 访问 JetBrains Runtime 发布列表

  2. 下载适合你操作系统的“启动 IntelliJ IDEA 的二进制文件”,例如,macOS 的 <path>jbr_jcef-17.0.9-osx-x64-b1087.7.tar.gz</path>

  3. 解压缩归档文件。

  4. 按照 IDEA Web 帮助 中描述的步骤操作,并选择下载的 JBR。

  5. 调用 Help | Find Action... ,输入“Registry”,按回车打开 Registry 对话框。

  6. 启用 ide.browser.jcef.enabled 标志。

  7. 重启 IDE 以使更改生效。

    在插件中使用 JCEF

    IntelliJ Platform API 暴露的核心 JCEF 类是 JBCefApp。 它负责初始化 JCEF 上下文并管理其生命周期。

    无需显式初始化 JBCefApp。 在调用 JBCefApp.getInstance() 时或创建浏览器客户端对象时,它会自动初始化。

    在使用 JCEF API 之前,需要检查当前运行的 IDE 是否支持 JCEF。 可以通过调用 JBCefApp.isSupported() 来完成此操作:

    if (JBCefApp.isSupported()) { // 使用 JCEF } else { // 可选的备用无浏览器解决方案 }

    JCEF 可能不受支持的情况包括:

    • IDE 使用了不包含 JCEF 的备用 JDK 启动。

    • 其版本与当前运行的 IDE 不兼容。

    浏览器

    JCEF 浏览器由 JBCefBrowser 类表示。
    它负责在实际的基于 Chromium 的浏览器中加载和渲染请求的文档。

    JCEF 浏览器可以通过 JBCefBrowser 类的构造函数创建,也可以通过 JBCefBrowserBuilder 创建。
    当默认的客户端和默认选项足够时,可以使用构造函数。
    构建器方法允许使用自定义客户端并配置其他选项。

    将浏览器添加到 UI

    JBCefBrowser.getComponent() 提供了嵌入实际浏览器的 UI 组件。 这个组件是 Swing JComponent 的实例,可以添加到插件 UI 中:

    // 假设 'JPanel myPanel' 是工具窗口 UI 的一部分 JBCefBrowser browser = new JBCefBrowser(); myPanel.add(browser.getComponent());

    加载文档

    要在浏览器中加载文档,使用 JBCefBrowserBase.load*() 方法之一。 加载文档的方法可以从 EDT 和后台线程调用。 可以设置一个初始 URL(传递给构造函数或构建器),在浏览器创建和初始化时加载。

    要在浏览器中加载文档,请使用 JBCefBrowserBase.load*() 方法之一。
    加载文档的方法可以从 EDT 和后台线程 调用。
    可以设置一个初始 URL(传递给构造函数或构建器),该 URL 将在浏览器创建和初始化时加载。

    浏览器客户端

    浏览器客户端提供了设置与各种浏览器事件相关的处理程序的接口,例如:

    • 加载 HTML 文档

    • 控制台消息打印

    • 浏览器获得焦点

    浏览器客户端提供了一个接口,用于设置与各种浏览器事件相关的处理器 ,例如:

    • HTML 文档加载完成

    • 控制台消息打印

    • 浏览器获得焦点

    处理器允许在插件代码中对这些事件做出反应并更改浏览器的行为。
    每个浏览器都与一个客户端绑定,一个客户端可以与多个浏览器实例共享。

    浏览器客户端由 JBCefClient 表示,它是 JCEF 的 CefClient 的封装。
    JBCefClient 允许注册多个相同类型的处理器,而 CefClient 则不支持。
    要访问底层的 CefClient 及其 API,请调用 JBCefClient.getCefClient()

    创建和访问客户端

    如果没有传递特定的客户端, JBCefBrowser 实例将绑定到默认客户端,该客户端会隐式创建。 隐式客户端在关联的浏览器实例被处置时会自动释放

    对于更高级的用例,通过调用 JBCefApp.createClient() 创建自定义客户端,并注册所需的处理程序。 自定义客户端必须在插件代码中显式处置。

    要访问与浏览器关联的客户端,调用 JBCefBrowser.getJBCefClient()

    JBCefClient client = JBCefApp.createClient(); JBCefBrowser browser = new JBCefBrowser(client); JBCefClient associatedClient = browser.getJBCefClient();

    事件处理程序

    JCEF API 提供了多种事件处理器接口,可以处理浏览器发出的各种事件。
    示例处理器:

    • CefLoadHandler - 处理浏览器加载事件。

      示例: 实现 CefLoadHandler.onLoadEnd() 在文档加载后 执行脚本

    • CefDisplayHandler - 处理与浏览器显示状态相关的事件。

      示例: 实现 CefDisplayHandler.onAddressChange() 在点击本地文件链接时加载项目文件,或者在点击外部链接时打开外部浏览器。

    • CefDisplayHandler - 处理与浏览器显示状态相关的事件。
      示例: 实现 CefDisplayHandler.onAddressChange() 在点击本地文件链接时在浏览器中加载项目文件,或点击外部链接时打开外部浏览器。

    • CefContextMenuHandler - 处理上下文菜单事件。
      示例: 实现 CefContextMenuHandler.onBeforeContextMenu() 来更改浏览器上下文菜单的项目。

    查看 org.cef.handler 包以了解所有可用的处理器。

    请参阅 org.cef.handler 包中的所有可用处理程序。

    处理程序应使用 JBCefClient.getCefClient().add*Handler() 方法进行注册。

    执行 JavaScript

    JCEF API 允许从插件代码在嵌入式浏览器中执行 JavaScript 代码。 JavaScript 可用于操作 DOM、创建在实现功能中需要的函数、注入样式等。

    在最简单的情况下,可以使用 JBCefBrowser.getCefBrowser().executeJavaScript() 执行 JavaScript 代码,例如:

    browser.getCefBrowser().executeJavaScript( "alert('Hello World!')", url, lineNumber );

    上面的代码片段将在嵌入式浏览器中执行,并显示一个包含“Hello World!”消息的警告框。
    urllineNumber 参数用于在脚本抛出错误时生成浏览器中的错误报告。
    它们的目的是帮助调试错误,并不对脚本的执行至关重要。
    通常可以将 browser.getCefBrowser().getUrl() 或 null/空字符串,以及 0 作为这些参数传递。

    从 JavaScript 执行插件代码

    JCEF 不直接提供对 DOM 的访问权限(未来可能会 变化 ),与 JavaScript 的异步通信通过回调机制实现。
    它允许通过 JavaScript 从嵌入式浏览器执行插件代码,例如,当点击按钮或链接、按下快捷键、调用 JavaScript 函数等情况时。

    JavaScript 查询回调由 JBCefJSQuery 表示。 它是一个绑定到特定浏览器的对象,持有一组实现所需插件行为的处理器。

    考虑一个需要在编辑器中打开本地文件链接,并在外部浏览器中打开外部链接的场景。
    可以通过以下方式实现该需求(每个步骤在代码片段下方进行解释):

    JBCefJSQuery openLinkQuery = JBCefJSQuery.create(browser); // 1 openLinkQuery.addHandler((link) -> { // 2 if (LinkUtil.isExternal(link)) { BrowserUtil.browse(link); } else { EditorUtil.openFileInEditor(link); } return null; // 3 }); browser.getCefBrowser().executeJavaScript( // 4 "window.openLink = function(link) {" + openLinkQuery.inject("link") + // 5 "};", browser.getCefBrowser().getURL(), 0 ); browser.getCefBrowser().executeJavaScript( // 6 """ document.addEventListener('click', function (e) { const link = e.target.closest('a').href; if (link) { window.openLink(link); } });""", browser.getCefBrowser().getURL(), 0 );
    1. 创建一个 JBCefQuery 实例。确保传入的浏览器实例是 JBCefBrowserBase 类型(可能需要进行类型转换)。

    2. 添加一个处理器,执行插件代码。
      示例实现根据链接是本地还是外部来决定是在编辑器中打开链接还是在外部浏览器中打开。

    3. 处理器可以选择性地返回一个 JBCefJSQuery.Response 对象,该对象包含插件代码执行时发生的成功或错误信息。
      如果需要,可以在浏览器中处理该响应。

    4. 执行 JavaScript,创建一个自定义的 openLink 函数。

    5. 注入负责调用在步骤 2 中实现的插件代码的 JavaScript 代码。
      添加到 openLinkQuery 的处理器将在每次调用 openLink 函数时被触发。

      请注意 JBCefJSQuery.inject() 方法的 "link" 参数。
      它是 openLink 函数的 link 参数的名称。
      该值会被注入到查询函数调用中,可以是处理器需要的任何值,例如 "myJsObject.prop""'JavaScript string'" 等。

    6. 执行 JavaScript,在浏览器中注册点击事件监听器。
      每当浏览器中的 a 元素被点击时,监听器将调用步骤 4 中定义的 openLink 函数,并传递被点击链接的 href 值。

    从插件分发中加载资源

    在插件功能实现基于 Web 的 UI 的情况下,插件可能会在其 分发包 中提供 HTML、CSS 和 JavaScript 文件,或者根据某些配置动态生成它们。
    浏览器无法轻易访问这些资源。
    通过实现适当的请求 处理器 ,可以使这些资源在预定义的 URL 上对浏览器可用。

    可以通过实现适当的请求处理器来使这些资源可访问,使其在预定义的 URL 上对浏览器可用。

    这种方法需要实现 CefRequestHandlerCefResourceRequestHandler ,这些处理器将资源路径映射到资源提供者。

    这类资源的服务由负责在 IntelliJ Platform 基于 IDE 中显示 SVG 文件的 Image Viewer 组件实现。 有关实现细节,请参见 JCefImageViewer 和相关类。

    默认的浏览器滚动条可能不够用,例如,当它们与 IDE 滚动条的外观不一致时,或者需要特定的外观和行为时。

    在 JCEF 浏览器中,滚动条的外观和行为可以通过 CSS 和 JavaScript 进行自定义。
    IntelliJ 平台提供了 JBCefScrollbarsHelper ,它允许通过两种方式自定义滚动条:

    1. 使用 JBCefScrollbarsHelper.buildScrollbarsStyle() ,它提供了与 IDE 滚动条适配的样式(推荐)。

    2. 使用适配 IDE 外观的 OverlayScrollbars 库。


      有关详细信息,请参阅 getOverlayScrollbarsSourceCSS()getOverlayScrollbarsSourceJS()getOverlayScrollbarStyle() 的 Javadoc。


      当需要透明滚动条或其他高级选项时,应使用此方法。

    在 JCEF 浏览器中,滚动条的外观和感觉可以通过 CSS 和 JavaScript 进行自定义。IntelliJ Platform 提供了 JBCefScrollbarsHelper ,允许以两种方式自定义滚动条:

    1. 使用 JBCefScrollbarsHelper.getOverlayScrollbarStyle() ,该方法提供适配 IDE 滚动条的样式。

    2. 使用 OverlayScrollbars 库,该库已适配 IDE 的外观和感觉。 详情请参见 getOverlayScrollbarsSourceCSS()getOverlayScrollbarsSourceJS()buildScrollbarsStyle() 的 Javadoc。 当需要透明滚动条或其他高级选项时,应使用该库。

    释放资源

    JBCefBrowserJBCefClientJBCefJSQuery 类实现了 JBCefDisposable ,该接口扩展了 Disposable。 这意味着这些类应按照 disposers.md 页面上描述的规则清理其资源。

    例如,自定义的 JBCefClient 如果注册了处理器,应该在 dispose() 方法的实现中移除它们。

    测试

    参见 JBCefTestHelper 以及该包中的测试。

    嵌入到 JCEF 中的 Chrome DevTools 可以用作调试和分析工具。
    它默认是启用的,因此 Chrome DevTools 客户端可以通过默认端口 9222 连接到它。
    默认端口可以通过注册表键 ide.browser.jcef.debug.port 进行更改(转到 Help | Find Action... 并输入“Registry”)。

    嵌入在 JCEF 中的 Chrome DevTools 可以用作调试和分析工具。 默认情况下,它是启用的,因此 Chrome DevTools 客户端可以通过默认的 9222 端口连接到它。 默认端口可以通过注册表键 ide.browser.jcef.debug.port 更改(前往 Help | Find Action... 并输入 "Registry")。

    因此,IntelliJ IDEA Ultimate 中的 JavaScript 调试器可以用于调试通过 Chrome DevTools 在 IDE 中运行的 JavaScript 代码。 使用 Attach to Node.js/Chrome 配置,并指定正确的端口号。

    此外,JCEF 提供了一个默认的 Chrome DevTools 前端(类似于 Chrome 浏览器中的前端),可以通过 JCEF 的浏览器组件上下文菜单中的 Open DevTools 打开。 此菜单项仅在 内部模式 下可用,并且从版本 2021.3 开始,注册表键 ide.browser.jcef.contextMenu.devTools.enabled 必须显式设置为 true

    程序化访问 DevTools

    要在插件代码中访问 Chrome DevTools,请使用以下 API:

    CefBrowser devTools = browser.getCefBrowser().getDevTools(); JBCefBrowser devToolsBrowser = JBCefBrowser.createBuilder() .setCefBrowser(devTools) .setClient(browser.getJBCefClient()) .build();

    要在单独的窗口中打开 DevTools,请调用 JBCefBrowser.openDevtools()

    JCEF 使用示例

    Last modified: 18 一月 2025