Qwen Code 桌面客户端品牌化构建白标实操:Tauri 壳 + brandId + Logo 快速生成品牌安装包
2026/9/20 21:20:08 网站建设 项目流程

Qwen Code 桌面客户端品牌化构建白标实操:Tauri 壳 + brandId + Logo 快速生成品牌安装包

【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code

客户提需求:“把 Qwen Code 桌面客户端装进我们自己的产品,换名字、换图标、换启动页,要改多少东西?”Qwen Code 仓库内置的 Desktop Brand Builder 技能把桌面客户端品牌化构建压缩成了一件两分钟的事:给一个brandId加一张 logo,基于 Tauri 的桌面壳就能被白标/换肤成带自己名字的应用、一整套图标、品牌启动页,以及对应的安装包。

全景图:3 个品牌挂载点 × 1 个零依赖脚本

Qwen Code 的桌面实现是 packages/desktop-shell 下的 Tauri 壳(Electron 时代的packages/desktop已移除),品牌信息全部集中在三处:

挂载点承载内容品牌化时改动什么
src-tauri/tauri.conf.jsonproductNameidentifier、updater 配置应用名、bundle identifier、更新源
src-tauri/icons/应用图标全家桶用品牌 logo 重建整套尺寸
bootstrap/ 启动 UIindex.html、bootstrap.js、logo svg启动页标题、启动文案、logo 引用

驱动这三个挂载点的只有一个零依赖脚本 brand-create.mjs(Node ≥ 18,无外部依赖):输入--shell-root加一份brand.json,输出 JSON 报告。技能全文定义在 SKILL.md。壳内部跑的是 Qwen Code Web Shell:

开工前准备:依赖与独立构建克隆

  • Node ≥ 18:品牌脚本零依赖;打包阶段还需要 Tauri 自己的构建链(Rust 工具链)。
  • 两处npm installbuild:runtime会回调仓库根部的构建(依赖根部 devDependencies 如cross-env、esbuild),所以根部依赖与 desktop-shell 依赖缺一不可:
npm install # 根部依赖 cd packages/desktop-shell npm install --workspaces=false # desktop-shell 依赖 cd ../..
  • 独立克隆、独立目录:品牌补丁不可逆,日常仓库不能拿来直接改,每个品牌给一个全新克隆:
BUILD_ROOT="$PWD/brand-builds/acme-ai-20260919" mkdir -p "$BUILD_ROOT" git clone --branch main --single-branch \ https://gitcode.com/GitHub_Trending/qw/qwen-code \ "$BUILD_ROOT/qwen-code" cd "$BUILD_ROOT/qwen-code" git checkout -B brand-acme-ai origin/main

clone 或 checkout 失败就停在这里报告,不要假装分支已创建继续往下走。

实操流程:从 brand.json 到安装包

第一步,写 brand.json。必填只有两项:brandId(须匹配^[a-z][a-z0-9-]*$)和logo(存在的本地文件,推荐 ≥ 1024px 方形 PNG)。其余字段都有确定性推导,全程拿acme-ai走一遍:

{ "brandId": "acme-ai", "logo": "/absolute/path/to/logo.png", "website": "https://acme.ai", "appName": "Acme AI", "appId": "ai.acme.desktop", "artifactPrefix": "Acme-AI", "updaterEndpoints": [], "updaterPubkey": "" }
  • appName:按短横线切段、逐段首字母大写、空格连接 →Acme AI
  • artifactPrefix:同样大写处理但用短横线连接 →Acme-AIai这类词在内置缩写集(ai/api/cli/ide/sdk/ui/url)里会整体大写,所以是Acme AI而不是Acme Aiacme-cli会得到Acme CLI
  • appId:取website的 host、去掉www.前缀、标签反转再追加.desktophttps://acme.aiai.acme.desktop;host 不足两段时回退为app.acme-ai.desktop
  • updaterEndpoints:默认空数组,即关闭应用内更新——这是刻意的设计,品牌包与官方更新源彻底隔离(见踩坑第 3 条)。

第二步,跑品牌脚本:

node packages/desktop-shell/.agents/skills/desktop-brand-builder/scripts/brand-create.mjs \ --shell-root /absolute/path/to/qwen-code/packages/desktop-shell \ --config /absolute/path/to/brand.json

脚本按顺序完成三个补丁:改写tauri.conf.json(应用名、identifier、短描述、updater 端点)、从 logo 重建整套图标、替换 bootstrap 的品牌字符串与 logo 引用。成功时打印一份 JSON 报告(appNameappIdartifactPrefixiconsbootstrapPatched等),直接拿它当交付摘要。脚本在手就不要手工去改tauri.conf.json和图标文件——它是打补丁的唯一权威。

第三步,打包:

cd packages/desktop-shell npm run build:runtime --workspaces=false # 按宿主平台捆绑 Node 运行时 npx tauri build # 当前平台

产物落在src-tauri/target/release/bundle/下,子目录dmg/(macOS)、nsis/(Windows)、appimage/deb/(Linux),对应 tauri.conf.json 里声明的 bundle targets;交叉编译则是src-tauri/target/<triple>/release/bundle/

三个补丁背后的设计动机

脚本可信,是因为它把几个容易出事的边角都提前处理了。

