Files
pqs-9100_client/doc/便携式JRE集成指南.md

4.8 KiB
Raw Blame History

便携式 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下载页面
  • BellSoft Liberica 8 JREStandard/FullFull 含 JavaFX下载页面
  • Eclipse Temurin 8 JREAdoptium下载页面

选择要点:

  • 需要 AWT/Swing/字体/打印 → 选择非 headless 包。
  • 需要 JavaFX → 选择 Liberica Full 或 ZuluFX。
  • 仅命令行/服务端 → 任意 JRE 8headless 也可)。

目录放置约定

将解压后的 JRE 放入项目的 build/extraResources/jre,保证内部存在 bin/java(.exe)

build/
  extraResources/
    jre/
      bin/
        java(.exe)
      lib/
      ...

构建后在生产环境可通过 process.resourcesPath 访问: <app>/resources/extraResources/jre/bin/java(.exe)

主进程调用示例

electron/preload/lifecycle.js 或你的业务模块中封装 Java 运行工具(开发/生产两种路径):

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 };

在生命周期中调用(示例):

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 TemurinAdoptium、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