独辟蹊径 —— NSIS 自定义 EXE 应用名称

一、背景

开发的桌面应用要求对应用名称进行多语言个性化:

  1. 支持多语言安装环境:

    • 中文环境生成程序入口为 中文应用.exe
    • 其他语言环境生成程序入口为 AppEN.exe
  2. 安装包在安装后,快捷方式、任务管理器显示的进程名需对应语言环境。

  3. 用户数据、SharedPreferences(SP)、数据库等持久化存储路径需保持一致,不随程序入口名称变化,保证原有逻辑不受干扰,最小程度侵入;

  4. CI/CD 流程基于 Jenkins,需要支持远程自动打包。

二、遇到的问题记录

1. NSIS 中文语句报错

最初尝试在 NSIS 脚本中直接使用中文程序名:

nsis 复制代码
OutFile "中文应用.exe"
CreateShortCut "$DESKTOP\中文应用.lnk" "$INSTDIR\中文应用.exe"

或者直接重命名 exe

nsis 复制代码
File "${EXE_NAME}"
Rename "$INSTDIR\${EXE_NAME}" "$INSTDIR\中文应用.exe"

问题现象

  • 本地编译正常,但 Jenkins 执行构建时失败
  • 错误信息多为 "Invalid character set" 或找不到文件

原因分析

  • NSIS 默认 ANSI 编码,如果脚本中包含中文字符,在英文系统或 Jenkins 执行环境(通常非中文)下无法正确解析
  • 中文字符可能在 UTF-8 或系统默认编码下被误处理,导致编译失败

2. CMake 多 EXE 输出

尝试在 CMake 中配置多程序入口:

camke 复制代码
cmake_minimum_required(VERSION 3.15)
project(MyApp)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# 原始可执行文件
add_executable(myapp main.cpp)

# 生成多语言版本(仅重命名副本,避免在 NSIS 内部硬编码中文)
add_custom_command(TARGET myapp POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy
        $<TARGET_FILE:myapp> ${CMAKE_BINARY_DIR}/bin/myapp_en.exe
    COMMAND ${CMAKE_COMMAND} -E copy
        $<TARGET_FILE:myapp> ${CMAKE_BINARY_DIR}/bin/myapp_zh.exe
)

