ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JxBrowser 7.19实战:Java桌面应用内嵌Chromium的完整指南

JxBrowser 7.19实战:Java桌面应用内嵌Chromium的完整指南 简介面向Java桌面应用开发者jxbrowser 7.19是用于在桌面程序中嵌入Chromium内核的商用浏览器组件定位为当前网上能找得到的较新完整发行包重点解决桌面端加载网页、渲染HTML以及前后端混合交互的集成难题。压缩包共1359个文件体积约437MB其中1345个HTML文件组成完整javadoc API文档包含类层次、常量字段值、方法索引、废弃API说明等配合少量CSS和package-list文件解压后即可在浏览器中离线查阅10个JAR包覆盖Windows、Linux、macOS及ARM平台并区分JavaFX、Swing、SWT三套集成方式另有少量JS与Java源码示例辅助理解。配套的Browser.java展示了如何将jxbrowser直接添加到指定容器组件中适合需要快速验证或进行二次封装的中级开发者。目前已有2589人学习不同平台的JAR包分别对应桌面运行环境可按目标系统选配免去自行交叉编译的麻烦整套资源结构清晰是桌面端浏览器组件接入、功能扩展与API查阅的实用参考资料。1. JxBrowser 7.19Java 桌面应用嵌 Chromium 的成套资源值不值得下JxBrowser 7.19 是目前网上能找到的最新一套 Java 桌面内嵌 Chromium 的 jar 包资源。做内部办公系统的团队基本都被同一个需求卡过产品经理要求界面用 Chrome 渲染但交付环境是内网、是 Windows 服务器还要求 Java 原生集成不让包一层 Electron。JxBrowser 就是干这个的——它把 Chromium 内核封装成纯 Java APISwing 和 JavaFX 都能直接挂一个浏览器组件。这套 7.19 资源适合两类人一类是桌面应用要内嵌网页、又必须离网部署的开发者另一类是爬过坑想换方案的人。它解决的是一整条链路建引擎、开浏览器、挂视图、走网络请求、处理登录态不只是让你把页面显示出来。2. 版本与资源结构7.19 在 7.x 序列里的位置以及包里该有哪些 jar2.1 版本线为什么网上成套资源就停在 7.19JxBrowser 的 6.x 和 7.x 是两套完全不同的 API。6.x 时代还是老式Browser.getContext()那套7.0 之后重写成了引擎Engine加浏览器Browser的模型网络层也换成了 Netty 实现。7.19 属于 7.x 序列里一个非常稳的版本线导航事件、CDP 命令、离屏渲染这些核心能力都已经打磨到位Linux 和 macOS 的二进制也都能正常解包运行。7.2x 之后 TeamDev 收紧了分发方式jar 基本只走官方账号体系下的私有 Maven 仓库网上能成套找到的就是 7.19 这一代。所以标题里说“最新版”不是随便讲的这是当前能拿到手、能本地跑通的实际天花板。版本上还有一个实际考虑7.19 的 license 文件和 jar 是配套的key 绑定的是jxbrowser-chromium-internal这一层的版本号。你拿 7.19 的资源就必须整套 7.19 一起用不能混一个 7.17 的 win64 jar 进去否则授权校验直接失败。选型上我建议直接锁这套不要动“先下一个新版 platform jar 试试”的念头后面坑全是这么来的。2.2 文件清单core、netty、平台 jar 和 license 文件各管什么7.19 的发布包里不是一个大 jar 全包而是按职责拆开的。核心业务代码、Chromium 内部实现、网络层、原生二进制各是各的包缺一个就跑不起来。拿到资源先对照下面这张表核对一遍jar 文件职责jxbrowser-7.19.x.jar公开 APIEngine、Browser、BrowserView、导航、DOMjxbrowser-chromium-7.19.x.jarChromium 引擎的 API 描述层编译期必须jxbrowser-chromium-internal-7.19.x.jarChromium 内核实现运行期必须缺失直接 NoClassDefFoundErrorjxbrowser-netty-7.19.x.jar基于 Netty 的网络层加载 http/https 全靠它jxbrowser-win64-7.19.x.jarWindows 64 位原生二进制Chromium 可执行文件和 dlljxbrowser-linux64-7.19.x.jarLinux 64 位原生二进制部署到服务器时用jxbrowser-macos-7.19.x.jarmacOS 原生二进制jxlicense.lic 或 .key 文本授权文件Engine 创建前必须加载这里最容易翻车的是把jxbrowser-chromium-internal当成“内部的不用管”漏掉。它跟公开 API jar 一样必须在 classpath 上而且必须和主版本号一致。平台 jar 是按操作系统二选一还是全带上取决于你打包的目标机器但开发机上建议三个平台 jar 都放进去方便切环境调试。2.3 依赖引入本地 Maven 仓库与手动 lib 目录两条路这套资源没有中央仓库坐标所以引入方式只有两条路。第一条是装进本地 Maven 仓库用install-file把每个 jar 单独装一遍mvn install:install-file -Dfilejxbrowser-7.19.1.jar \ -DgroupIdcom.teamdev.jxbrowser -DartifactIdjxbrowser \ -Dversion7.19.1 -Dpackagingjar mvn install:install-file -Dfilejxbrowser-chromium-internal-7.19.1.jar \ -DgroupIdcom.teamdev.jxbrowser -DartifactIdjxbrowser-chromium-internal \ -Dversion7.19.1 -Dpackagingjar每个平台 jar 和 netty jar 都这样装一遍注意 artifactId 不要互相覆盖。装完在 pom 里按坐标引用即可。第二条路更省事直接把所有 jar 丢进项目的lib/目录IDE 里 add as library打包时用classpath指过去。这条路径适合不折腾 Maven 的小项目。提示JDK 9 以上跑 JxBrowser 必须加模块开放参数否则sun.awt反射会抛 IllegalAccessError。我一般在启动脚本里固定带上--add-opens java.desktop/sun.awtALL-UNNAMED --add-opens java.desktop/java.awtALL-UNNAMED --add-opens java.base/java.langALL-UNNAMED。3. 跑通第一个窗口Engine 参数、BrowserView 与 Swing 集成3.1 最小可运行 Demo加载页面并打印标题先不聊复杂配置把第一个窗口跑出来是建立信心的关键。下面这段是我在 7.19 上验证过的最小编排建引擎、开浏览器、挂 Swing 视图。import com.teamdev.jxbrowser.engine.Engine; import com.teamdev.jxbrowser.engine.EngineOptions; import com.teamdev.jxbrowser.engine.RenderingMode; import com.teamdev.jxbrowser.browser.Browser; import com.teamdev.jxbrowser.view.swing.BrowserView; import com.teamdev.jxbrowser.navigation.event.FramesLoadFinished; import com.teamdev.jxbrowser.license.License; import javax.swing.*; import java.nio.file.Paths; public class JxDemo { public static void main(String[] args) { // 先加载 license再创建引擎顺序反了会报授权错误 License.getInstance().setLicenseFile(Paths.get(jxlicense.lic)); Engine engine Engine.newInstance( EngineOptions.newBuilder(EngineOptions.Type.MASTER) .renderingMode(RenderingMode.HARDWARE_ACCELERATED) .userDataDir(Paths.get(data)) .args(--disable-gpu, --langzh-CN) .build()); Browser browser engine.newBrowser(); browser.navigation().loadUrl(https://www.baidu.com); browser.waitUntil(FramesLoadFinished.class); System.out.println(title browser.title()); BrowserView view BrowserView.newInstance(browser); JFrame frame new JFrame(JxBrowser 7.19 Demo); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.add(view); frame.setSize(1024, 768); frame.setVisible(true); } }这段代码的核心顺序是license 在 Engine 之前、Engine 在 Browser 之前、Browser 在 View 之前。waitUntil(FramesLoadFinished.class)是 7.x 导航事件模型里的标准等待方式它阻塞到主 frame 加载完成这时browser.title()才有值。如果改成loadUrl后立刻读标题拿到的还是空字符串这是新手最常踩的时序坑。userDataDir(Paths.get(data))指定 Chromium 写缓存和用户数据的目录第一次跑会在这里解包原生二进制所以别放在只读路径下。3.2 EngineOptions 参数怎么设MASTER 类型、渲染模式和 argsEngineOptions 是 JxBrowser 7.x 里所有行为的总开关参数设不对后面全是怪现象。先说类型MASTER是全功能引擎支持多 Browser、CDP、完整网络层LIGHTWEIGHT是轻量模式资源占用小但功能有裁剪我一般只在纯截图场景用。默认选 MASTER 不会错。渲染模式用RenderingMode.HARDWARE_ACCELERATED走 GPU 合成画面流畅但如果目标机器是虚拟机或远程桌面GPU 驱动经常抽风这时候要配合--disable-gpu让 Chromium 退回软件合成。args()方法就是给底层 Chromium 进程传命令行参数这里注意一个细节它是追加式的不是覆盖式的。你可以在代码里这样组合EngineOptions.newBuilder(EngineOptions.Type.MASTER) .renderingMode(RenderingMode.HARDWARE_ACCELERATED) .userDataDir(Paths.get(data)) .args(--disable-gpu, --no-sandbox, --langzh-CN) .remoteDebuggingPort(9222) .build();remoteDebuggingPort(9222)会开启 CDP 调试端口这个后面专门讲。--no-sandbox只在 Linux root 用户或容器环境才需要加Windows 上加了反而降低安全性别图省事无脑上。--langzh-CN是让内置的navigator.language返回中文对需要按语言判断的站点有用。注意userDataDir 一旦指定后续版本升级时最好清空重建否则旧缓存里的 GPU 配置可能导致新版本白屏。3.3 关闭顺序决定程序能不能退干净桌面程序最容易被人忽略的是退出逻辑。JxBrowser 的 Browser 和 Engine 都是重量级对象背后有真实的 Chromium 进程不按顺序关任务管理器里会残留jxBrowser相关进程或者下次启动报“Engine already created”。正确关闭顺序是 View 先 dispose然后 Browser close最后 Engine closeframe.addWindowListener(new WindowAdapter() { Override public void windowClosing(WindowEvent e) { view.dispose(); // 释放原生窗口句柄 browser.close(); // 关闭浏览器实例 engine.close(); // 关闭引擎终止 Chromium 进程 System.exit(0); } });browser.close()返回 boolean如果返回 false 说明内部还有未释放资源一般是因为还有 JavaScript 回调持有 Browser 引用。engine.close()是阻塞的它会等所有子进程退出如果等不到说明前面有 Browser 没关干净。这个顺序我每写一个窗口都强制走一遍省掉了大量“程序退出后进程残留”的血泪经验。4. 避坑与排查白屏、授权失败和启动崩溃的五个典型4.1 授权异常license 文件加载失败的几种表现现象程序启动后立刻抛LicenseException提示 invalid license 或 expired或者更隐蔽的是窗口能弹出来但页面永远空白。原因最常见的有三种。一是setLicenseFile的调用晚于Engine.newInstance授权校验发生在引擎初始化内部晚了就来不及了。二是 license 文件和 jar 版本不配套key 是 7.18 的、jar 是 7.19 的内部校验按chromium-internal的版本号比对必然失败。三是 resources 路径写错打包后 license 文件没进到 classpath 对应的位置。解决把 license 加载提到 main 方法第一行并且用绝对路径兜底。我一般两种姿势都配License.getInstance().setLicenseFile(Paths.get(config/jxlicense.lic)); // 同时支持 -Djxbrowser.license.fileconfig/jxlicense.lic 系统属性这样开发期和打包后都能找到文件。注意申请试用 key 时填的域名和最终运行的机器域名要一致不然换台机器部署又是同一个错。4.2 Windows 上双击闪退VC 运行库与 GPU 的经典组合拳现象打包后的 exe 双击进程起来几秒钟就消失没有任何 Java 异常输出或者弹出一个空白的错误框。原因JxBrowser 的 Windows 原生二进制依赖 VC 2015-2022 运行库干净的服务器上往往没装。还有一个高发原因是显卡驱动过老Chromium 初始化 GPU 进程时崩溃整个引擎连带退出Java 侧来不及打印异常。解决部署机器预装 VC redist 是必须的没得商量。GPU 问题在启动参数里加--disable-gpu大概率能绕过。另外确认 JVM 是 64 位的——32 位 JVM 配 win64 jar 会直接 UnsatisfiedLinkError。排查这类启动即崩的问题我建议先用命令行 java 跑一次而不是双击 exe能看到完整 stderr。4.3 Linux 无桌面环境跑不起来libnss3 与 libgbm 的连锁反应现象服务器上java -jar启动报错加载.so失败常见的是libnss3.so: cannot open shared object file或者进程卡在Engine.newInstance不返回。原因Chromium 在 Linux 上依赖一批系统库包括 libnss3、libnspr4、libgbm、libasound2、libx11。精简版 CentOS 或 Docker 容器里这些默认没有缺一个就加载原生库失败。卡住不返回的情况多半是缺 GPU 相关库Chromium 在等待显示设备初始化。解决装齐依赖再跑。Debian/Ubuntu 系这样处理apt-get install -y libnss3 libnspr4 libgbm1 libasound2 libx11-6 libxcomposite1 libxrandr2 libgtk-3-0root 用户或容器里还要加--no-sandbox。判断到底缺哪个库用ldd直接查 JxBrowser 解包出来的.so文件比瞎猜快得多。解包位置就在 userDataDir 下的chromium目录里。4.4 白屏但标题能拿到Z 序和渲染模式的玄学现象控制台能打印出title ...说明页面加载逻辑正常但窗口里一片白或者只有第一次显示有一帧画面。原因页面逻辑正常但没画面基本是渲染管线没接上。常见的有两种一是BrowserView被丢进了一个没有 LayoutManager 的容器组件尺寸是 0画不出来二是创建 Engine 时用了OFF_SCREEN渲染模式或--disable-gpu组合不当结果又往 Swing 窗口里塞离屏渲染结果没有上屏通道。解决先把 view 放进带布局的容器frame.add(view)配合setSize别用绝对定位。如果确认是渲染模式问题把RenderingMode改成HARDWARE_ACCELERATED虚拟机环境下配合--disable-gpu。这类问题没有固定的银弹我排查顺序是先确认 title 能打出来页面层 OK再查 view 尺寸布局层 OK最后查渲染模式管线层 OK三层定位基本十分钟内能锁定。4.5 内存只涨不降Browser 没 close 的泄漏现场现象程序反复打开关闭窗口任务管理器里 JVM 内存和jxBrowser子进程内存持续上涨GC 之后也不回落。原因JxBrowser 的内存分两块Java 堆里的对象和 Chromium 进程里的原生内存。只关了窗口、没调browser.close()Chromium 侧的资源不会释放Java GC 管不到原生内存。更隐蔽的是每个engine.newBrowser()创建后丢了引用但 Chromium 进程里依然活着。解决每创建一个 Browser必须在一个确定的生命周期里 close 它。窗口关闭监听器里view.dispose()和browser.close()缺一不可。我自己的习惯是封装一个BrowserHolder类持有 Browser 和 View 两个引用在close()方法里强制按顺序释放杜绝裸 new。5. 拿 7.19 干正事UA、代理、Cookie 与截图入库5.1 改 UA 和代理的两个入口CDP 与 NetworkService很多站点会校验 User-Agent默认 UA 里带的JxBrowser标识会被识别出来导致页面返回降级版本或直接拒绝。7.19 里改 UA 最稳的入口是 CDP 的Emulation.setUserAgentOverride它对当前 Browser 立即生效// 包路径以 jar 里 cdp.commands 下的实际类名为准7.19 是 Emulation.setUserAgentOverride browser.cdp().send(new Emulation.setUserAgentOverride() .withUserAgent(Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0 Safari/537.36));注意 CDP 的覆盖是 per-browser 的新建的 Browser 又要重新设一遍。代理配置走NetworkService这个必须在导航开始前设置NetworkService network engine.network(); network.setProxyConfig(ProxyConfig.newBuilder(ProxyType.HTTP) .host(127.0.0.1) .port(8080) .build());ProxyType.HTTP处理普通 http/https 代理如果要动态切换代理先setProxyConfig(null)清掉再设新的直接覆盖有时不生效这是我实测过的行为。代理配好后 DNS 解析也走代理所以内网地址要加 bypass 规则JxBrowser 的 ProxyConfig 里要显式配置豁免列表。5.2 操作 CookieCookieStorage 的读写两步登录态是内网工具绕不开的需求。JxBrowser 的 Cookie 存储在 CookieStorage 里可以枚举、追加、删除CookieStorage storage engine.network().cookieStorage(); ListCookie cookies storage.getAllCookies(); for (Cookie c : cookies) { System.out.println(c.domain() c.name() c.value()); } Cookie session Cookie.newBuilder(session_id, abc123) .domain(.example.com) .path(/) .build(); storage.set(session);加 Cookie 的正确姿势是在loadUrl之前写入这样导航请求自带 Cookie 头。三个细节要注意domain 必须带前导点或者和站点域名完全匹配否则浏览器直接丢弃path 写/最稳妥Cookie.newBuilder的方法名在 7.19 的小版本之间可能有出入以 jar 里 Cookie.Builder 实际接口为准但 domain/path/value 三段固定。读取时getAllCookies()返回的是当前引擎所有会话的集合区分站点要自己按 domain 过滤。5.3 headless 截图从加载到落盘的完整链路服务器上跑截图任务是这个组件的高频场景。7.19 支持离屏加载后直接截整页图不依赖显示设备Engine engine Engine.newInstance( EngineOptions.newBuilder(EngineOptions.Type.MASTER) .renderingMode(RenderingMode.OFF_SCREEN) .args(--disable-gpu) .build()); Browser browser engine.newBrowser(); browser.resize(1920, 1080); // 离屏模式下先定画布尺寸 browser.navigation().loadUrl(https://example.com); browser.waitUntil(FramesLoadFinished.class); Image shot browser.takeSnapshot(); shot.saveToFile(Paths.get(snapshot.png), ImageFormat.PNG);browser.resize必须在导航前调用否则截图尺寸是默认的 800x600。takeSnapshot拿的是当前渲染帧页面里如果有懒加载图片等FramesLoadFinished还不一定加载完我一般会在截图前再补一个固定休眠或者轮询页面内某个标记元素。这里有个实用技巧OCR 识别验证码这类场景用browser.takeSnapshot()拿到 Image 后可以直接走 BufferedImage 转换不用落盘再读盘省一次 IO。提示OFF_SCREEN 模式下不要创建 BrowserView离屏渲染没有上屏通道硬塞进去就是白屏这也是前面 4.4 里那个坑的根源。6. 进阶验证开 CDP 调试端口把 Browser 当本地网页服务调JxBrowser 对开发者和运维来说最值钱的能力是 CDP 调试端口。开一个 9222 端口整个 Browser 实例就变成一个本地调试服务任何一个支持 CDP 协议的客户端都能挂上去看内部状态。我拿到一套 7.19 资源的第一件事永远是先把这个端口打开确认内核真的活着。启动参数里加remoteDebuggingPort(9222)之后用任意浏览器访问http://127.0.0.1:9222/json能看到当前所有页面目标每个目标带webSocketDebuggerUrl。curl 快速验证curl -s http://127.0.0.1:9222/json/version返回 JSON 里有Browser版本和 WebSocket 地址就说明 Chromium 进程健康、CDP 链路通。端口通了我才会继续测 UI 和 license这等于先验证了黑匣子的电源再谈里面的零件。外部工具可以连这个 WebSocket 做注入、截图、网络监听等于把 Java 桌面里的浏览器当成了一个可控的本地网页服务排查问题时能直接抓到真实请求头和 console 日志。从那以后我每接一套 JxBrowser 版本都是先开调试端口、抓一份/json列表再跑业务代码。这套验证习惯帮我过滤掉了大量“页面白屏到底是渲染问题还是网络问题”的无效排查。希望帮到你。本文还有配套的精品资源点击获取
返回列表