pubkey 置空字符串,而不是删字段。tauri-plugin-updater的 schema 声明pubkey: String且没有 serde 默认值——把字段整个删掉,应用启动时反序列化直接失败;而端点为空时,空字符串 pubkey 意味着根本不会跑更新检查,无害。

缺 updater 段时 fail closed。如果品牌提供了端点或公钥,但目标tauri.conf.json里没有plugins.updater段(fork 或手改过的 shell-root 就可能缺),脚本在任何文件写盘前就报错退出。否则报告会显示“已应用”,实际交付的却是一个永远无法更新的品牌包。

logo 以 argv 传递,不经过 shell。脚本先用require.resolve直接定位 Tauri CLI 入口,再以spawnSync(process.execPath, [...])调用,logo 路径只是普通 argv 元素,不经过任何命令解释器——文件名里带$(cmd)或反引号也不会触发注入。

JS/HTML 两种语境分别转义。bootstrap.js里应用名在单引号字符串内,先经JSON.stringify完整转义(只转单引号不够:Bob's App\这种以反斜杠结尾的名字会“逃逸”掉结束引号);index.html里则按&<>"'做 HTML 实体转义,先转&避免二次转义。两处替换都用函数式 replacer,防止$&之类的模式被展开。

汇总成一张输入 → 校验 → 行为表:

输入校验规则不满足时行为
brandId匹配^[a-z][a-z0-9-]*$立即报错,不写任何文件
logo文件存在,扩展名在 png/jpg/jpeg/svg/ico/webp 内立即报错
updaterEndpoints非空必须同时提供updaterPubkey立即报错——否则每次更新签名校验都失败
appName不得等于Qwen Code Desktop立即报错——等于默认值会使单次使用守卫失效
提供 updater 配置,但目标无plugins.updaterfail closed,一个文件都不写
Tauri icon CLI 不可用logo 为 PNG 时兜底只替换icons/icon.png,警告其余尺寸仍是旧 logo

踩坑手册:四个容易翻车的点

交叉编译为什么必须逐目标重跑 build:runtime

  • 现象:交叉编译出的安装包能装上,启动即报 exec format error;
  • 原因:prepare-runtime.js 按QWEN_DESKTOP_TARGET环境变量(默认宿主平台)下载并捆绑对应平台的 Node 运行时。换目标后不重跑,装进产物的是错误架构的 Node 二进制;
  • 解法:每次tauri build --target前都带着环境变量重跑一次:
QWEN_DESKTOP_TARGET=aarch64-apple-darwin npm run build:runtime --workspaces=false npx tauri build --target aarch64-apple-darwin

该变量接受aarch64-apple-darwin等 Rust triple(共五个受支持目标,不支持的直接抛错)。target: all就按“build:runtime → tauri build”逐目标迭代,且只跑当前机器或 CI 支持的目标——文件真实存在之前,不要声称产出了跨平台产物。

单次使用守卫:同一克隆里不能重跑脚本

  • 现象:第二次运行被拒,提示 shell 已品牌化;
  • 原因:守卫检测productName是否仍为Qwen Code Desktop。bootstrap 补丁依赖原始字面量,pubkey/endpoints 的变更也无法回滚,重跑会在品牌文件里重复拼接字符串;
  • 解法:每个品牌一个全新克隆;brand.json写错了就丢弃整个克隆重来,而不是在补丁过的树上“修补”。

品牌包与官方更新源彻底隔离

  • 现象:默认配置的品牌包完全不会轮询更新;
  • 原因:设计上品牌包永远不得轮询官方 Qwen Code 更新源,官方更新源也永远不得更新品牌包;端点为空时脚本还会同步关掉bundle.createUpdaterArtifacts,避免 Tauri bundler 继续产出没人消费的签名更新产物;
  • 解法:需要应用内更新时自建更新源,把updaterEndpoints指向它,updaterPubkey配签名用的公钥。

签名与自建更新源:密钥对必须自备

  • 现象:品牌构建默认不签名,直接分发就是未签名包;
  • 原因:上游发布流水线的 Apple/Windows 签名密钥与更新私钥只属于官方 Qwen Code 发布,复用等于拿别人的身份发自己的包;
  • 解法:自己生成一对:
npx @tauri-apps/cli signer generate -w ~/.tauri/my-brand.key

.key是私钥,放进构建 CI 作为TAURI_SIGNING_PRIVATE_KEY.pub里的 base64 公钥填入brand.jsonupdaterPubkey。两者必须配对——更新器用这把公钥校验每个更新签名,配错或缺失都会让应用永远无法更新。

交付前验收:产物、指纹与上报项

验收项动作
产物位置确认在src-tauri/target/release/bundle/(交叉编译为src-tauri/target/<triple>/release/bundle/),子目录应为dmg/nsis/appimage/deb/
指纹对每个产物算sha256sum(macOS 用shasum -a 256
DMG 完整性macOS 上对 DMG 跑hdiutil verify
上报内容产物路径、SHA-256、应用名、appId、构建目录
构建失败时保留构建目录供事后排查,返回最后有用的错误行与完整日志路径;不删目录,也不在同一克隆里重试品牌步骤

写在最后

白标换肤场景,一份brand.json加一个零依赖脚本就能覆盖“名字、图标、启动页”三个挂载点;需要应用内更新时,再叠加自备的签名密钥对和自建更新源即可——而整个流程不会触碰官方更新分发的任何一个字节。

【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询