name: lktop-app-project description: "Use when working in ~/Code/lktop/app or when the user says ‘按 lktopapp 项目约束来做’. Applies the repo's uni-app/HBuilderX, BLE charger, firmware OTA, and product-management constraints." version: 1.2.0 author: Hermes Agent license: MIT metadata: hermes: tags: [project, uni-app, hbuilderx, ble, firmware, product-management] related_skills: [uni-app, hbuilderx-cli, writing-plans, systematic-debugging]
LKTOP App 项目 Skill
Overview
这是 ~/Code/lktop/app 项目的专用项目约束 Skill。
当用户说“按 lktopapp 项目约束来做”时,默认应套用这份规则,而不是把它当成一个普通的 uni-app demo、通用蓝牙示例项目,或者纯 UI 壳工程来处理。
这个项目本质上是一个面向 BLE 充电器设备的配套 App,当前代码已体现出以下核心能力:
- 搜索并连接 BLE 充电器设备
- 管理已连接设备与重连/替换入口
- 查看设备详情与设置项
- 检查固件版本、选择版本并执行设备固件升级
- 提供意见反馈入口
- 通过
uniCloud-tcb中的firmware云对象支撑固件能力
它不是空白项目,也不是只停留在概念验证阶段;产品、研发、测试判断必须优先基于当前仓库真实代码事实。
When to Use
在以下场景使用本 Skill:
- 你正在
~/Code/lktop/app仓库内工作 - 用户说“按 lktopapp 项目约束来做”
- 用户要求你做这个项目的产品经理、研发协作助手、需求分析、排查、文档、构建或发布支持
- 需求涉及 uni-app 页面结构、BLE 连接、充电器设备控制、固件升级、反馈链路
- 需求涉及 HBuilderX / HBuilderX CLI / uni-app 多端构建与打包
- 需求涉及
uniCloud-tcb的firmware云对象
默认不要把这个项目误判成:
- 普通营销型 App
- 纯 Web H5 页面项目
- 没有后端/云对象依赖的纯前端仓库
- 以
index.vue为首页的常规 uni-app 模板项目
如果任务已经超出 app 单仓库,开始同时涉及 website / admin / website-next / admin-next / lktop-platform 的产品边界、迁移关系或多项目统筹,应额外加载 lktop-product-portfolio skill。
Quick Facts
- 仓库路径:
~/Code/lktop/app - 工程类型:HBuilderX 管理的 uni-app 项目
- 技术栈:uni-app + Vue 3
- 关键能力域:BLE 设备接入 / 设备详情与控制 / 设备固件 OTA / 反馈入口
- 固件服务:
uniCloud-tcb/cloudfunctions/firmware/index.obj.js - 当前 PRD:
docs/lktop-app-prd-v1.md - 当前页面注册基线:
pages.json - App 启动会预热
firmware云对象 - 当前代码基线中,真实主入口页是
pages/devices/connected/connected manifest.json显示当前版本基线为1.0.71 / 1071- 仓库内已有经验证的 Harmony debug HAP 构建脚本:
scripts/build-harmony-debug-hap.sh - 鸿蒙正式签名包当前走
cli pack app-harmony --project /Users/chester/Code/lktop/app,产物与pack.info位于unpackage/dist/build/app-harmony/build/outputs/release/ - 当前仓库的 Harmony 签名材料实际放在
harmony-configs/,构建出的临时 Harmony 工程会复制这些文件到unpackage/dist/build/app-harmony/;正式发布 release profile 应使用lktopappRelease.p7b,不要使用历史/测试 profilelktopapp_cbtRelease.p7b - 构建产物交付给用户时,最终回复应包含纯文本可复制的直链(优先用代码块包住 URL),不要只给富文本描述或不可直接复制的链接呈现
- 当前工程已体现多端配置,不应按单端 demo 理解
- 设备图片已统一为全平台 256×256 RGBA PNG(实物照片),MC326 与 MINI 共用同一照片(
charger-mini.png是charger-mc326.png的副本),详见references/cross-platform-device-images.md - 当前活跃特性分支:
feat/mc326-v1-1-device-profile-ota(13 文件变更 vs master,含 device-profile.js、设备图片、charger/searching/connected/upgrade 页面改动,以及 firmware 云对象 channel 筛选) - 新增核心文件
utils/device-profile.js(型号识别、路由、图片映射、firmwareChannel 推导),全平台共用,详见references/device-profile-and-ota-channel-touchpoints.md
产品经理默认工作方式
当用户让我“作为这个项目的产品经理”时,默认不是只做文案整理,而是按下面模式工作:
先基于代码事实做现状盘点
- 先看
pages.json、App.vue、目标页面、相关 utils、云对象 - 再给出产品判断,不先写空泛建议
- 先看
优先从用户链路而不是页面孤岛出发 默认按 4 条链路思考:
- 接入链路:搜索、授权、连接、首连成功
- 回访链路:已连接设备、重进、替换设备、状态恢复
- 升级链路:检查版本、选择版本、下载、OTA、失败收口
- 反馈闭环:问题触发、反馈提交、后续跟踪
每次分析都区分“现状事实 / 问题判断 / 建议动作”
- 现状事实:当前代码里已经存在什么
- 问题判断:哪里会伤害转化、成功率、理解成本、售后效率
- 建议动作:下一步该改什么、为什么、优先级多高
优先级判断优先看主链路成功率 默认优先级排序:
- P0:影响连接成功、升级成功、设备可控、严重误导用户
- P1:影响高频效率、失败恢复、跨页状态一致性
- P2:影响理解成本、信息表达、次要体验细节
- P3:装饰性优化、风格统一、非关键文案润色
默认把自己当“产品 + 研发协同 PM”,不是纯业务 PM
- 结论要能落到页面、状态、接口/云对象、构建链路
- 避免只写抽象愿景,不可执行
当用户明确要“方案 / 需求分析 / 接入方案”时,先直答当前问题,禁止上下文漂移
- 先围绕当前 ask 输出:现状事实、差距、方案、影响范围、风险、验收口径
- 不要先汇报“我有什么 skill / 记忆 / 能力 / 之前做过什么”,除非用户问的就是这些
- 不要把上一任务(如构建、上传、发包、git、部署)的结果带进本轮方案回答,除非它与当前方案直接相关
- 如果前一轮刚做过别的事情,回答前先重新对齐用户的最新一句话,避免把“我能做什么”错答成“我建议怎么接入”
当用户问的是“你有没有这种技能 / 记忆 / 现成链路”时,先直接回答能力边界,再决定是否执行
- 先明确回答:有/没有;有哪些已加载或相关 skill;有哪些项目记忆/仓库事实可支撑当前请求
- 如果用户当前 ask 只是确认能力、技能、记忆、现成流程,默认先回答能力清单与约束,不要直接切回仓库里另一个进行中的代码任务
- 如果本轮任务类型已经从“代码改造/排查”切换成“构建/打包/上传/发链接”,必须先重新分类任务,再进入对应 workflow;不要被旧的 active task list、context compaction 里保留下来的 TODO、或刚才读到的代码上下文牵走
- 看到会话里仍显示 earlier active tasks / preserved task list 时,把它们当成背景状态,不是覆盖用户最新一句话的新指令;必须先对齐最新用户 ask
- 只有在回答完 capability 之后,且用户明确要继续执行时,再进入实际打包、上传、托管、发链路步骤
默认输出结构
如果用户没有指定格式,默认优先输出以下其中一种:
A. 产品分析
- 目标问题 / 当前任务
- 现状事实
- 关键问题
- 用户影响
- 优先级判断
- 建议方案
- 验收口径
B. 需求拆解
- 背景
- 目标
- In Scope
- Out of Scope
- 功能点拆解
- 风险与依赖
- 验收标准
- 待确认问题
C. 页面/流程评审
- 当前角色定位
- 上下游页面关系
- 主要断点
- 建议调整
- 影响范围
- 是否需要联动改动
D. 版本规划 / 优先级建议
- 必做项
- 应做项
- 可延后项
- 不建议现在做的项
- 排序理由
产品判断基线
1. 真实首页判断必须以 pages.json 为准
当前项目里,真实主入口页是 connected.vue,不是 index.vue。
默认规则:
- 页面入口、首页定义、用户首屏旅程判断时,优先看
pages.json - 不要因为存在
pages/index/index.vue就默认把它当成当前首页 - 如果讨论“首页改版”“首屏链路”“首次进入体验”,默认先从
connected.vue与searching.vue的关系切入
2. 产品本质是 BLE 设备配套 App,不是普通内容型 App
这个项目的产品主链路是:
- 已连接设备页
connected - 搜索/接入页
searching - 设备详情/控制台页
charger - 固件升级页
upgrade - 反馈页
feedback
默认处理原则:
- 任何需求分析都要围绕“连接成功率、设备操作效率、升级成功率、失败收口”来判断优先级
- 不要把页面优化只理解为视觉改版;必须考虑设备状态、连接链路与异常恢复
- 需求拆解时,优先把“接入链路”“回访链路”“升级链路”“反馈闭环”分开看
3. 必须严格区分 App 更新 与 设备固件 OTA
当前仓库同时存在:
uni_modules/uni-upgrade-center-app/pages/upgrade-popup:更接近 App 包更新能力pages/devices/upgrade/upgrade.vue:设备固件 OTA 能力
默认规则:
- 讨论升级时,先明确是在说 App 更新还是设备固件升级
- 如果用户没有明确说明,而语境在设备详情、设备版本、固件列表、BLE 传输,则默认指设备固件 OTA
- 不要把两个升级能力混写成同一个需求
4. 与固件相关的判断要同时看 App 侧与云对象侧
当前固件能力不是纯前端假数据:
App.vue启动时会预热firmware云对象- 云对象位于
uniCloud-tcb/cloudfunctions/firmware/index.obj.js
因此:
- 涉及版本列表、升级资格、下载地址、固件筛选时,不能只看页面代码
- 如果升级行为异常,要同时检查页面、BLE 传输链路和
firmware云对象 - 不要凭空设计未被当前代码证明存在的云端能力
5. HBuilderX / HBuilderX CLI 是正式构建链路的一部分
这是 HBuilderX 管理的 uni-app 项目,涉及多端构建与打包时,默认优先考虑:
- HBuilderX 工程结构本身
manifest.json中的多端配置hbuilderx-cliskill 中定义的 CLI 构建/打包方式uni-appskill 中的框架约束
默认规则:
- 做构建、打包、云函数、HarmonyOS HAP、App 资源生成等任务时,优先加载/遵守
hbuilderx-cli与uni-app技能 - 不要擅自把项目改造成 Vite-only、纯 npm-only 或其他不兼容的构建方式
- 不凭印象拼 HBuilderX CLI 命令;需要以 skill 中的命令形式和参数约束为准
- 如果只是做产品分析或页面改动,不必为了“工程现代化”顺手重构构建体系
6. BLE 是高风险核心域,不能轻率重构
仓库中 BLE 相关逻辑集中在 utils/ble-*、连接状态管理、设备连接列表、通知恢复等模块。
默认规则:
- 涉及连接、重连、扫描、后台前台切换、升级传输时,按高风险区域处理
- 没有明确证据时,不要假设连接问题只来自 UI 或只来自权限
- 任何产品结论都要考虑平台差异、BLE 栈限制和状态同步问题
- 当前仓库的厂商广播解析已确认采用:
companyId(0xACCA)+secondaryMark(0xAFFA)+productType/productSeries/productModel+ 14 字节 ASCII 序列号 +00 00保留字节;旧 6 字节 HEX 仅作为兼容回退 - 如果下游逻辑使用
deviceIdBytes,要先确认它依赖的是“历史 6 字节标识”还是“当前序列号字节”,避免把字段名当成协议事实
7. 平台差异是产品事实,不是实现噪音
App.vue 已明确体现平台差异:
- HarmonyOS:进入后台时尽量保持 BLE 连接
- Android / iOS:进入后台时会断开 BLE 连接以释放 GATT 资源
默认规则:
- 讨论“后台切回前台后为什么断了”“为什么鸿蒙和 Android 行为不同”时,不要把这种差异直接定义成 bug
- 需求、测试用例和验收标准应按平台区分
- 如果做连接恢复体验优化,应先确认目标平台
8. 当前反馈页并不等于真实客服闭环
当前 pages/feedback/feedback.vue 中已有明显“模拟提交延迟”的实现痕迹。
默认规则:
- 不要把反馈页现状描述成已打通完整服务闭环
- 任何关于售后、工单、问题追踪的结论,都应先确认后端是否真实接入
- 产品分析里应把反馈链路缺口视为现状问题,而不是已完成能力
9. 产品讨论优先基于现有 PRD 与代码事实,而不是脑补
当前仓库已存在 docs/lktop-app-prd-v1.md。
默认规则:
- 做产品分析、任务拆解、评审摘要时,优先对齐 PRD 与现有代码
- 没被当前代码和文档证实的业务规则,必须明确标注为“假设”或“待确认”
- 不要把 demo 风格建议直接上升为正式需求
默认工作流
处理这个项目的需求时,默认按下面顺序:
- 先判断需求属于哪一类:
- 产品分析 / PRD / 任务拆解
- 页面与交互改动
- BLE 连接/状态问题
- 固件升级 / 云对象问题
- HBuilderX CLI 构建/打包/部署
- 先读与本次需求直接相关的代码与文档,不凭记忆推断。
- 如涉及页面与链路判断,先核对
pages.json、App.vue、相关页面.vue文件。 - 如涉及升级,先区分 App 更新 vs 设备固件 OTA,再看
upgrade.vue与firmware云对象。 - 如涉及构建/打包/发布,优先参考
manifest.json与hbuilderx-cliskill。 - 输出时默认给出“事实、问题、建议、优先级、验证方式”五要素。
- 改动时只做和需求直接相关的最小变更,不顺手大改 BLE、构建体系或页面架构。
- 完成后根据任务类型做相应验证,而不是只看代码通过与否。
参考文件
优先参考这些文件:
docs/lktop-app-prd-v1.mddocs/lktop-app-prd-skeleton.mdpages.jsonApp.vuemanifest.jsonpackage.jsonpages/devices/connected/connected.vuepages/devices/searching/searching.vuepages/devices/charger/charger.vuepages/devices/upgrade/upgrade.vuepages/feedback/feedback.vueuniCloud-tcb/cloudfunctions/firmware/index.obj.jsutils/ble-*.jsreferences/ble-platform-architecture.md(BLE 模块跨平台代码架构:哪些文件是 Harmony 专有 API 层、哪些是通用逻辑层,以及跨平台同步的判断规则)references/harmony-debug-hap-workflow.mdreferences/harmony-release-app-workflow.md(鸿蒙正式签名包.app的已验证构建与核验流程)references/harmony-release-app-hosting-links.md(鸿蒙正式.app上传到前端托管并返回提审下载直链的已验证流程)references/harmony-privacy-consent-gate.md(HarmonyOS 不消费androidPrivacy.json时,自定义隐私协议弹窗与 uniCloud/BLE/权限 gate 的实现触点与验收口径)references/harmony-hap-hosting-links.md(HAP 上传到前端托管并返回可下载直链的已验证流程)references/ble-watchdog-vs-device-info.md(连接后0x180A设备信息读取与 charger proto watchdog 误判的排查要点)references/device-profile-and-ota-channel-touchpoints.md(device profile 数据源/路由/存储/OTA channel 现状、已落地实现触点,以及 MC326 硬件改版兼容的已确认决策)references/v1-1-firmware-channel-guard.md(V1.1 中firmwareChannel为空时 OTA 入口/升级页的保守拦截触点与验收口径)references/cross-platform-device-images.md(SVG 图片在微信小程序/Android/iOS 上的兼容性问题,以及 macOS 上 SVG → PNG 转换工具链)references/android-cloud-pack-workflow.md(HBuilderX CLI Android 云打包工作流、交互式提示的 expect 处理方案、构建时间线与常见坑)references/ios-cloud-pack-workflow.md(HBuilderX CLI iOS 云打包工作流、Bundle ID 配置踩坑记录、证书/profile 路径与密码配置位置,以及 minified 插件源码逆向排查经验)references/ble-state-machine-pitfalls.md(BLE Pipeline STOPPED 状态死锁与isScanning标志位不一致的排查要点:断连后重连无效、微信小程序后续搜索失败)references/lktop-feishu-bitable-task-tracker.md(飞书多维表格任务跟踪:Base/表结构、新建项目+任务的完整 lark-cli 流程与验证命令)references/wechat-mp-upload-workflow.md(微信小程序编译上传的完整工作流:HBuilderX 编译 → 微信开发者工具 CLI 上传 / preview 二维码生成,已弃用 miniprogram-ci)references/firmware-channel-admin-alignment.md(当 App OTA 查询依赖firmwareChannel时,旧 admin 固件版本运营表单/schema/list 的字段对齐检查清单)references/lito-firmware-channel-verification.md(LITO 返回全部 charger 固件版本时的排查路径、云对象部署验证命令、同事手持设备检查清单)references/www-lktop-cn-domain-migration.md(www.lktop.cn在 APP 中的引用盘点、旧 hash URL 映射、Nginx 反向代理迁移方案)references/cos-apk-upload.md(APK 上传到腾讯云 COS + CDN 分发:凭证获取、上传脚本、验证流程,替代已失效的www.lktop.cn前端托管)references/admin-next-local-dev.md(admin-next 本地开发环境:npm vs pnpm、Node v22、zsh session restore 绕过、NODE_ENV 缓存陷坑、启动与验证命令)
One-Shot Recipes
场景 A:做产品分析 / PRD / 需求拆解
默认动作:
- 先看
docs/lktop-app-prd-v1.md - 再回读
pages.json、App.vue、相关页面源码核对事实 - 输出时优先围绕:接入链路、回访链路、升级链路、反馈闭环
- 明确区分“代码已实现”“代码有雏形”“尚未实现/待确认”
- 默认补一个优先级判断,不只描述现状
场景 B:做页面 / 交互优化
默认动作:
- 先确认目标页在当前路由中的真实角色
- 不要误把
index.vue当成当前首页 - 如果改动会影响连接、升级、设置入口,要同步考虑相关页面跳转和状态文案
- 完成后至少回看关键路径是否仍闭环
- 输出时说明这次改动影响的是哪一条用户链路
场景 C:排查 BLE 连接或状态问题
默认动作:
- 先确认发生在哪个平台
- 再确认问题落在扫描、连接、已连接列表、通知恢复、前后台切换中的哪一段
- 不把 BLE 问题简单归因到单一文件
- 优先做最小修复与验证,不轻易全链路重写
- 如果给产品建议,必须说清是"连接成功率问题"还是"恢复体验问题"
- 如涉及广播识别,优先核对
utils/ble-adv-parser.js与references/ble-manufacturer-advertisement.md,确认当前设备到底是 14 字节 ASCII 序列号 还是旧 6 字节 HEX 回退格式 - 必须先区分标准 GATT Device Information Service (
0x180A) 与 充电器 proto 数据通道(00008300/00008301/00008302):前者用于读取model/serial/firmware/manufacturer等设备信息,后者才是 charger 页的 notify / proto 请求主通道。不要把"0x180A读取成功"误判成"charger proto 首包已到"。 - 如连接建立后出现"反复启用 notify / 反复读取设备信息 /
data-timeout -> restart"循环,优先检查 charger 页 pipeline 的 watchdog 是否过早在 READY 后启动。对本项目,若页面会先走0x180A设备信息读取,再等待00008301首包 proto 数据,watchdog 应延后到首个 proto 数据到达后再开始计时,否则会把初始化空窗期误判成链路超时。 - 用 Node 对
ble-adv-parser.js做最小验证时,优先构造完整AD Structure样本,而不是只传ManufacturerData纯 payload;否则会被未预处理的APP-HARMONY分支误导 - 如用户反馈「点击重连无效」或「设备日志显示未收到 APP 连接请求」:优先检查
ble-pipeline.js中state.phase是否为'STOPPED';scheduleRestart()在 STOPPED 状态下直接返回(L642),且restart()不恢复 phase。这是 Pipeline STOPPED 状态死锁,见 Pitfall #22 与references/ble-state-machine-pitfalls.md。 - 如用户反馈「搜索页首次正常,后续搜索不到设备」:优先检查
searching.vue:_cleanupBle()是否await了safeStopBluetoothDevicesDiscovery;再检查ble-init.js中isScanning标志位是否与平台实际扫描状态一致(safeStartBluetoothDevicesDiscovery的假复用逻辑,L372-374)。这是标志位不一致导致的假扫描,见 Pitfall #23 与references/ble-state-machine-pitfalls.md。
场景 D:处理固件升级 / 版本能力
默认动作:
- 先确认是设备固件 OTA,不是 App 更新
- 查看
upgrade.vue、charger.vue、App.vue与uniCloud-tcb/cloudfunctions/firmware/index.obj.js - 明确当前是否已有版本列表、版本选择、下载地址、升级状态与失败处理
- 如果做产品需求,要把失败出口、重试、反馈入口一起考虑
- 对 MC326/MINI/LITO 的 V1.1 链路,如果
firmwareChannel为空,默认按保守策略处理:允许控制,不允许放行 OTA;至少在 charger 页升级入口与 upgrade 页版本拉取/开始升级前做双重 guard,并提示“暂无法识别设备型号,请重新连接后再试”。 - 如果 App 云对象已按
firmwareChannel筛选固件,但admin-next尚未承接固件运营,必须同步检查旧~/Code/lktop/admin的firmware-versionsschema、validator、新增/编辑/列表页是否能录入并展示同名字段;参考references/firmware-channel-admin-alignment.md。 - LITO/MINI/MC326 固件隔离应保持
deviceType=charger,用firmwareChannel分流;如果详情页显示 LITO 但仍返回全部版本,优先核对resolveDeviceProfile()的识别候选是否包含 GATTmodelNumber/model,参考references/lito-firmware-channel-verification.md。 - 输出时优先回答:升级入口是否清晰、失败是否可恢复、用户是否理解当前状态
场景 F:鸿蒙已验证 → 向 Android/iOS/微信小程序传播修改
当用户说"鸿蒙已验证,现在对安卓/苹果/小程序做相应修改"时的默认动作:
- 先确认当前分支、版本号、与 master 的差异(
git diff master --stat) - 系统性扫描所有
#ifdef APP-HARMONY/#ifndef APP-HARMONY条件编译块,逐一检查非鸿蒙平台的路径是否有对应实现 - 重点检查三类差异:
- BLE 广播解析:确认
#ifndef APP-HARMONY分支能正确提取 V1.1 新增字段(productType/productSeries/productModel) - 文件读写:确认
MP-WEIXIN(wx.getFileSystemManager)、APP-PLUS(plus.io)分支已覆盖 - URL 跳转/系统能力:确认各平台有对应的实现(如
uts-openSchema仅 Harmony,其他平台用plus.runtime.openURL或navigateTo) - 注意:设备图片已全平台统一为 PNG,无需检查图片格式差异(详见
references/cross-platform-device-images.md)
- BLE 广播解析:确认
- 做最小修改,不改动已验证的鸿蒙分支逻辑
- 提交前至少核对:
git diff --check、新增行安全扫描、diff 中无意外引入的鸿蒙代码修改
场景 G:Android 云打包调试包
默认动作:
- 确认工作区干净(
git status) - 优先使用
expect+spawn处理可能出现的云端队列交互式提示,不要用yes |或echo Y |管道(CLI 读/dev/tty不读 stdin) - 提交命令:
cli pack --project ... --platform android --safemode false --android.packagename com.lktop.app --android.androidpacktype 1 - 如果用 expect,必须设置
set timeout≥ 1800(30 分钟);构建分两阶段:本地编译(~10s)→ 云端编译(5-15 分钟,此期间 CLI 无输出) - 构建完成后 APK 落在本地
unpackage/release/apk/lktop__<timestamp>.apk - 上传 COS(推荐 ✅):将 APK 上传到腾讯云 COS(
lktop-media-1331053332),通过 CDN(cdn.lktop.cn)分发,获取永久下载直链。详见references/cos-apk-upload.md。 - 交付时提供纯文本可复制的直链(优先用代码块包住 URL)
- 详见
references/android-cloud-pack-workflow.md和references/cos-apk-upload.md
场景 K:向飞书多维表格写入任务记录
当用户要求将 LKTOP App 的 BUG/需求/任务录入飞书多维表格时,默认动作:
- 先确认 Base Token(
S9BvbM79DakbrCsSqSSc3aaEnQf)、任务表(tblLv3IaYMN3SKTm)、项目表(tbl6WhCgQVf8cjZQ) - 检查项目表中是否已存在目标项目记录;不存在则先创建
- 获取项目
record_id后,创建任务记录并通过fldfhHpt7e(所属项目)link 关联 - 任务写入字段:
任务、状态、优先级、子项目专属描述、实际完成时间、所属项目 - 完成后用
+record-search验证写入结果 - 详见
references/lktop-feishu-bitable-task-tracker.md
场景 H:iOS 云打包调试包
默认动作:
- 确认证书文件存在:
p12和mobileprovision - 确认
hxiOSResign.json中CERTYPE为apple-dev - 推荐方式:使用
--ios.bundleCLI 参数显式传入 Bundle ID(绕过 manifest.json 的app-plus键名和 JSONC 注释导致的解析问题) - 使用
expect+spawn处理可能的队列交互式提示(同 Android,CLI 读/dev/tty不读 stdin) - 命令(推荐 ✅):
cli pack --project ... --platform ios --safemode false --ios.bundle cn.lktop.likigo --ios.profile /path/to/profile.mobileprovision --ios.certfile /path/to/cert.p12 --ios.certpassword "密码" - 备用方式:如果 manifest.json 的
plus.distribute.apple节点完整且 CLI 能正确解析,可省略--ios.bundle参数(但不可靠,不推荐) - 构建成功后输出中包含云端临时下载链接(不会像 Android 那样本地有 APK)
- 如需永久链接,从临时链接下载 IPA 后上传到前端托管
- 详见
references/ios-cloud-pack-workflow.md
场景 I:微信小程序编译上传
默认动作:
- 先 HBuilderX 编译:
cli publish mp-weixin --project ... --appid wxa10b843e85839619 - 再微信开发者工具上传:
/Applications/wechatwebdevtools.app/Contents/MacOS/cli upload --project .../unpackage/dist/build/mp-weixin -v "版本号" -d "描述"- ⚠️
--project必须指向编译产物目录unpackage/dist/build/mp-weixin/,不是项目根目录
- ⚠️
- 上传完成后 CLI 无法直接生成体验版二维码,需登录微信公众后台获取
- CLI 预览二维码生成不可靠:
preview --qr-format image --qr-output报TypeError,auto-preview报二维码路径无效。开发预览码只能通过微信开发者工具 GUI 获取。 - 详见
references/wechat-mp-upload-workflow.md
Common Pitfalls
把
index.vue当首页。 当前真实主入口是connected.vue。把 App 更新和设备固件升级混成一件事。 这是两个不同层级的能力。
把反馈页误判成已接通完整后端。 现状代码显示仍有模拟提交痕迹。
为了改一个页面,顺手重构整套 BLE 逻辑。 这是高风险行为。
把
0x180A设备信息读取与 charger proto notify 当成同一条链路。 在本项目里两者是分离的;如果 watchdog 只认00008301数据,就不能因为0x180A已成功而放松,也不能在 proto 首包到来前误判超时重启。忽略平台差异。 HarmonyOS 与 Android/iOS 的 BLE 后台策略不同。
构建/打包时绕开 HBuilderX CLI 约束。 这个项目不是随便用一套通用 Web 命令就能等价处理的。
只写产品想象,不校验代码事实。 这个项目已有真实能力,不应用空洞 PRD 覆盖事实。
输出只有建议,没有优先级和验收口径。 这不符合本项目的 PM 协作要求。
把 HBuilderX CLI 当成可自由猜参数的工具。 涉及构建、云函数、打包时必须按 skill 中已验证命令执行。
做 device profile/路由透传时破坏现有 BLE 页面跳转语义。
searching.vue -> charger.vue前,当前实现会先_cleanupBle()再导航;不要为了多带几个 query 参数把这个停扫时序删掉。connected.vue的“重连”不是直接进charger.vue,而是先回searching.vue走 rediscovery,用来刷新 BLE 地址/缓存状态;不要把 profile 透传优化误做成绕过搜索页的直连捷径。charger.vue.applyRouteOptions()已经会按serialNumber/deviceId取 stored record,新增 profile merge 时优先复用这条早期数据源,而不是等到0x180A后才初始化页面身份。
把
cli pack app-harmony当成 Harmony debug/dev HAP 方案。 对这个仓库,已验证的 debug/dev 包链路是unpackage/dist/dev/app-harmony+hvigor assembleHap ... buildMode=debug,优先走仓库脚本。做鸿蒙正式包时只看 CLI 成功日志,不核验 release 产物与元数据。 对这个仓库,正式包至少要核对
unpackage/dist/build/app-harmony/build/outputs/release/pack.info;如需进一步确认,检查.app内部.hap的module.json是否debug=false。用通用严格解析误判 uni-app 文件。
manifest.json在 HBuilderX/uni-app 项目中可能是 JSONC(含注释),不能直接用严格JSON.parse当作唯一语法检查;如需自动校验,应先用strip-json-comments等方式去注释/尾逗号后解析。.vue文件中// #ifdef MP-WEIXIN、// #ifdef APP-HARMONY等条件编译块可能在同一函数作用域里声明同名变量;普通 Babel 全量解析会把多端条件块同时解析,从而报出实际平台编译不会同时存在的重复声明。遇到这类验证失败时,先和HEAD:<file>做基线比较;若 HEAD 已同样失败,不要把它当成本次 diff 引入的新阻断。- 提交前仍要跑
git diff --check、新增行安全扫描,并尽量对新增/改动逻辑做局部审查;不要因为全文件解析有既有条件编译噪音就跳过验证。
- 在 MC326/MINI/LITO 兼容实现里把
firmwareChannel覆盖写进deviceType。
deviceType在当前项目里仍应保持基础设备品类语义(如charger),不要把它直接改成charger-mini/charger-lito。- 机型分流应通过独立的
firmwareChannel字段完成;云对象查询按deviceType + firmwareChannel处理,并在 channel 未命中时仅回退到无 channel 的旧记录。 - 如果把
deviceType和firmwareChannel混成一层,会破坏 Scheme B 的兼容目标,也会让旧数据回退语义变得含混。
- 在 uni-app 多端项目中使用 SVG 图片作为设备/产品静态资源,但没有为微信小程序和 Android/iOS 准备 PNG 回退。
- 微信小程序的
<image>组件不支持 SVG 格式。 - Android/iOS 原生 image 组件对 SVG 的支持不可靠。
- 鸿蒙平台 SVG 支持良好,但为了一致性和可维护性,本项目已统一使用 PNG 实物照片,并删除了所有设备 SVG 占位图。
- 当前方案:
utils/device-profile.js中全平台统一引用 PNG 常量,不再使用#ifdef APP-HARMONY/#ifndef APP-HARMONY条件编译切换格式。 - 历史方案(已废弃,仅作参考):曾使用条件编译让鸿蒙走 SVG、其他平台走 PNG。
- 详见
references/cross-platform-device-images.md。
- V1.1 已接入 profile/OTA channel,但
firmwareChannel为空时仍放行升级链路。
- 这会让前端重新退回按
deviceType='charger'查固件,等于把型号隔离保护绕开。 - 至少要在
charger.vue的"检查更新 / 选择固件 / 跳 upgrade"入口,以及upgrade.vue的"拉版本列表 / 开始升级"前做双重 guard。 - 允许控制链路继续可用;禁止的是 OTA 放行,不是整机不可操作。
- 微信小程序上传时使用
miniprogram-ci而非微信开发者工具 CLI。
- 旧方案
miniprogram-ci需要全局 npm 安装 + IP 白名单配置,已弃用。 - ✅ 当前方案:使用微信开发者工具自带的 CLI(
/Applications/wechatwebdevtools.app/Contents/MacOS/cli),前提是 DevTools 已打开项目且保持登录态。 - 编译:
cli publish mp-weixin --project ... --appid wxa10b843e85839619(HBuilderX → 微信项目) - 上传:
cli upload --project .../unpackage/dist/build/mp-weixin -v "版本号" -d "描述" - 上传后无法从 CLI 获取体验版二维码,需登录微信公众后台获取;可用
cli preview --qr-format image --qr-output /tmp/qr.png生成开发预览码。 - 详见
references/wechat-mp-upload-workflow.md。
- Android 云打包交互式提示用 pipe 输入(
yes |/echo Y |)绕过。
- HBuilderX CLI 的 Android 云打包在检测到云端队列已有项目时,会弹出
/dev/tty交互式提示:「是否继续提交?」 echo "Y" |、yes "Y" |、printf 'Y\n' |都不会生效——提示读取的是/dev/tty而不是 stdin。- ✅ 正确做法:使用
expect的spawn(提供 PTY):expect -re "是否继续提交" { send "Y\r" } - 不要假设
--safemode false或--confirm能跳过这个提示(实测无效)。 - 详见
references/android-cloud-pack-workflow.md。
- iOS 云打包持续报
Bundle ID(AppID)不能为空,尽管已在多个位置配置。
- HBuilderX CLI 的
pack --platform ios读取的 Bundle ID 来源是manifest.json→plus.distribute.apple.appid,不是setting.json的IOS_APPID,也不是manifest.json的ios.bundleIdentifier。 setting.json是 GUI IDE 使用的配置,HBuilderX 运行期间会覆写IOS_APPID/IOS_CERTFILE/IOS_PROFILE为空——不要在 CLI 打包流程中依赖它。- 方式 A(manifest.json,不推荐):在
manifest.json的plus.distribute下添加"apple"节点。但因为 manifest.json 实际使用app-plus键而非plus,且 JSONC 注释可能影响解析,此方式不可靠,已验证即使配置正确仍可能报错。 - 方式 B(CLI 参数,推荐✅):直接传
--ios.bundle cn.lktop.likigo绕过 manifest.json 解析问题,配合--ios.profile/--ios.certfile/--ios.certpassword完整传入。已验证稳定通过。 - 辅助:确保项目级
hxiOSResign.json(~/Library/Application Support/HBuilder X/projects/<hash>/hxiOSResign.json)存在且CERTYPE为apple-dev或apple-dis。 - 详见
references/ios-cloud-pack-workflow.md。
- 用户发送多张设备实物照片时,反复用 PIL 颜色分析/区域采样来猜测型号。
- 白底产品实物照片的平均 RGB 基本都在灰色范围(~170-200),颜色分析无法区分 MC326/MINI/LITO。
- 不要像处理彩色 SVG 设计稿一样依赖色相差异;实物照片的型号区分靠外形和标签文字,这些不能用简单的平均色来推断。
- 正确做法:最多做一次
file+ls -lh确认文件基本信息后,直接向用户确认"哪张图对应哪个设备型号"。 - 详见
references/cross-platform-device-images.md。
- 用户点击管道弹窗「重连」但无效,日志显示
createBLEConnection从未被调用。
- 根因:Pipeline 在
maxRestarts次自动重试后进入state.phase = 'STOPPED'(ble-pipeline.js:627),但restart()→scheduleRestart()内部检查if (state.phase === 'STOPPED') return(L642),导致用户的手动重连请求被直接丢弃。 restart()虽重置了restartCount = 0,但未改变state.phase,所以scheduleRestart在 STOPPED 下立即返回。- 同样受影响:
resume()也有if (state.phase === 'STOPPED') return(L681)。 - 修复方向:
restart()中先将state.phase从 STOPPED 恢复,或给scheduleRestart()加force参数。 - 详见
references/ble-state-machine-pitfalls.md。
- 微信小程序首次搜索正常,后续搜索设备列表永远为空,但设备日志显示广播正常。
- 根因:
searching.vue:_cleanupBle()调用safeStopBluetoothDevicesDiscovery()时未await,是 fire-and-forget。 - 微信小程序在
onHide时可能挂起页面 JS 执行,BLE.stopBluetoothDevicesDiscovery的complete回调未调用 →ble-init.js中isScanning标志位保持true。 - 下次
safeStartBluetoothDevicesDiscovery看到isScanning=true且currentScanOptionsKey相同 → 直接返回{ reused: true }(L372-374),未启动实际扫描。 - Android 原生 APP 理论上也可能触发(系统高负载/BLE 操作延迟大时),但微信小程序因 onHide JS 挂起机制几乎必现。
- 修复方向:
_cleanupBle()加await;safeStartBluetoothDevicesDiscovery增加僵尸扫描主动检测(超时无设备回调则重置并重启)。 - 详见
references/ble-state-machine-pitfalls.md。
- Vue methods 里加
await时漏了async声明。
- 在非 async 的 Vue methods 函数体内 patch 加了
await调用,但忘记把函数声明从methodName() {改成async methodName() {。 - HBuilderX/uni-app 的 Vite + vue/compiler-sfc 会直接报错:
[vite:vue] [vue/compiler-sfc] Unexpected reserved word 'await'。 - 这是一个两处联动修改:不能只 patch 调用行而漏掉函数签名行。
- 如果漏掉,Android 云打包和微信小程序编译都会失败(两者共享同一源码,编译期即暴露)。
- 修复后必须重新编译验证,不要假设「patch 看起来对就行」。
- Android 云打包 CLI 轮询长时间无输出时误以为正常排队。
- CLI 正常每 60 秒轮询一次队列位置;如果 8 分钟以上无任何输出,说明 CLI 与 DCloud 云端连接已断开。
- Kill + restart 不会丢失已提交的打包任务(提交发生在"向云端发送打包请求..."阶段,早于轮询)。
- 重启后的 CLI 会重新附加到同一云端任务并恢复状态轮询。
- 微信小程序上传时把 uni-app 项目根目录当成
--project参数传给微信 CLI。
- 微信开发者工具 CLI 的
upload/preview命令需要编译后的原生小程序项目(含app.json+project.config.json)。 - uni-app 项目根目录没有这些文件 → 报错
app.json: 在项目根目录未找到 app.json。 - ✅ 正确路径:
unpackage/dist/build/mp-weixin/或unpackage/dist/dev/mp-weixin/。 - 如果
open命令也需要指定 AppID:--appid wxa10b843e85839619,否则Using AppID: undefined会静默失败。
Verification Checklist
- 已先核对相关代码与文档,而不是凭印象下结论
- 如涉及首页/入口,已以
pages.json为准 - 如涉及升级,已区分 App 更新与设备固件 OTA
- 如是 V1.1 device profile / OTA channel 场景,已确认
firmwareChannel为空时不会放行 OTA(charger 入口 + upgrade 页双重 guard) - 如涉及 BLE,已确认平台与问题所在线路段
- 如涉及构建/打包,已参考
hbuilderx-cli与uni-app技能 - 如涉及反馈链路,没有把模拟能力描述成真实闭环
- 输出中包含事实、问题、建议、优先级、验证方式中的核心要素
- 输出中的产品判断与当前仓库事实一致
Notes
这是当前可直接用于 ~/Code/lktop/app 的正式项目约束 Skill。
后续如果页面入口、BLE 架构、升级链路、云对象能力、HBuilderX 构建链路或产品文档基线发生明显变化,应同步更新本 Skill。