Uni-App 实战 SOP
一、使用说明
本 skill 是 uni-app 项目实战操作手册,沉淀了跨平台项目(微信小程序 + Android/iOS APP + H5)从开工准备到上线验收的全流程经验。
使用原则:
- 先读本文 → 确定任务类型 → 按路由表加载对应 reference
- 配合通用
uni-app skill 获取框架 API 细节
- 所有改动前必须:确认目标子项目 → 确认目标平台 → 阅读最近 README.md 和 package.json → 检查真实调用链和当前配置
- 优先使用项目中已集成的成熟方案(官方 uni-app API、DCloud 插件、现有本地 helper),不手写平台桥接层
- 改动范围限定在相关层,运行最小验证命令
二、快速决策树
我要做 App 推送
任务类型?
├── 首次配置 UniPush 2.0 → references/UniPush2.0配置小白文档.md
├── 推送收不到,排查问题 → references/APP定位与UniPush2.0小白排查手册.md
├── 检查当前项目推送状态 → references/UniPush2.0整体跑通检查结论.md
├── 发包前权限检查 → references/APP定位与UniPush2.0权限配置检查清单.md
└── 理解底层架构/升级 → references/DCloud官方通知方案源码级说明.md
我要做微信小程序订阅消息
→ references/微信小程序订阅消息配置小白操作手册.md
我要做 App 后台定位
├── 排查定位问题 → references/APP定位与UniPush2.0小白排查手册.md
├── 发包前权限检查 → references/APP定位与UniPush2.0权限配置检查清单.md
我要发包/上架
├── 理解发布流程 → references/release-and-verification-sop.md
├── 权限配置检查 → references/APP定位与UniPush2.0权限配置检查清单.md
├── 了解需要准备的资料 → references/uni小程序+APP的全程经验案例分享.md
我遇到了某个具体 Bug
├── 常见陷阱速查 → references/pitfalls-and-debugging.md
└── 全链路排查思路 → references/uni小程序+APP的全程经验案例分享.md(第15节)
三、官方文档验证记录
以下发现基于 2026-07-19 对 uni-app/DCloud/HBuilder 官方文档的实际查阅。当 reference 内容与官方最新文档有出入时,以此处记录为准。
3.1 UniPush 2.0 厂商通道配置
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
| 厂商参数存放位置 |
references 提及 manifest.json 中厂商参数为空对象,视为风险 |
厂商推送参数在 DCloud 开发者中心 (dev.dcloud.net.cn) 配置,不在 manifest.json 中。manifest.json 仅用于开启 Push 模块和选择 uni-push 版本 |
manifest.json 的空对象 hms: {} 等是正常的占位,不应视为配置缺失。真正的厂商配置状态应去 DCloud 后台确认 |
offline 字段 |
多处讨论 offline: true |
官方文档描述为勾选框(开启/关闭离线推送),勾选后会打包个推原生 SDK |
仅开启 offline: true 不意味着离线推送已跑通,这只是客户端的必要条件之一 |
| 荣耀 (Honor) 通道 |
references 中列为需配置项 |
uni-push 主文档中未列出 Honor 为独立厂商 |
Honor 仍需在 DCloud 后台配置,但需确认当前官方支持状态 |
| 服务空间绑定 |
references 未强调 |
UniPush 2.0 开通时必须绑定 uniCloud 服务空间,即使后端不在 uniCloud |
必须在 uni-app 项目中创建 uniCloud 环境并绑定 |
3.2 uni-cloud-s2s 鉴权
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
| hashMethod 可选值 |
提到 hmac-sha256 是推荐值 |
官方支持 4 种:md5, sha1, sha256, hmac-sha256。默认 hmac-sha256 |
references 中关于 "sha256 实际调用 md5" 的描述如属实,可能是特定已安装版本 (v1.0.1) 的 bug,官方文档未记录此问题。升级后需重新审计 |
| HMAC 签名串格式 |
未明确 |
hmac-sha256:签名字符串 = timestamp\npayloadStr(不含 signKey 在签名串末尾)hash 方法(md5/sha1/sha256):签名字符串 = timestamp\npayloadStr\nsignKey |
references 中 NestJS 侧实现应按此格式 |
| JSON 签名字段筛选 |
正确描述了"只纳入顶层基础类型" |
官方确认:仅 string/number/boolean 进入签名,对象和数组被排除 |
✓ 正确 |
| connectCode 模式 |
references 未提及 |
官方还提供更简单的 connectCode 共享密钥模式,适合内网服务间调用 |
可考虑安全性要求不高的场景使用 |
3.3 客户端 Push API
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
uni.createPushMessage |
描述为"本地系统通知兜底" |
官方定义:创建本地通知栏消息。参数包括 title(可选)、content(必填)、payload、icon、sound、cover、delay、when、channelId、category |
✓ 用法正确,HBuilderX 3.5.2+ |
uni.getChannelManager |
references 未提及 |
Android 8.0+ / HBuilderX 4.02+,可创建和管理通知渠道,渠道一旦建立不可修改配置(即使删除重建也无效) |
这是重要约束,应加入 references |
uni.setAppBadgeNumber |
未覆盖 |
仅鸿蒙 (HarmonyOS) 支持,iOS/Android 使用 plus.runtime.setBadgeNumber |
- |
uni.offPushMessage |
未覆盖 |
可移除推送消息监听,不传参数时移除所有监听器 |
- |
3.4 登录 API
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
| 支付宝 App 登录 |
使用第三方插件 DHQ-AlipayAuth |
官方 uni.login 不直接支持支付宝 App 登录,需通过插件市场或 UTS 原生插件 |
✓ 使用插件的做法是正确的 |
| 微信 App 登录安全性 |
references 未强调 |
HBuilderX 3.4.18+ 移除了 manifest.json 可视化 appsecret 配置,建议使用 onlyAuthorize: true 在后端换 token,避免 appsecret 泄露 |
应推荐 onlyAuthorize: true 方案 |
| Apple 登录 |
references 正确 |
uni.login({ provider: 'apple' }) 返回 appleInfo |
✓ 正确 |
3.5 隐私合规
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
androidPrivacy.json |
多处提及,已描述主要字段 |
HBuilderX 3.2.1+ 引入,核心字段:version、prompt ("template"/"none"/"custom")、title、message、buttonAccept、buttonRefuse、hrefLoader、backToExit、second、disagreeMode、styles |
✓ 正确 |
template vs custom 模式 |
使用 template 模式 |
官方明确建议:先用 template 模式,custom 模式不能完全阻止隐私弹窗前的设备信息读取(第三方 SDK 在应用启动时就初始化) |
✓ 使用 template 是正确的 |
pushRegisterMode |
references 中多处写为 android.pushRegisterMode = "manual" |
⚠️ 官方 manifest schema 中 pushRegisterMode 属于 ios 节点,Android 不存在该字段。Android 隐私合规通过 androidPrivacy.json template 模式实现 |
已统一修正:ios.pushRegisterMode = manual(控制 iOS 通知权限弹窗);Android 用 template 阻断 |
enableOAID |
正确描述为 HBuilderX 3.8.5+ 新增字段 |
确认在 app-plus.distribute.android.enableOAID,默认 true。设为 false 排除旧版 OAID SDK (v1.0.13) |
✓ 正确 |
3.6 后台定位
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
uni.startLocationUpdateBackground |
用于微信小程序后台定位 |
uni-app 没有跨平台的 startLocationUpdateBackground API。微信小程序有自己的后台定位 API,App 平台需要原生插件或第三方方案 |
✓ references 使用 sup-gpslocation 插件是正确的,但需标注这不是 uni-app 内置 API |
| Android 后台定位可靠性 |
正确描述了"进程可能被杀" |
官方明确:Android 进程被杀后代码无法执行,方案建议使用 "保活" 插件 + uni-push 兜底 |
✓ 产品承诺边界应如实告知用户 |
3.7 统一推送网关
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
| 推送主链路 |
"NestJS 编排 + uniCloud 统一推送网关" |
UniPush 2.0 唯一支持的服务端方案是 uniCloud uni-cloud-push 扩展库,不提供 MasterSecret,不支持直连个推 REST API(那是 UniPush 1.0 已废弃方案)。非 uniCloud 后端需要创建云函数 URL 化后通过 HTTP 调用 |
⚠️ 关键发现:UniPush2.0配置小白文档.md 描述的"后端直连个推 REST API"是 UniPush 1.0 的废弃方案,不应在新项目中使用。当前项目应只保留 uniCloud push-gateway 这一条主链路 |
uni-cloud-push 运行环境 |
正确描述为"只能在 uniCloud 云函数运行时使用" |
官方确认:uniCloud 是云函数运行时注入的全局对象,普通 Node.js 不可用,也没有可安装的通用 npm SDK |
✓ 正确,这验证了 NestJS → HTTP 云函数 → uniCloud Push 架构的必要性 |
sendMessage() 返回结构 |
reference 定义了 { ok, status: 'SUBMITTED'|'IGNORED'|'FAILED', ... } 的接口 |
DCloud 原始 API 返回 { errCode, data: { $taskid: { $cid: \"$status\" } } },其中 $status 为 successed_offline/successed_online/successed_ignore |
⚠️ reference 定义的接口是项目 push-gateway 的封装层,不是 DCloud 原始返回。应明确区分原始返回与封装后的结构,避免后人混淆 |
uni-cloud-s2s v1.0.1 的 bug |
提到 sha256 分支实际调 md5 |
v1.0.0 → v1.0.1 的 changelog 明确写了"修复 方法名错误",该 bug 可能已被修复。DCloud 论坛确认过 hash 方法标签错位问题 |
建议对当前已安装的 uni_modules/uni-cloud-s2s 源码重新审计,确认 v1.0.1 是否已修复 |
3.8 微信小程序
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
| 订阅消息模板字段类型 |
references 列出 5 种:thing, character_string, phrase, time, amount |
官方支持 13 种字段类型,还包括 number, letter, symbol, date, name, phone_number, car_number, enum |
references 中列出的 5 种是项目实际使用的,正确但不够完整。如需扩展模板,参考全部 13 种类型 |
| 错误码 43101/47003 |
references 描述为通用错误 |
这两个错误码是服务端发消息 API (/cgi-bin/message/subscribe/send) 的错误,不是客户端 wx.requestSubscribeMessage 的错误。客户端有自己的错误码体系 |
references 中错误码的使用上下文正确(用于后端发消息失败排查),但应标注来源 |
getPhoneNumber API |
references 描述流程为 "调用 getPhoneNumber 获取手机号" |
⚠️ 微信已更换 getPhoneNumber 方案:不再需要先 wx.login(),返回值从 encryptedData+iv 改为 code(5 分钟有效,单次使用),服务端用 phonenumber.getPhoneNumber 接口换号,自 2023-08-28 起收费 0.03 元/次(1000 次免费额度) |
references 中的流程如果是旧方案(AES 解密 encryptedData),需要更新为新方案 |
requiredBackgroundModes: ["location"] |
references 正确列出 |
官方支持 "audio" 和 "location"。但后台定位需要三层配置:app.json 声明 + 后台接口审批 + 用户手势授权,且需要通过人工审核(需提供录屏证明使用场景) |
✓ 正确,但需注意人工审核要求 |
| 合法域名配置 |
references 正确列出四种域名 |
需在微信公众平台「开发-开发设置-服务器域名」配置,仅支持 HTTPS/WSS,不支持 IP 和父域名,域名需中国大陆 ICP 备案 |
✓ 正确 |
3.9 其他重要发现
| 项目 |
references 中的说法 |
官方文档实际 |
处理建议 |
app-plus.modules.Geolocation |
权限检查清单中列为必查项 |
官方 manifest 模块列表中不存在 Geolocation。有效模块名包括:Maps、Push、OAuth、Payment、Share 等 15 个。地图/定位能力对应 Maps 模块 |
已修正 references 中此处为 Maps,并添加说明 |
| manifest.json 中的厂商字段 |
references 将 hms: {} 等空对象视为配置缺失 |
UniPush 2.0 的厂商参数在 DCloud 后台配置,manifest.json 中的这些字段是旧版遗留,不起作用 |
manifest.json 中的空厂商对象是正常的,不应视为风险项。确认厂商配置状态应去 DCloud 开发者中心 |
pushRegisterMode 所属节点 |
references 多处写为 android.pushRegisterMode |
⚠️ 官方文档将 pushRegisterMode 放在 ios 节点下(app-plus.distribute.ios.pushRegisterMode),用于控制 iOS 通知权限弹窗时机。Android 的隐私合规通过 androidPrivacy.json template 模式实现,官方 manifest schema 中不存在 android.pushRegisterMode |
所有 references 中已统一标注,建议项目按官方位置配置:iOS 用 ios.pushRegisterMode,Android 走 androidPrivacy.json |
四、Reference 路由表
按任务类型加载对应 reference,不必全部读取:
新手入门(必读)
| 文档 |
什么时候读 |
内容摘要 |
| uni小程序+APP的全程经验案例分享 |
首次接触项目或 uni-app 跨平台开发 |
完整项目复盘:主体/账号/证书/权限准备清单、登录闭环、推送订阅、实时定位、支付、隐私合规、部署运维、27 个真实问题复盘 |
| project-workflow |
接任何任务前 |
项目结构、命令速查、首轮巡检清单、平台分支规则、依赖偏好 |
| materials-and-permissions |
改 manifest.json 或配置权限前 |
各平台物料清单、H5/小程序/Android/iOS 配置检查项、登录/支付/推送/广告/隐私检查项 |
推送与通知
| 文档 |
什么时候读 |
内容摘要 |
| UniPush2.0配置小白文档 |
首次配置 UniPush 2.0 |
DCloud 后台配置步骤、前端 manifest 确认项、后端环境变量、cid 上报链路、测试步骤 |
| APP定位与UniPush2.0小白排查手册 |
推送/定位收不到,给非技术人员排查 |
手机权限检查步骤、DCloud/Apple 后台检查步骤、验证标准、按角色分工的联系人指南 |
| UniPush2.0整体跑通检查结论 |
检查当前项目推送状态 |
前后端代码闭环确认、已通/未通项清单、风险评估、下一步排查建议 |
| APP定位与UniPush2.0权限配置检查清单 |
发包前 |
sup-gpslocation 检查项、UniPush 2.0 检查项、隐私合规检查项、发包前最终核对表 |
| DCloud官方通知方案源码级说明 |
理解推送架构底层或升级依赖 |
官方通知能力边界、源码级约束、升级检查清单、uni-cloud-s2s 行为说明、不采用方案说明 |
| 微信小程序订阅消息配置小白操作手册 |
配置小程序订阅消息 |
模板申请步骤、AppID/AppSecret 获取、前后端配置、验证步骤、常见错误码处理 |
发布与验证
| 文档 |
什么时候读 |
内容摘要 |
| release-and-verification-sop |
构建、打包、发布、验证时 |
最小编译验证命令、H5/小程序/Android/iOS 各平台验证步骤、发布前 SOP、变更报告模板 |
排障
| 文档 |
什么时候读 |
内容摘要 |
| pitfalls-and-debugging |
遇到具体 Bug 时 |
证据优先调试循环、H5 uni.request 报错、定位权限缓存、实时追踪、支付宝登录、协议链接、原生打包缓存、日志规范 |
运维(非 uni-app 核心,按需取用)
| 文档 |
什么时候读 |
| 七牛云CDN证书自动同步操作指南 |
服务器证书管理 |
五、核心架构速查
5.1 技术栈
| 层 |
技术 |
| 前端框架 |
uni-app (Vue 3 + Vite) |
| 状态管理 |
Pinia |
| 状态机 |
XState v5(全局定位会话管理) |
| 包管理 |
pnpm |
| App 打包 |
HBuilderX 云打包 |
| 小程序调试 |
微信开发者工具 |
| 后端 |
NestJS + Prisma + PostgreSQL |
| 实时通信 |
Socket.IO (WebSocket) |
| App 推送 |
UniPush 2.0 → uniCloud push-gateway |
| 小程序通知 |
微信订阅消息 |
| 地图 |
高德地图 |
| 对象存储 |
七牛云 |
5.2 通知架构(重要)
订单业务状态变化
→ OrderEventOutbox(PostgreSQL)
→ OrderNotificationOrchestratorService(NestJS 编排)
→ 三路独立投递(一路不可用不阻断其他路):
├── WebSocket:在线实时推送(Socket.IO)
├── APP 系统通知:uniCloud push-gateway → UniPush 2.0 → 厂商通道/APNs
└── 微信订阅消息:NestJS 直调微信 API
→ OrderEventDelivery 记录每路投递状态
5.3 关键能力边界
| 能力 |
微信小程序 |
Android/iOS APP |
H5 |
| 系统通知 |
订阅消息(用户主动触发) |
UniPush 2.0(在线+离线) |
不适用 |
| 接收者标识 |
openid + 模板 ID |
cid / recipientUniId |
- |
| 离线推送 |
微信服务通知 |
厂商通道 (Android) / APNs (iOS) |
不支持 |
| 后台定位 |
微信后台定位 API(受生命周期限制) |
原生后台定位 + 前台服务通知 |
仅前台尽力 |
| 登录方式 |
微信登录 + 手机号 |
微信/支付宝/Apple + 手机号 |
取决于业务配置 |
| 支付方式 |
余额 + 微信 JSAPI |
余额 + 微信 APP 支付 + 支付宝 APP 支付 |
取决于产品方案 |
六、开工前强制准备清单
跨平台项目(小程序 + APP)的失败大多不是代码问题,而是账号、证书、权限、域名没提前准备好。
6.1 公司/主体层面
6.2 域名与服务器
6.3 平台账号
6.4 测试设备
仅用模拟器无法验证:厂商离线推送、APNs、App OAuth、Android 后台定位、iOS Always 定位。真机验证不可省略。
七、关键约束与易错点
7.1 配置不能混用的四组
- 微信小程序 AppID/AppSecret ≠ 微信开放平台移动应用 AppID/AppSecret(混用导致登录失败)
- APP 的 UniPush 系统通知 ≠ 微信小程序订阅消息(两种完全不同的机制)
- 前端 manifest.json 中的配置 ≠ 后端服务端密钥(UniPush AppID 不等于 AppKey 或 MasterSecret)
- 仓库模板中的配置 ≠ 服务器运行进程实际加载的配置(上线结论必须回到真实配置)
7.2 UniPush 离线推送成立的完整条件链
包内包含 Push 模块
→ 用户允许通知权限
→ DCloud 应用与当前 AppID 一致
→ 厂商/APNs 通道在 DCloud 后台配置正确(不是代码仓库里)
→ 隐私协议同意后才初始化推送(Android: androidPrivacy.json template 模式;iOS: pushRegisterMode=manual)
→ 真机获取到 cid
→ cid 正确入库(PostgreSQL)
→ 服务端成功发送(UNIPUSH_* 环境变量齐全)
→ 厂商系统没有拦截通知
→ 真机能收到
7.3 Android 后台定位成立的完整条件链
包内权限完整(含 POST_NOTIFICATIONS + FOREGROUND_SERVICE_LOCATION)
→ 系统定位总开关已开
→ APP 已获前台定位权限
→ APP 已获后台定位权限("始终允许")
→ Android 13+ 已授予通知权限
→ 通知渠道未被用户手动关闭
→ 插件配置正确(sup-gpslocation 已落库)
→ 重新打包并安装新包(不是旧包)
→ 真机切后台/锁屏后仍可上报
7.4 常见混淆点
| 混淆 |
正确理解 |
| 拿到 cid = 离线推送已通 |
cid 只是必要条件之一,厂商通道/APNs/服务器配置缺一不可 |
| manifest.json 厂商参数为空 = 没配置 |
厂商参数在 DCloud 后台配置,不在仓库的 manifest.json 中 |
| 仓库代码存在 = 线上已生效 |
必须验证:真包 + 真机 + 真实后台配置 + 真实验收 |
| online push 正常 = offline push 也正常 |
在线走 Socket,离线走厂商/APNs,是两套独立通道 |
| WebSocket 收到消息 = 推送已通 |
WebSocket 只保证在线实时性,不是离线通知替代 |
八、平台条件编译速查
<!-- App 专用 -->
<!-- #ifdef APP-PLUS -->
<!-- #endif -->
<!-- 微信小程序专用 -->
<!-- #ifdef MP-WEIXIN -->
<!-- #endif -->
<!-- H5 专用 -->
<!-- #ifdef H5 -->
<!-- #endif -->
- 条件编译必须成对出现,缺失
#endif 会导致编译错误
- 条件编译注释看似普通注释,实际会改变不同平台的最终源码
- 每次修改条件编译后,必须构建相关平台验证,不能只看编辑器 TypeScript
九、官方资源
核心文档
推送专题
uniCloud
平台
社区
十、输出规范
报告使用中文,包含以下结构:
## 目标
- 子项目:code/frontend / code/backend / code/admin
- 目标平台:H5 / MP-WEIXIN / APP-ANDROID / APP-IOS / 跨平台
- 任务描述:...
## 改动范围
- 涉及文件:...
- 涉及配置层面:manifest / pages / 环境变量 / 平台后台
## 根因/依据
- 根因分析(排障时):...
- 官方文档依据(配置时):...
- 代码调用链证据:...
## 实际改动
- 文件路径 → 改动内容
- 配置变更(标注:仅仓库 / 需同步平台后台 / 需重新打包)
## 验证
- 验证命令与结果:...
- 涉及平台的真机验证结果:...
## 剩余风险
- 需要人工确认的第三方后台配置:...
- 无法静态验证的项目:...
- 仍待真机验收的场景:...