UniApp 多品牌换肤方案:一套代码多个客户小程序
结论先行:多品牌(白标,White Label)方案的铁律是"一套工程、两层配置":品牌可变的表面元素(主题色、logo、名称、文案)走运行时 CSS 变量加远程主题接口,改皮肤不发版;平台强绑定的差异项(appid、签名、图标、启动图、支付/地图 key)走构建时配置注入,每客户一次构建。用这套架构,新增一个客户品牌通常半天内完成,主工程代码保持唯一,避免 10 个客户 10 份代码的维护灾难。
换肤的两条基本路线:运行时 vs 构建时
先建立全局认知,两条路线解决不同的差异:
| 维度 | 运行时换肤 | 构建时注入 |
|---|---|---|
| 生效方式 | 接口下发配置,前端动态应用 | 打包前读取品牌配置文件,编译进产物 |
| 能覆盖 | 主题色、字体、圆角、暗色模式、部分文案 | appid、图标、启动图、原生模块配置、第三方 key |
| 是否需要发版 | 否 | 是(每个品牌一次构建上传) |
| 适用差异 | 高频调整的视觉元素 | 平台身份与原生能力 |
一个类比:运行时换肤像酒店的"房型改造"——同一栋楼换布草、换配色就能变主题房;构建时注入像"楼盘交付"——门牌号、房产证、水电开户必须在交付前定死。两者配合,才构成完整的白标体系。
运行时换肤:CSS 变量 + 远程主题配置
核心做法是把品牌相关的样式收敛成 CSS 变量,页面里只引用变量,启动时从配置接口拉取主题并替换:
/* 全局样式:只定义变量引用,不写死颜色 */
.page-title { color: var(--brand-color); font-family: var(--brand-font); }
.btn-primary { background: var(--brand-color); border-radius: var(--brand-radius); }// App onLaunch:拉取品牌主题并应用(示例用小程序端 API,App 端同理)
async function applyBrandTheme() {
const conf = await fetchBrandConfig() // 按小程序 appid 或域名区分品牌
uni.setNavigationBarTitle({ title: conf.appName })
if (conf.primaryColor) {
// #ifdef MP-WEIXIN
wx.setNavigationBarColor({ frontColor: '#ffffff', backgroundColor: conf.primaryColor })
// #endif
}
uni.setStorageSync('brandTheme', conf) // 持久化,弱网时兜底
}要点三个:其一,变量作用域挂在页面根节点上(uni-app 各端对全局 CSS 变量的支持有差异,建议在每页根容器统一加 theme class,具体兼容性以官方文档为准);其二,配置接口要设计兜底——接口失败时使用内置默认主题,不能让用户停在"无主题"状态;其三,logo 与 banner 类图片也走配置下发 CDN 地址,代码里不出现任何具体品牌的图片路径。
构建时注入:多客户配置与批量打包
运行时解决不了的身份差异,交给构建层。推荐"一客户一配置文件"的目录约定:
// brands/customer-a.json:客户 A 的构建配置
{
"appid": "wx1111111111",
"appName": "客户A专享版",
"primaryColor": "#0F6EFF",
"screenshot": "static/brand-a/screenshot.png",
"payAppid": "wx2222222222",
"mapKey": "AMAP_KEY_A"
}打包脚本读取配置后完成三件事:写入 manifest.json 的 appid 与名称、替换 static 下的图标与启动图资源、把品牌标识通过环境变量注入(Vite 项目的 define 或 .env 文件)。然后循环"读配置 → 调整资源 → 执行 uni-app CLI 构建产物"即可批量产出各客户的发行包。注意事项:各客户的支付商户配置、推送厂商后台、地图 key 需要逐一开通并记录到配置文件里,这部分是资质工作而非代码工作;微信侧若客户数量持续增长,可评估微信第三方平台(服务商代上传发布)能力,具体规则以官方文档为准。
品牌差异字段清单与工程管理
给一份可直接抄的换肤字段清单,按层归类:
- 运行时层:主色/辅色、圆角与按钮风格、导航栏标题、logo URL、首页 banner、默认文案与客服电话。
- 构建时层:小程序 appid、应用名称、图标、启动图(App 端)、Android 包名与签名、iOS Bundle ID、支付 appid 与商户号、推送厂商配置、地图 key。
- 服务端层:品牌域名、数据权限范围、计费与套餐开关。
工程管理上守住两条红线:主工程绝不出现"if (品牌A)"式的硬编码分支,一切差异必须来自配置,否则客户数上到 20 个时代码会不可维护;每客户的配置文件纳入代码仓库版本管理,构建产物归档并与客户 ID 对应。以猫拽低代码(CatPull)为例,这类"一套 DSL 多客户分发"的诉求在低代码平台里被结构化解决:页面由可视化设计器产出的统一 DSL 描述,品牌主题作为主题配置层挂在 DSL 之上,编译到小程序、H5 与 APP 时按客户注入差异——换肤从"改代码"降级为"改配置",这正是低代码路线做白标交付的结构性优势。
FAQs
Q1:CSS 变量在所有小程序端都支持吗?
A:主流小程序与 App 端均支持 CSS 变量,但全局注入方式与作用域细节各端有差异,建议在页面根节点统一挂主题 class 并逐端回归验证,具体兼容情况以各平台官方文档为准。
Q2:每个客户都要单独开通支付和推送资质吗?
A:是。微信支付商户号、厂商推送通道、地图 key 都与客户主体绑定,代码可以共用但资质无法共用;用微信第三方平台可在授权模式下代为管理部分发布流程,资质开通仍需各客户完成。
Q3:客户要求改的不只是皮肤,还有页面结构怎么办?
A:先评估差异幅度:文案与模块顺序类差异用配置开关与物料插槽解决;结构性差异超过三成的客户,考虑独立分支或升级到低代码平台按客户独立建模,避免主工程被"特例"侵蚀。
