## 便携式 JRE/JDK8 集成指南 本指南介绍如何将 JRE 8 以“便携式”(解压即用、无需安装)的方式随应用打包,并在 Electron 主进程中通过绝对路径调用,从而避免要求用户在系统中安装 JDK/JRE。 ### 为什么选择便携式 JRE - 无需管理员权限与系统环境变量配置,用户无感知。 - 不污染系统环境(不写入 JAVA_HOME/PATH)。 - 跨平台一致,可精简体积、可控版本。 ### 适用场景 - 运行 Java 程序或 JAR 包(仅需运行时)。 - 不需要 javac/jcmd/jmap 等开发/诊断工具(若需要,请改为随包便携式 JDK)。 ### 推荐的 JRE 8 发行版(可再分发) - Azul Zulu 8 JRE(可选 ZuluFX 含 JavaFX):[下载页面](https://www.azul.com/downloads/?version=java-8-lts&package=jre) - BellSoft Liberica 8 JRE(Standard/Full,Full 含 JavaFX):[下载页面](https://bell-sw.com/pages/downloads/#/java-8-lts) - Eclipse Temurin 8 JRE(Adoptium):[下载页面](https://adoptium.net/temurin/releases/?version=8) 选择要点: - 需要 AWT/Swing/字体/打印 → 选择非 headless 包。 - 需要 JavaFX → 选择 Liberica Full 或 ZuluFX。 - 仅命令行/服务端 → 任意 JRE 8(headless 也可)。 ### 目录放置约定 将解压后的 JRE 放入项目的 `build/extraResources/jre`,保证内部存在 `bin/java(.exe)`: ``` build/ extraResources/ jre/ bin/ java(.exe) lib/ ... ``` 构建后在生产环境可通过 `process.resourcesPath` 访问: `/resources/extraResources/jre/bin/java(.exe)`。 ### 主进程调用示例 在 `electron/preload/lifecycle.js` 或你的业务模块中封装 Java 运行工具(开发/生产两种路径): ```js const path = require('path'); const { spawn } = require('child_process'); function getExtraResourcesDir() { // 开发态:使用项目目录;生产态:使用 asar/resources 目录 const isDev = !!process.env.EE_DEV || process.env.NODE_ENV === 'development'; return isDev ? path.join(process.cwd(), 'build', 'extraResources') : path.join(process.resourcesPath, 'extraResources'); } function getJavaBinPath() { const extraDir = getExtraResourcesDir(); const javaBinName = process.platform === 'win32' ? 'java.exe' : 'java'; return path.join(extraDir, 'jre', 'bin', javaBinName); } function runJavaJar(jarAbsPath, args = [], options = {}) { const javaPath = getJavaBinPath(); const child = spawn(javaPath, ['-jar', jarAbsPath, ...args], { stdio: 'inherit', ...options, }); return child; } async function ensureJavaVersion(logger) { return new Promise((resolve) => { const child = spawn(getJavaBinPath(), ['-version']); let out = ''; let err = ''; child.stdout && child.stdout.on('data', (d) => (out += d.toString())) child.stderr && child.stderr.on('data', (d) => (err += d.toString())) child.on('close', () => { const text = (out + '\n' + err).trim(); logger && logger.info('[java] version check:', text); resolve(text.includes('1.8.0')); }); }); } module.exports = { getJavaBinPath, runJavaJar, ensureJavaVersion }; ``` 在生命周期中调用(示例): ```js const { logger } = require('ee-core/log'); const path = require('path'); const { runJavaJar, ensureJavaVersion } = require('./java-runner'); class Lifecycle { async ready() { const ok = await ensureJavaVersion(logger); if (!ok) { logger.error('[java] 未检测到 JRE 8,请检查 extraResources/jre 是否存在'); } } async windowReady() { const jarPath = path.join(process.resourcesPath || process.cwd(), 'extraResources', 'tools', 'your-app.jar'); // 示例:延后在某业务时机再启动 Java 进程 // const proc = runJavaJar(jarPath, ['--arg1', 'value']); } } ``` 注意:示例中的 `java-runner` 为上文工具函数文件,实际请按你的项目结构放置。 ### 验证清单 - 运行 `jre/bin/java -version` 输出包含 `1.8.0_xxx`。 - 若涉及 GUI/字体/打印,验证 AWT/Swing 中文渲染与打印。 - 若需 JavaFX,验证 JavaFX Demo 启动。 - 若涉及 TLS/HTTPS,验证 SSL 通信正常。 ### 许可与合规 - Azul Zulu、Eclipse Temurin(Adoptium)、BellSoft Liberica 的 JRE/JDK 8 发行包均可免费再分发(GPLv2+CE 或厂商许可证)。 - 建议在应用的“关于/许可证”中附上所选发行版的许可证链接与致谢。 ### 常见问题 1) 是否“阉割”? — 上述 JRE 8 发行版均为标准运行时,通过兼容性测试;JRE 不包含开发者工具属于正常区别,不是删减。 2) 何时需要 JDK 而不是 JRE? — 需要 `javac` 编译或 `jcmd/jmap` 等诊断工具,或你的 Java 组件依赖 `tools.jar` 时。 3) 体积如何优化? — 选择 headless(若无 GUI 需求)、去除无用语言/字体包;或改用 JDK 9+ 使用 jlink(不适用于 8)。