独辟蹊径 —— 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 英文系统下顺利打包。
相关推荐
阿笑带你学前端4 小时前
当手机遇上电视:Flutter实现局域网遥控输入的奇妙之旅
前端·flutter
早起的年轻人4 小时前
Flutter 3.35.2 以上版本中 数字转字符串的方法指南
前端·flutter
深兰科技13 小时前
深兰科技AI问诊助手走访打浦桥街道社区卫生服务中心
人工智能·windows·github·postman·visual studio·深兰科技·ai问诊
ajassi200014 小时前
开源 C++ QT Widget 开发(十一)进程间通信--Windows 窗口通信
linux·c++·windows·qt·开源
PEI0418 小时前
Java集合遍历的方法有哪些
java·windows·python
vortex518 小时前
Windows 电源管理和 Shutdown 命令详解
windows·stm32·命令行
tangweiguo0305198718 小时前
Flutter代码生成:告别重复劳动,效率飙升
flutter
AGG_Chan19 小时前
flutter专栏--深入剖析你的第一个flutter应用
前端·flutter