问题现象

  • 构建阶段可以生成多个 EXE(中文应用.exeEnglish App.exe
  • 安装界面文本仍然固定
  • 程序启动及任务管理器显示名称不稳定
  • SP、数据库等存储路径未受影响,但在某些安装目录下出现权限或访问异常

原因分析

  • CMake 对 RUNTIME_OUTPUT_NAME 的编码依赖系统环境,中文名称在 Jenkins 或英文环境下可能无法正确生成
  • 即便 EXE 成功生成,NSIS 拷贝或快捷方式创建过程中仍可能因中文文件名报错

3. CMake 多 EXE 输出 + LangString

Tips

安装界面多语言采用 NSIS 官方推荐的 LangString 机制: Reference/LangString - NSIS

  • LangString 定义一组以 语言 ID 区分的字符串常量
  • 在运行时,NSIS 会根据用户选择的安装语言自动切换对应的字符串
  • 使用时通过 $(变量名) 引用,而不是直接写死在脚本里

具体实现

根据安装平台拷贝 exe

nsis 复制代码
  ${If} $LANGUAGE == ${LANG_SIMPCHINESE}
    File /oname=$(EXE_NAME_LOCALIZED) "..\build\windows\x64\runner\${BT}\中文应用.exe"
  ${ElseIf} $LANGUAGE == ${LANG_TRADCHINESE}
    File /oname=$(EXE_NAME_LOCALIZED) "..\build\windows\x64\runner\${BT}\中文应用.exe"
  ${Else}
    File /oname=$(EXE_NAME_LOCALIZED) "..\build\windows\x64\runner\${BT}\AppEN.exe"
  ${EndIf}

安装界面多语言

nsis 复制代码
!include MUI2.nsh

!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "SimpChinese"

; 定义不同语言下的应用名称
LangString APP_NAME ${LANG_ENGLISH} "AppEN"
LangString APP_NAME ${LANG_SIMPCHINESE} "我的应用"

Section "Install"
  ; 在快捷方式创建中引用 LangString
  CreateShortcut "$DESKTOP\$(APP_NAME).lnk" "$INSTDIR\myapp.exe"
SectionEnd

效果验证

  • 不论 Jenkins 或本地环境,NSIS 编译均可通过
  • 安装后,中文系统显示 中文应用.exe,英文系统显示 AppEN.exe
  • 任务管理器显示名称符合语言环境
  • 用户 SP、数据库路径保持不变,不受 EXE 重命名影响

原因分析

  • LangString 内部使用 Unicode 编码,支持多语言环境安全解析
  • 避免了在 NSIS 脚本中直接书写中文字符,兼容 Jenkins 的英文系统环境

三、最终构建流程

flowchart TD A["用户运行安装程序"] --> B["NSIS 检测系统语言($LANGUAGE)"] B --> C{"语言判断分支"} C -->|LANG_SIMPCHINESE| D["选择 '中文应用.exe'"] C -->|LANG_ENGLISH默认| F["选择 'AppEN.exe'"] D --> G["LangString 动态设置界面文本和文件名"] F --> G G --> H["File /oname=$(EXE_NAME_LOCALIZED)\n复制对应 exe"] H --> I["创建快捷方式\n$(PRODUCT_NAME_LOCALIZED).lnk"]
  1. Flutter build

    • 执行 flutter build windows,生成默认 EXE。
    • 使用 CMake 配置生成多语言输出(可选,作为中间文件管理)。
  2. NSIS 安装包生成

    • 脚本中使用 LangString 定义不同语言的 EXE 名称。
    • 拷贝构建生成的 EXE,并在安装目录重命名。
    • 创建语言对应的快捷方式。
  3. 持久化数据路径管理

    • Flutter 应用中 SP、数据库路径固定使用 AppData\Roaming\MyApp 或其他固定路径。
    • 重命名 EXE 不影响数据访问。
  4. Jenkins CI/CD

    • Jenkins 执行 NSIS 脚本时,无需额外修改系统语言环境。
    • 编译流程全程 Unicode 安全。

四、总结与建议

graph TD A[Flutter项目] --> B[flutter build windows] B --> C[CMake配置] C --> D[生成两个exe: AppEN.exe & AppCN.exe] D --> E[NSIS安装脚本] E --> F{系统语言环境判断} F -->|中文环境| G[设置名称为 中文命名.exe] F -->|其他语言| H[设置名称为 AppEN.exe] G --> I[拷贝文件到安装目录] H --> I I --> J[创建桌面快捷方式] J --> K[保持用户数据路径一致性] K --> L[安装完成] %% 问题说明 M[NSIS中文命名兼容性问题] --> D N[多exe生成配置] --> C O[LangString多语言解决方案] --> F
  1. NSIS 不直接使用中文字符:避免编码问题,特别是 CI/CD 英文系统环境。
  2. 使用 LangString 实现多语言文件名:安全可靠,支持简繁中文及英文。
  3. CMake 输出多 EXE 可选:主要用于本地或调试环境,生产安装包依赖 NSIS 重命名更稳定。
  4. 持久化路径固定:保证用户数据、SP、数据库不随 EXE 名称变化,提升跨语言环境兼容性。
  5. CI/CD 环境安全:Unicode + LangString 可以在 Jenkins 英文系统下顺利打包。
相关推荐
jyOverQ3 小时前
ChatGPT Windows 客户端点击无反应、有进程却没窗口?一次 MSIX 非系统盘启动卡死的完整排查
windows·chatgpt
未来猫咪花3 小时前
Everything is ViewModel:让状态管理回到对象世界
android·flutter·ios
Flutter OH4 小时前
Flutter OH 日志抓取与过滤指南
flutter
Flutter OH4 小时前
Flutter OH 内存与 GPU 问题定位指南
flutter
Flutter OH5 小时前
Flutter OH 多设备适配问题定位指南
flutter
还是大剑师兰特6 小时前
MySQL8.0 Windows完整安装教程
windows·mysql·大剑师
律宏阔6 小时前
Flutter Hooks 与 flutter_map_animations 冲突:第二次地图动画报错的解决方案
flutter
redfred8 小时前
HandBrake 使用教程:开源视频压缩工具 视频太大压缩 MKV转MP4 批量转码 硬件加速 Windows/macOS/Linux
windows·开源·音视频
kakakahahahaha8 小时前
【Windows】C盘拒绝访问0x80070005的7步排查
windows·电脑·内容运营·软件需求
Flutter OH10 小时前
Flutter OH 卡死冻屏问题定位指南
flutter·命令模式