Unity游戏打包指南:使用Inno Setup制作专业Windows安装包

📅 2026/7/11 5:47:39
Unity游戏打包指南:使用Inno Setup制作专业Windows安装包
1. 项目概述为什么Unity开发者需要一个专业的安装包如果你是一个Unity开发者辛辛苦苦几个月甚至几年终于把游戏或应用开发完成在Unity Editor里点击“Build”生成了一堆.exe和.dll文件然后兴冲冲地发给朋友或客户测试。结果对方问“怎么安装直接运行这个.exe吗为什么我电脑提示缺少什么DLL这个Data文件夹是干嘛的能删吗” 这时候一个专业、傻瓜式的安装包就显得至关重要了。这就是我们今天要聊的核心使用Inno Setup将Unity程序打包成一个标准的Windows安装包.exe。这不仅仅是把文件打个压缩包那么简单。一个专业的安装包意味着用户体验用户只需双击一个文件跟着向导点击“下一步”程序就会自动安装到合适的位置比如Program Files并在开始菜单和桌面上创建快捷方式。专业形象一个带有公司Logo、许可协议、安装进度条的安装程序远比一个需要用户自己解压、找启动文件的文件夹要专业得多。部署简化自动处理依赖项如.NET Framework、VC运行库、创建注册表项、设置环境变量这些都是手动复制粘贴无法做到的。分发便利一个单一的.exe或.msi文件便于上传到网站、网盘或通过邮件发送。Inno Setup正是解决这个问题的利器。它是一款免费、开源、功能强大且脚本驱动的安装程序制作工具。对于Unity开发者来说它学习曲线平缓能生成非常“Windows原生”风格的安装程序与系统完美融合。网络上搜索“inno setup 美化”的热度也说明社区有大量资源可以让你的安装界面变得独一无二。所以无论你是独立开发者准备发布你的第一款Steam游戏还是企业团队需要为客户部署一个严肃的行业应用掌握Inno Setup都是提升产品交付质量的关键一步。2. 核心思路与准备工作在动手写脚本之前在打开Inno Setup编译器之前我们需要把准备工作做扎实。很多新手卡壳不是因为脚本多难而是前期思路没理清。2.1 理解Unity的构建输出结构首先你必须清楚Unity构建出来的文件是什么样子的。以最常见的Windows PC平台x86_64构建为例当你构建完成后会得到一个文件夹通常包含以下核心内容YourGame.exe这是游戏的主程序入口。注意这个exe本身并不能独立运行它需要同目录下的其他文件支持。YourGame_Data/文件夹这是Unity游戏的核心资源文件夹里面包含了场景、资源、脚本代码编译后的、设置等所有游戏数据。绝对不可以删除或移动这个文件夹相对于.exe的位置。MonoBleedingEdge/或UnityPlayer.dll等这些是Unity运行时环境如Mono或IL2CPP所需的依赖库。其他.dll文件可能包括UnityCrashHandler64.dll崩溃报告、xinput等系统交互库。核心原则对于大多数Unity构建你需要将整个构建输出文件夹视为一个不可分割的整体进行打包。安装时这个整体的相对结构必须保持不变。2.2 工具准备Inno Setup与脚本编辑器下载Inno Setup前往其 官方网站 下载安装程序。建议下载带“QuickStart Pack”的版本它包含了图形化的脚本向导Inno Setup Compiler和一些有用的预处理器。安装像安装任何Windows软件一样安装它。脚本编辑器选择Inno Setup自带的编辑器比较简单。对于复杂的脚本我强烈推荐使用Visual Studio Code并安装“Inno Setup”扩展。它会提供语法高亮、代码提示和片段补全效率提升巨大。这也是很多资深用户的选择搜索“inno setup 美化”时看到的很多高级脚本都是在专业编辑器里编写的。2.3 规划安装包行为在写第一行代码前想清楚你的安装包需要做什么安装目录默认是{pf}\YourCompany\YourGame{pf}代表Program Files还是{localappdata}\YourGame前者需要管理员权限更适合所有用户使用的程序后者不需要更适合单用户或便携式应用。开始菜单文件夹叫什么名字里面放哪些快捷方式游戏主程序、卸载程序、官网链接桌面快捷方式需要创建吗许可协议有需要用户同意的EULA最终用户许可协议文件吗通常是一个.rtf或.txt文件。依赖项检查你的Unity项目是否依赖特定的.NET Framework版本或VC运行库Unity 2022 LTS及以后版本使用.NET 6/7/8的情况越来越常见可能需要单独分发或引导安装。安装类型例如“典型安装”、“最小安装”、“自定义安装”让用户选择安装哪些组件比如高清纹理包、离线文档等。这对于大型游戏很实用。卸载程序Inno Setup会自动生成但你需要决定它的名字和是否在开始菜单中显示。把这些想清楚相当于画好了设计图接下来就是按图施工。3. Inno Setup脚本核心章节详解Inno Setup的脚本文件.iss是其灵魂。它由多个[Section]构成。我们从一个最基础、可工作的脚本开始然后逐步添加功能。假设我们的Unity游戏构建输出文件夹名为MyUnityGameBuild里面包含MyGame.exe。3.1[Setup]段全局配置这是脚本的“大脑”定义了安装程序的基本信息。[Setup] ; 唯一标识你的应用程序。通常使用GUID格式可以使用Inno Setup自带的工具生成或者使用反向域名格式。 AppId{{A1B2C3D4-E5F6-7890-ABCD-EF1234567890} ; 应用程序名称显示在安装向导标题和已安装程序列表中。 AppName我的Unity游戏 ; 应用程序版本 AppVersion1.0.0 ; 发布者名称 AppPublisher我的工作室 ; 发布者网站的URL可选 AppPublisherURLhttps://www.mywebsite.com ; 程序支持/更新网站的URL可选 AppSupportURLhttps://support.mywebsite.com ; 应用程序的默认安装目录。 ; {pf} 是常量代表 Program Files 文件夹通常是 C:\Program Files ; 使用 {pf}\MyStudio\MyGame 这样的结构是个好习惯避免污染 Program Files 根目录。 DefaultDirName{pf}\MyStudio\MyUnityGame ; 安装程序的默认组开始菜单文件夹 DefaultGroupName我的Unity游戏 ; 输出安装包的文件名。这里将生成 MyUnityGame_Setup_1.0.0.exe OutputBaseFilenameMyUnityGame_Setup_1.0.0 ; 安装程序的压缩方式。solid 压缩率更高但修改其中任何一个文件都需要重新压缩整个安装包。 ; lzma2/ultra64 是目前最佳的平衡选择。 Compressionlzma2/ultra64 ; 是否启用安装程序本身的运行时压缩几乎总是 yes。 SolidCompressionyes ; 安装程序图标可选 SetupIconFilemy_setup_icon.ico ; 安装向导窗口左上角图标可选 WizardSmallImageFilewizard_small.bmp ; 许可文件.rtf或.txt如果不需要可以注释掉 ; LicenseFilelicense.rtf ; 安装完成后是否在开始菜单创建卸载程序快捷方式 CreateUninstallIconyes关键点解析AppId这是控制程序“升级”和“修复”的关键。如果两个安装包的AppId相同后安装的会覆盖先前的。如果你发布了新版本如1.0.1但希望它覆盖1.0.0就必须保持AppId不变。反之如果你想并行安装两个版本则需要不同的AppId。DefaultDirName使用常量如{pf},{localappdata}能让安装程序自动适应不同语言和配置的Windows系统。Compression对于Unity游戏资源文件如图片、音频本身已压缩再用lzma2压缩效果可能不明显但能进一步减小安装包体积。构建时间会稍长。3.2[Files]段文件部署这是脚本的“双手”告诉安装程序哪些文件需要复制到用户电脑以及复制到哪里。这是处理Unity构建输出的核心。[Files] ; 基本模式源文件 - 目标目录 ; 将构建文件夹下的所有文件递归地复制到应用程序目录 {app} Source: MyUnityGameBuild\*; DestDir: {app}; Flags: ignoreversion recursesubdirs createallsubdirs ; 更精细的控制示例如果需要 ; 将主程序单独列出可以附加不同的标志 Source: MyUnityGameBuild\MyGame.exe; DestDir: {app}; Flags: ignoreversion ; 递归复制Data文件夹及其所有内容 Source: MyUnityGameBuild\MyGame_Data\*; DestDir: {app}\MyGame_Data; Flags: ignoreversion recursesubdirs createallsubdirs ; 复制运行时依赖文件夹 Source: MyUnityGameBuild\MonoBleedingEdge\*; DestDir: {app}\MonoBleedingEdge; Flags: ignoreversion recursesubdirs createallsubdirs ; 如果你有额外的依赖比如.NET运行时安装包可以这样包含进来但不立即安装 ; Source: Prerequisites\windowsdesktop-runtime-6.0.xx-win-x64.exe; DestDir: {tmp}; Flags: deleteafterinstallFlags参数详解ignoreversion安装时忽略文件版本检查直接覆盖。对于Unity的资源和DLL通常使用这个标志因为它们的版本管理不如传统Windows DLL严格。recursesubdirs递归包含源目录下的所有子目录。这是打包Unity构建文件夹的关键。createallsubdirs在目标位置创建源目录中存在的所有子目录结构。deleteafterinstall安装完成后删除此文件。常用于临时存放的预装程序如VC运行库。nocompression不对此文件进行压缩。对于已经高度压缩的文件如.mp4,.unityweb加上这个可以加快安装速度。实操心得我强烈推荐使用第一种简单的通配符方式Source: “BuildFolder\*”;配合recursesubdirs。这能确保完整复制Unity构建的整个生态避免因遗漏某个子文件夹下的文件导致游戏无法启动。在脚本开发阶段可以先用这种方式确保功能正常后再考虑是否需要更精细的控制。3.3[Icons]与[Tasks]段创建快捷方式与任务安装程序不只是复制文件还要让用户方便地找到你的程序。[Icons] ; 在开始菜单中创建游戏主程序的快捷方式 ; Name: “{group}\我的Unity游戏”; Filename: “{app}\MyGame.exe” ; 在开始菜单中创建卸载程序的快捷方式 Name: “{group}\卸载我的Unity游戏”; Filename: “{uninstallexe}” ; 在桌面创建快捷方式可选由用户选择 Name: “{commondesktop}\我的Unity游戏”; Filename: “{app}\MyGame.exe”; Tasks: desktopicon [Tasks] ; 定义用户可选的安装任务 ; 创建一个复选框任务让用户选择是否创建桌面快捷方式 Name: “desktopicon”; Description: “创建桌面快捷方式”; GroupDescription: “附加快捷方式:”; Flags: unchecked ; 另一个例子选择是否安装“高清纹理包”假设有的话 ; Name: “hitextures”; Description: “安装高清纹理包 (额外 2GB)”; GroupDescription: “可选组件:”; Flags: unchecked关键点解析{group}代表在[Setup]段中定义的DefaultGroupName即开始菜单文件夹。{commondesktop}代表所有用户的公共桌面文件夹。使用{userdesktop}则为当前用户桌面。Tasks: desktopicon将桌面图标与名为desktopicon的任务绑定。只有当用户在安装时勾选了此任务该快捷方式才会被创建。Flags: unchecked默认不勾选此任务让用户自己决定。3.4[Run]段安装后操作文件复制完成后你可能还想执行一些操作。[Run] ; 安装完成后立即运行游戏可选 Filename: “{app}\MyGame.exe”; Description: “启动我的Unity游戏”; Flags: postinstall nowait skipifsilent ; 安装前或安装后运行预装程序如.NET检查器 ; Filename: “{tmp}\dotnet-runtime-checker.exe”; Parameters: “/silent”; StatusMsg: “正在检查系统依赖…”; Flags: runhiddenFlags参数详解postinstall在安装成功完成后在最后的向导页面上显示一个复选框来运行此程序。nowait安装程序不会等待这个运行的程序结束。对于启动主游戏一定要用这个否则安装程序会一直卡住直到游戏关闭。skipifsilent如果安装是以静默模式/SILENT或/VERYSILENT运行的则跳过此操作。这对于自动化部署很重要。runhidden以隐藏窗口的方式运行程序适用于后台检查工具。4. 高级功能与实战技巧掌握了基础章节你的安装包已经能用了。但要做得专业、健壮还需要下面这些进阶知识。4.1 依赖项检查与自动安装Unity程序可能依赖特定的运行环境。虽然现代Unity IL2CPP构建将大部分依赖静态链接但一些情况仍需注意VC Redistributable某些Unity版本或第三方插件可能需要特定版本的VC运行库。你可以使用Inno Setup的[Files]和[Run]段来包含并静默安装它。.NET Desktop Runtime如果你的Unity项目使用.NET 6/7/8作为脚本后端在Player Settings中设置则目标机器必须安装相应的.NET运行时。你可以编写Pascal脚本来检查。以下是一个检查并安装.NET 6运行时的示例放在[Code]段[Code] function InitializeSetup(): Boolean; var dotnetVersion: string; isInstalled: Boolean; resultCode: Integer; begin // 检查.NET 6.0.0或更高版本是否存在 isInstalled : RegQueryStringValue(HKLM, ‘SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedhost’, ‘Version’, dotnetVersion); if (not isInstalled) or (CompareVersion(dotnetVersion, ‘6.0.0’) 0) then begin if MsgBox(‘本游戏需要 Microsoft .NET 6.0 运行时。是否立即下载并安装’, mbConfirmation, MB_YESNO) IDYES then begin // 这里可以启动浏览器打开下载页面或者如果你已将安装包包含在[Files]中则直接运行 ShellExec(‘open’, ‘https://dotnet.microsoft.com/download/dotnet/6.0/runtime’, ”, ”, SW_SHOW, ewNoWait, resultCode); end else begin MsgBox(‘无法继续安装。必须安装 .NET 6.0 运行时才能运行此游戏。’, mbError, MB_OK); Result : False; // 中止安装 Exit; end; end; Result : True; end;注意事项自动安装系统组件如VC、.NET需要非常谨慎。务必从微软官方渠道获取安装包并使用正确的静默安装参数如/install /quiet /norestart。最好在安装前明确提示用户并给予选择权避免“流氓软件”的嫌疑。对于面向大众的游戏更常见的做法是在游戏商店页面如Steam或README中明确列出系统要求由用户自行准备环境。Steam等平台会自动处理这些依赖。4.2 自定义界面与美化Inno Setup默认界面是经典的Windows向导风格略显陈旧。通过[Setup]段的WizardImageFile和WizardSmallImageFile可以更换侧边栏图片。但真正的美化需要借助第三方插件或资源文件。使用WizardImageFile准备一张高约330像素宽约164像素的BMP图片作为安装向导左侧的大图。使用WizardSmallImageFile准备一张高约55像素宽约55像素的BMP图片作为窗口左上角的小图标。使用SetupIconFile指定安装程序文件.exe本身的图标。第三方皮肤Advanced社区有像“Inno Setup Toolbar Icons”或完全重写UI的插件如VCL Styles或ISSkin。这涉及到更复杂的DLL集成和脚本编写搜索“inno setup 美化”能找到大量教程和资源。对于大多数项目更换图片和图标已经足够提升观感。4.3 静默安装与命令行参数这对于自动化部署、通过管理软件批量安装非常有用。/SILENT或/VERYSILENT启动静默安装。/VERYSILENT连进度窗口都不显示。/SUPPRESSMSGBOXES抑制所有消息框。/NORESTART即使需要重启也禁止安装程序重启电脑。/DIR”x:\path\to\install”指定自定义安装目录。/GROUP”Folder Name”指定开始菜单文件夹名称。/TASKS”desktopicon”或/TASKS”!desktopicon”选择或取消选择特定任务。例如一个完整的静默安装命令可能是MyUnityGame_Setup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /DIR“C:\MyGames\MyUnityGame” /TASKS“desktopicon”在脚本中你可以通过{param:DIR|{pf}\...}来读取命令行传入的目录参数增加灵活性。4.4 版本升级与数据持久化这是一个关键但容易出错的部分。假设用户安装了1.0.0现在要安装1.0.1。关键保持AppId一致。这是Inno Setup识别为同一应用程序的唯一标识。使用[InstallDelete]段在安装新版本前删除旧版本中废弃的文件。例如1.0.1版本移除了一个旧的资源包OldAssetBundle.unity3d。[InstallDelete] Type: files; Name: “{app}\MyGame_Data\StreamingAssets\OldAssetBundle.unity3d”用户数据持久化游戏存档、配置文件通常不应放在安装目录{app}下因为卸载程序会删除整个目录。应该将它们存储在用户目录如{localappdata}\YourCompany\YourGame\。在Unity中可以使用Application.persistentDataPath来获取这个路径。安装包不需要处理这些文件它们由游戏自己管理。5. 完整脚本示例与编译流程让我们整合以上所有内容形成一个完整的、带注释的脚本示例。; 脚本保存为 MyUnityGame.iss ; 假设你的Unity构建输出在 ..\Build\MyUnityGame\ 目录下 #define MyAppName “我的Unity游戏” #define MyAppVersion “1.0.0” #define MyAppPublisher “我的工作室” #define MyAppURL “https://www.mywebsite.com” #define MyBuildPath “..\Build\MyUnityGame” ; 相对于此脚本文件的路径 [Setup] AppId{{A1B2C3D4-E5F6-7890-ABCD-EF1234567890} AppName{#MyAppName} AppVersion{#MyAppVersion} AppPublisher{#MyAppPublisher} AppPublisherURL{#MyAppURL} AppSupportURL{#MyAppURL} AppUpdatesURL{#MyAppURL} DefaultDirName{autopf}\{#MyAppPublisher}\{#MyAppName} DefaultGroupName{#MyAppName} ; 输出目录和文件名 OutputDirOutput OutputBaseFilename{#MyAppName}_Setup_{#MyAppVersion} ; 压缩设置 Compressionlzma2/ultra64 SolidCompressionyes ; 界面美化 WizardStylemodern SetupIconFileassets\setup_icon.ico WizardImageFileassets\wizard_image.bmp WizardSmallImageFileassets\wizard_small.bmp ; 许可文件 LicenseFilelicense.rtf [Languages] Name: “english”; MessagesFile: “compiler:Default.isl” Name: “chinesesimplified”; MessagesFile: “compiler:Languages\ChineseSimplified.isl” [Tasks] Name: “desktopicon”; Description: “创建桌面快捷方式”; GroupDescription: “附加快捷方式:”; Flags: unchecked [Files] ; 核心递归复制整个Unity构建文件夹 Source: “{#MyBuildPath}\*”; DestDir: “{app}”; Flags: ignoreversion recursesubdirs createallsubdirs ; 注意如果构建文件夹内有不需要分发的临时文件如.log, .bak建议在构建后清理或使用更精细的Source规则排除它们。 [Icons] Name: “{group}\{#MyAppName}”; Filename: “{app}\MyGame.exe” Name: “{group}\卸载 {#MyAppName}”; Filename: “{uninstallexe}” Name: “{commondesktop}\{#MyAppName}”; Filename: “{app}\MyGame.exe”; Tasks: desktopicon [Run] Filename: “{app}\MyGame.exe”; Description: “启动 {#MyAppName}”; Flags: postinstall nowait skipifsilent编译流程将上述脚本保存为.iss文件例如MyUnityGame.iss。确保MyBuildPath指向的Unity构建文件夹存在且内容完整。准备好assets文件夹下的图标、图片文件以及license.rtf许可文件。打开Inno Setup Compiler。点击菜单File-Open...选择你的.iss脚本文件。点击工具栏上的编译按钮F9。如果脚本没有语法错误编译将开始。你可以在下方的输出窗口看到进度。编译成功后安装程序将生成在脚本中OutputDir指定的目录本例中是Output文件夹下。6. 常见问题与排查技巧实录即使脚本写对了在实际打包和安装过程中也可能遇到各种问题。这里记录一些我踩过的坑和解决方案。6.1 游戏启动报错“找不到必要的DLL”或“应用程序无法正常启动(0xc000007b)”问题原因这是最常见的问题。根本原因是安装包没有包含Unity构建输出的所有必要文件或者文件结构被破坏。排查步骤检查[Files]段确认使用了recursesubdirs和createallsubdirs标志并且源路径正确。最稳妥的方式是使用通配符*复制所有。对比文件夹在安装完成后打开安装目录如C:\Program Files\MyStudio\MyUnityGame将其与原始的Unity构建输出文件夹进行逐项对比。文件数量和大小是否一致MyGame_Data文件夹里的内容是否完整检查杀毒软件有些激进的杀毒软件可能会误删Unity生成的可执行文件或DLL。尝试将整个构建文件夹和生成的安装包添加到杀毒软件的白名单中。依赖项问题虽然IL2CPP减少了依赖但某些第三方原生插件可能需要特定的VC运行库。尝试在目标机器上安装最新的 Visual C Redistributable 。6.2 安装包体积过大问题原因Unity构建的Data文件夹尤其是Resources和StreamingAssets可能包含大量未压缩的资源。Inno Setup的lzma2压缩对某些已压缩格式如.jpg, .mp3, .unityweb效果有限。优化方案Unity端优化这是根本。检查Unity构建日志使用AssetBundle启用Player Settings中的压缩选项如LZ4HC优化纹理、音频格式和大小。Inno Setup端优化在[Files]段为已经高度压缩的文件类型添加nocompression标志。但这需要手动列出所有这类文件比较麻烦。一个折中的办法是如果安装速度比安装包大小更重要可以尝试使用压缩率稍低但更快的算法如zip/2。分卷压缩对于超大型游戏Inno Setup支持创建分卷安装包[Setup]段设置DiskSpanningyes可以刻录到多张光盘或分多个文件下载。6.3 安装或卸载时提示“文件正在被使用无法删除”问题原因卸载程序或安装升级程序试图删除或覆盖一个正在被系统或其他进程锁定的文件。常见于游戏没有完全退出进程仍在后台。杀毒软件或文件索引服务正在扫描游戏文件。解决方案重启资源管理器有时是Windows资源管理器预览窗格锁定了文件。结束explorer.exe进程再重启。使用RestartReplace标志在[Files]段对可能被锁定的关键文件如主exe核心dll使用Flags: restartreplace。这会在文件被锁定时安排在下一次系统重启时替换。在卸载前关闭程序在[UninstallRun]段尝试运行一个命令来结束游戏进程但这通常不可靠因为卸载程序本身可能没有权限。用户教育在卸载前提示用户“请确保游戏已完全关闭”。6.4 如何为32位和64位系统制作统一安装包Unity可以分别构建x86和x64版本。Inno Setup可以制作一个同时包含两者并根据系统架构自动安装正确版本的安装包。思路将两个版本的构建输出放在不同的子文件夹如Build\x86和Build\x64。在[Files]段使用Check参数和Is64BitInstallMode函数来判断。示例脚本片段[Files] ; 根据系统架构复制不同的文件 Source: “Build\x64\*”; DestDir: “{app}”; Check: Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirs Source: “Build\x86\*”; DestDir: “{app}”; Check: not Is64BitInstallMode; Flags: ignoreversion recursesubdirs createallsubdirsIs64BitInstallMode在64位系统上返回True即使安装的是32位模式。IsWin64检查操作系统是否是64位。通常对于Unity游戏我们根据系统位数安装对应的版本所以使用Is64BitInstallMode是合适的。6.5 安装界面语言为英文如何汉化Inno Setup支持多语言。默认安装后在安装目录的Languages文件夹下可以找到.isl语言文件。将ChineseSimplified.isl简体中文文件复制到你的脚本所在目录或一个专门的Languages子目录。在脚本的[Languages]段添加一行Name: “chinesesimplified”; MessagesFile: “compiler:Languages\ChineseSimplified.isl”。如果你把文件放在自定义位置路径要相应修改如“ChineseSimplified.isl”。重新编译安装程序启动时就会让用户选择语言或根据系统语言自动选择。最后一个最朴素的建议在虚拟机或一台干净的测试机上测试你的安装包。从下载、运行安装程序、每一步选择、到安装后启动游戏、创建和删除快捷方式、最后卸载走完整个流程。这是发现潜在问题的唯一可靠方法。打包看似是开发的最后一步却是用户接触你产品的第一步这一步的体验至关重要。