ARTICLE DETAIL

资讯详情

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

Cocos Creator 项目打包为 Windows 桌面应用与安装包全流程指南

Cocos Creator 项目打包为 Windows 桌面应用与安装包全流程指南 1. 从 Cocos Creator 到 Windows 桌面端为什么值得折腾用 Cocos Creator 做完一款游戏或者互动应用之后很多人第一反应是发 Web 版、发小游戏平台或者打 Android 包。但真正做过商业交付的人都知道客户嘴里那句“给我一个能在电脑上双击就打开的东西”往往才是项目验收的最后一公里。尤其是做展厅互动、教学课件、企业内部工具、线下活动大屏这类场景Windows 桌面端几乎是绕不开的交付形态。这个项目的核心目标很明确把 Cocos Creator 构建出来的 Web 产物包装成一个独立的.exe可执行文件再进一步做成一个带安装向导的 Windows 安装包。听起来像是两步实际上中间涉及构建配置、Electron 壳工程、主进程与渲染进程通信、资源路径处理、图标替换、打包工具选型、安装包生成器配置等一整套链路。任何一个环节没处理好最后交付给客户的就是一个双击闪退、白屏、或者被杀毒软件拦截的“半成品”。我前后用这套方案交付过好几个线下互动项目踩过的坑从“打包后资源 404”到“安装到中文路径下直接崩溃”都有。所以这篇内容不是搬运官方文档而是把整条链路拆开讲清楚每一步为什么这么做、参数怎么定、哪些地方最容易翻车。适合已经能用 Cocos Creator 正常构建项目、但对桌面端打包不太熟悉的开发者也适合需要给客户交付 Windows 安装包的技术负责人。整条链路大致是Cocos Creator 构建 Web 产物 → 搭建 Electron 壳工程 → 把产物嵌入壳工程 → 配置主进程与窗口 → 本地调试 → 用打包工具生成 exe → 用安装包生成器做成 setup 安装程序。下面按这个顺序把每个环节的细节和坑都摊开讲。2. 整体方案设计与技术选型拆解2.1 为什么选 Electron 而不是其他壳方案把 Web 产物变成桌面 exe市面上能走的路其实有好几条。常见的有 Electron、Tauri、NW.js还有一些老牌的 CEF 封装方案。我最终长期用 Electron不是因为它是唯一选择而是它在“Cocos Creator 产物”这个特定场景下综合成本最低。Cocos Creator 构建出来的 Web 产物本质是一个完整的 HTML JS WASM 资源文件集合它依赖浏览器环境提供 WebGL、Audio、Canvas、Fetch 等能力。Electron 内置的是完整的 Chromium对 WebGL 和 WASM 的支持和 Chrome 几乎一致这意味着 Cocos 的渲染层不需要做任何特殊适配就能跑起来。Tauri 用的是系统 WebView在 Windows 上走的是 WebView2虽然体积小很多但不同机器上 WebView2 的版本差异、WebGL 兼容性、以及部分音频解码行为都可能让 Cocos 产物出现难以复现的问题。对于要交付到各种客户机器上的项目这种不确定性是致命的。另一个关键点是 Node 集成能力。线下互动项目经常需要读写本地文件、调用串口、启动外部程序、做本地数据持久化。Electron 的主进程天然带 Node 环境这些需求用几行代码就能搞定。Tauri 走 Rust 侧虽然也能做但开发效率和团队熟悉度上对前端背景的团队不够友好。提示如果你的项目对安装包体积极度敏感比如要求 20MB 以内且能接受 WebView2 的兼容性风险Tauri 可以作为备选。但只要项目涉及复杂 WebGL 渲染或本地能力调用Electron 仍然是更稳的选择。2.2 构建产物形态的选择Web Mobile 还是 Web DesktopCocos Creator 在构建面板里有多个平台选项做桌面壳工程时通常选Web Mobile或Web Desktop。这两个的区别不只是分辨率适配还影响构建出来的目录结构和默认配置。Web Mobile 默认会做移动端适配构建产物里会带一些针对触摸事件的 polyfill屏幕适配策略偏向竖屏或横屏移动设备。Web Desktop 则更贴近传统网页默认按浏览器窗口尺寸适配。对于要放进 Electron 窗口里运行的项目我更推荐用Web Desktop因为 Electron 窗口本身就是一个桌面浏览器窗口用 Web Desktop 的适配逻辑更自然不会出现莫名其妙的缩放或触摸事件干扰。构建时还有几个关键选项要注意。MD5 Cache建议开启它能给资源文件名加哈希避免缓存问题但要注意 Electron 加载时路径要对应上。调试模式在正式打包时一定要关掉否则会带一堆调试代码体积和性能都受影响。资源服务器地址如果项目里有远程资源要提前配好本地资源则保持默认。构建完成后你会得到一个build/web-desktop目录里面有index.html、assets、src、cocos-js等。这个目录就是后面要嵌入 Electron 的“网页根目录”。2.3 壳工程与游戏产物的目录组织方式这里有个很多人第一次做会纠结的问题Electron 壳工程和 Cocos 构建产物到底怎么放常见有两种做法。第一种是把 Cocos 构建产物直接复制到 Electron 工程的某个子目录里比如electron-app/game/然后主进程加载game/index.html。第二种是把两者完全分开Electron 工程只负责壳构建产物通过配置指向外部路径。我推荐第一种原因是打包工具在收集文件时对工程内相对路径的处理最稳定。第二种在开发阶段用绝对路径能跑但打包后路径一变就容易出问题。具体做法是先建好 Electron 工程然后在package.json的构建配置里把 Cocos 产物目录作为额外资源包含进去或者直接在构建前用脚本把产物复制到指定目录。目录结构大概长这样electron-app/ ├── main.js ├── preload.js ├── package.json ├── game/ # Cocos 构建产物 │ ├── index.html │ ├── assets/ │ ├── src/ │ └── cocos-js/ └── build/ # 打包输出这种结构清晰构建脚本也好写。每次 Cocos 重新构建后只需要把build/web-desktop的内容同步到game/目录即可。3. Electron 壳工程的核心配置与实操要点3.1 主进程窗口配置的关键参数主进程是整个 Electron 应用的入口窗口配置直接决定了用户体验。对于 Cocos 项目窗口配置有几个参数必须认真对待。首先是width和height。不要随便写个 800x600要根据 Cocos 项目的设计分辨率来定。比如项目设计分辨率是 1920x1080那窗口初始尺寸至少要是这个值否则会出现画面被压缩或者留黑边。可以用useContentSize: true让宽高指的是内容区域避免被窗口边框影响。resizable这个参数要看场景。展厅互动类项目通常要禁止用户随意缩放设为false而工具类应用可以放开。fullscreen在需要全屏沉浸的场景下设为true但要注意全屏后如何退出最好保留一个快捷键或者隐藏的退出按钮。webPreferences里的配置是安全重点。nodeIntegration建议设为falsecontextIsolation设为true这是 Electron 官方推荐的安全配置。需要 Node 能力时通过preload脚本用contextBridge暴露有限接口而不是直接把 Node 环境开放给渲染进程。很多教程为了图省事直接开nodeIntegration: true这在交付给客户的产品里是隐患。const { app, BrowserWindow } require(electron); const path require(path); function createWindow() { const win new BrowserWindow({ width: 1920, height: 1080, useContentSize: true, resizable: false, fullscreen: false, autoHideMenuBar: true, webPreferences: { preload: path.join(__dirname, preload.js), nodeIntegration: false, contextIsolation: true, webSecurity: false } }); win.loadFile(path.join(__dirname, game, index.html)); } app.whenReady().then(createWindow);webSecurity: false这个参数要特别说明。Cocos 构建产物在本地加载时如果涉及跨域资源或者 WASM 加载可能会被同源策略拦住。开发阶段可以关掉但正式发布时最好通过自定义协议或者本地服务器的方式解决而不是长期关闭安全策略。如果项目确实简单、资源全在本地关闭它也能跑但要清楚这是用安全性换便利。3.2 资源路径处理与本地加载的坑Cocos 构建产物里的资源引用默认是相对路径或者以/开头的绝对路径。在浏览器里以/开头指的是域名根目录但在 Electron 用loadFile加载本地文件时/会被解析成磁盘根目录直接导致资源 404。这个问题最典型的表现就是打包后打开 exe画面全黑或者白屏控制台报一堆Failed to load resource。解决办法有两个方向。第一个方向是改 Cocos 的构建配置把资源路径改成相对路径。在构建面板里有些版本可以设置“资源服务器地址”为空让产物用相对路径引用。但不同版本的 Cocos 行为不一致不能完全依赖。第二个方向是在 Electron 侧做路径重写。可以在preload或者主进程里拦截请求把以/开头的路径映射到本地文件目录。更简单的做法是用loadFile加载index.html后通过webContents的did-fail-load事件排查具体是哪些资源没加载上然后针对性处理。我自己的习惯是构建后先本地用浏览器打开index.html确认产物本身没问题再放进 Electron 里跑。如果浏览器能跑、Electron 白屏那基本就是路径问题。这时候打开开发者工具正式打包前记得保留win.webContents.openDevTools()看 Network 面板里哪些请求是红的路径长什么样一目了然。注意Cocos 的 WASM 文件比如物理引擎、Spine 相关加载时对 MIME 类型有要求。Electron 本地加载时如果 MIME 不对WASM 会加载失败。可以在主进程里注册自定义协议给.wasm文件返回application/wasm这是比较彻底的解法。3.3 主进程与渲染进程的通信设计Cocos 游戏逻辑跑在渲染进程里但很多桌面能力读写文件、调用系统对话框、退出应用、获取机器信息必须在主进程做。两者之间的通信设计直接决定了后续功能扩展顺不顺畅。标准做法是用ipcMain和ipcRenderer配合contextBridge。在preload.js里暴露一组有限的 APIconst { contextBridge, ipcRenderer } require(electron); contextBridge.exposeInMainWorld(desktopAPI, { saveData: (data) ipcRenderer.invoke(save-data, data), loadData: () ipcRenderer.invoke(load-data), quitApp: () ipcRenderer.send(quit-app), getMachineId: () ipcRenderer.invoke(get-machine-id) });然后在主进程里处理这些请求const { ipcMain, app } require(electron); const fs require(fs); const path require(path); ipcMain.handle(save-data, async (event, data) { const filePath path.join(app.getPath(userData), save.json); fs.writeFileSync(filePath, JSON.stringify(data)); return true; }); ipcMain.handle(load-data, async () { const filePath path.join(app.getPath(userData), save.json); if (fs.existsSync(filePath)) { return JSON.parse(fs.readFileSync(filePath, utf-8)); } return null; }); ipcMain.on(quit-app, () { app.quit(); });在 Cocos 的 TypeScript 代码里就可以通过window.desktopAPI调用这些能力。注意要做类型声明否则 TS 编译会报错。可以在项目里加一个global.d.tsdeclare global { interface Window { desktopAPI: { saveData: (data: any) Promiseboolean; loadData: () Promiseany; quitApp: () void; getMachineId: () Promisestring; }; } } export {};这套设计的好处是渲染进程完全不知道 Node 的存在只看到一组干净的 API安全性和可维护性都好。后续要加新能力只需要在 preload 和主进程里各加一处游戏代码里调用即可。3.4 图标、菜单与窗口行为的细节打磨交付给客户的产品细节决定专业度。默认的 Electron 图标是那个原子标志直接打包出去客户一眼就知道是“套壳”。替换图标分两处窗口左上角图标和 exe 文件图标。窗口图标在BrowserWindow配置里用icon指定传一个.ico或.png路径。exe 图标则要在打包工具配置里指定这个后面讲打包时再说。.ico文件建议包含多个尺寸16、32、48、256否则在不同缩放比例下会模糊。菜单方面默认菜单栏有 File、Edit、View 等对游戏类应用完全是干扰。用Menu.setApplicationMenu(null)可以直接去掉整个菜单栏。如果还需要保留一些快捷键比如 F12 开发者工具、CtrlQ 退出可以用globalShortcut或者before-input-event单独处理而不是留着默认菜单。窗口行为上autoHideMenuBar: true可以隐藏菜单栏但保留 Alt 唤出frame: false可以做成无边框窗口适合自定义标题栏的沉浸式应用。但无边框窗口要自己处理拖动和关闭按钮工作量不小除非设计上有明确要求否则不建议轻易用。还有一个容易被忽略的点单实例锁。线下项目经常出现用户重复双击图标开出好几个窗口的情况。用app.requestSingleInstanceLock()可以保证只有一个实例运行第二次启动时激活已有窗口const gotTheLock app.requestSingleInstanceLock(); if (!gotTheLock) { app.quit(); } else { app.on(second-instance, () { if (win) { if (win.isMinimized()) win.restore(); win.focus(); } }); }这几行代码能避免很多现场尴尬强烈建议加上。4. 从源码到 exe打包工具选型与完整实操4.1 electron-builder 与 electron-packager 的取舍Electron 打包工具有好几个主流的是electron-builder和electron-packager现在叫electron/packager。两者定位不同electron-packager只负责把 Electron 运行时和你的代码打成一个可执行目录不生成安装包electron-builder则一条龙既能生成免安装的绿色版也能生成 NSIS 安装包、MSI 等。对于要交付安装包的项目我直接用electron-builder省得再引入第二个工具。它的配置集中在package.json的build字段或者单独的electron-builder.yml里支持多平台、多架构、代码签名、自动更新等功能足够覆盖绝大多数场景。安装很简单npm install electron-builder --save-dev然后在package.json里加脚本{ scripts: { dist: electron-builder --win } }4.2 electron-builder 配置详解与参数计算配置是打包的核心写错一个字段就可能导致打包失败或者产物不能用。下面是一份经过实战验证的 Windows 配置{ build: { appId: com.yourcompany.yourgame, productName: YourGame, directories: { output: build }, files: [ main.js, preload.js, game/**/* ], win: { target: [ { target: nsis, arch: [x64] } ], icon: build/icon.ico, artifactName: ${productName}-Setup-${version}.${ext} }, nsis: { oneClick: false, allowToChangeInstallationDirectory: true, createDesktopShortcut: true, createStartMenuShortcut: true, shortcutName: YourGame, installerIcon: build/icon.ico, uninstallerIcon: build/icon.ico, deleteAppDataOnUninstall: false } } }几个关键参数值得展开说。appId是应用的唯一标识安装后在注册表里用它区分建议用反向域名格式。productName是显示名称会出现在安装向导、快捷方式、程序列表里中文也可以但要注意编码问题稳妥起见用英文或拼音。files字段决定哪些文件被打进应用。这里把game/**/*包含进去确保 Cocos 产物完整。注意node_modules默认会被包含但electron-builder会做依赖分析只打包生产依赖。如果你的项目里有只在开发时用的包确保它们在devDependencies里否则会被打进去体积白白增大。win.target里arch选x64还是ia32取决于目标机器。现在绝大多数 Windows 机器都是 64 位选x64即可。如果客户有老旧的 32 位工控机才需要ia32。两个都打会让安装包体积翻倍没必要。nsis配置里oneClick: false表示用向导式安装而不是双击直接装。allowToChangeInstallationDirectory: true让用户能选安装路径这对企业客户很重要他们往往有固定的软件安装盘。deleteAppDataOnUninstall: false表示卸载时保留用户数据避免用户重装后存档丢失这个要根据项目性质决定。4.3 打包过程中的常见报错与排查打包过程报错是家常便饭我整理了几个高频问题和处理方式。报错一下载 Electron 二进制超时。electron-builder打包时需要下载对应版本的 Electron 运行时网络不好时会卡住或失败。解决办法是配置镜像源在项目根目录建.npmrcelectron_mirrorhttps://npmmirror.com/mirrors/electron/ electron_builder_binaries_mirrorhttps://npmmirror.com/mirrors/electron-builder-binaries/报错二Application entry file main.js does not exist。这通常是files配置没包含main.js或者package.json里的main字段指向的路径不对。检查package.json的main字段是否指向实际的主进程文件。报错三打包成功但运行白屏。回到第 3.2 节的路径问题排查。另外检查files是否真的把game目录打进去了可以解压生成的app.asar看看内容。报错四安装包被杀毒软件报毒。这是 Electron 应用的常见困扰尤其是没有代码签名的 exe。根本解法是购买代码签名证书对 exe 和安装包签名。没有证书的情况下可以尝试在nsis配置里加perMachine: false减少对系统目录的写入降低误报概率但不能完全避免。报错五中文路径下崩溃。有些老版本 Electron 对中文路径处理有问题表现为安装到D:\我的软件\下就打不开。解决办法是升级 Electron 到较新版本或者在主进程启动时检测路径必要时提示用户换路径。4.4 生成安装包的完整流程与验证配置写好后完整流程是这样的在 Cocos Creator 里构建 Web Desktop 产物输出到build/web-desktop。用脚本或手动把产物复制到electron-app/game/。在electron-app目录下执行npm run dist。等待打包完成产物在build/目录下会看到YourGame-Setup-1.0.0.exe和一个win-unpacked目录。先运行win-unpacked里的 exe验证功能正常。再运行安装包走一遍安装流程验证快捷方式、安装路径、卸载是否正常。验证环节有几个必查项安装后从开始菜单启动是否正常、桌面快捷方式图标是否正确、安装到非默认路径是否正常、卸载后残留文件是否清理、以及在没有开发环境的干净机器上是否能跑。最后一项尤其重要开发机上往往装了一堆运行时掩盖了依赖缺失问题。有条件的话用一台干净的虚拟机做验收测试。提示win-unpacked目录里的 exe 是免安装版可以直接拷给客户做绿色版使用。如果客户不接受安装流程这个目录压缩一下就能交付但要注意首次运行可能会有 SmartScreen 拦截。5. 常见问题排查与实战避坑经验5.1 白屏、闪退、资源加载失败速查这三类问题占了桌面端打包故障的八成以上我整理成一张速查表遇到问题按表排查能省不少时间。现象可能原因排查方法解决方式打开后纯白屏资源路径以/开头开 DevTools 看 Network 报错改相对路径或注册自定义协议打开后黑屏WebGL 初始化失败看 Console 是否有 WebGL 报错检查显卡驱动或加--disable-gpu测试双击闪退主进程代码报错命令行运行 exe 看输出修复主进程异常加 try-catch部分图片不显示大小写敏感或路径错误对比浏览器和 Electron 的请求路径统一路径大小写检查构建产物WASM 加载失败MIME 类型不对Console 报WebAssembly相关错误注册协议返回正确 MIME音频不播放自动播放策略限制Console 有 autoplay 警告首次交互后再播放或配置autoplayPolicy关于黑屏补充一个经验有些集成显卡或者远程桌面环境下Electron 的 GPU 加速会出问题。可以在启动参数里加app.disableHardwareAcceleration()强制用软件渲染虽然性能下降但兼容性大幅提升。线下项目如果目标机器配置参差不齐这个开关值得考虑做成可配置项。5.2 安装包体积优化的几个实操手段Electron 应用体积大是公认的一个空壳打包出来就 150MB 起步。加上 Cocos 产物轻松上 200MB。客户看到这个数字往往会皱眉所以优化是有必要的。第一个手段是排除无用文件。files字段要精确控制不要把源码、测试文件、文档打进去。node_modules里只保留生产依赖devDependencies里的东西不会被打包但要确认没有误放。第二个手段是压缩 asar。electron-builder默认会把代码打成app.asar可以开启asar的压缩选项。不过压缩对启动速度有轻微影响要权衡。第三个手段是精简 Electron 运行时。这个比较激进需要手动删除 Electron 里用不到的语言包、调试符号等。有工具可以做这件事但操作不当会导致运行异常不建议新手尝试。第四个手段是Cocos 产物本身瘦身。构建时关掉调试模式、移除未使用的模块、压缩纹理这些在 Cocos 构建面板里都有选项。一个优化良好的 Cocos 产物比默认构建能小 30% 以上。实测下来一个中等规模的 Cocos 互动项目经过上述优化安装包能控制在 120MB 到 180MB 之间。如果客户对体积有硬性要求就要考虑前面提到的 Tauri 方案或者把资源做成按需下载。5.3 交付前的自检清单与现场部署建议项目做完不等于交付完成现场翻车才是最要命的。我养成了一个习惯交付前按清单过一遍在干净虚拟机上完整走一遍安装、启动、使用、卸载流程。测试目标机器的分辨率确认窗口没有超出屏幕或显示不全。测试断网情况下能否正常启动如果项目不依赖网络。确认存档、配置文件的读写路径正确不会因为权限问题失败。检查任务管理器里的进程名和图标确认没有暴露 Electron 默认信息。准备好绿色版作为备用万一安装包在客户机器上装不上可以直接解压运行。现场部署时如果客户机器有还原卡或者权限限制安装包可能装不上。这时候绿色版就是救命稻草。另外提前问清楚客户机器的 Windows 版本和位数避免打出来的包不兼容。Windows 7 虽然已经很少见但个别工控场景还在用而新版 Electron 已经不支持 Win7这种项目只能用老版本 Electron 或者换方案。5.4 后续扩展自动更新与多平台打包项目交付后需求变更和 bug 修复是常态。如果每次都要客户重新下载安装包体验很差。electron-builder配合electron-updater可以做自动更新原理是应用启动时检查服务器上的版本文件有新版本就下载替换。配置不算复杂但需要一个能放更新包的服务器以及处理好更新失败的回滚逻辑。多平台方面同一套 Electron 壳工程改改配置就能打 macOS 的 dmg 和 Linux 的 AppImage。但要注意 Cocos 产物在不同平台上的表现可能有差异尤其是音频和字体渲染。macOS 打包还需要苹果开发者账号做签名和公证否则用户打开会提示“无法验证开发者”。这些是另一个话题这里不展开但心里要有数Windows 只是第一站跨平台交付的坑还在后面。我个人在实际操作中的体会是Cocos Creator 加 Electron 这套组合胜在成熟和可控。它不完美体积大、启动慢、偶尔被杀毒软件误报但在“快速把 Web 产物变成桌面应用”这件事上目前没有更省心的方案。把路径处理、进程通信、打包配置这三块吃透剩下的就是熟练度问题。真正决定交付质量的往往不是技术选型而是那些文档里不写、只有踩过才知道的细节。
返回列表