Files
cmr-mini/doc/debug/罗盘排障记录.md

219 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 罗盘问题排查记录
> 文档版本v1.0
> 最后更新2026-04-02 08:28:05
## 背景
本项目在微信小程序中使用罗盘驱动:
- 指北针针头
- 指北针顶部角度数字
- `heading-up` 自动转图
在一次围绕顶部提示窗、传感器显示链和性能优化的修改后,出现了以下问题:
- iOS 端偶发正常,偶发异常
- Android 端罗盘长期无样本
- 指北针不转
- `heading-up` 自动转图一起失效
## 最终结论
这次问题的主因不是算法本身,而是:
**Android 微信环境下,罗盘监听需要被持续保活;之前将多处看似冗余的 `compassController.start()` 清理掉后Android 的罗盘样本链被破坏了。**
也就是说:
- iOS 对罗盘监听更宽容
- Android 对罗盘监听更脆弱
- 之前稳定,不是因为链路更“干净”,而是因为老代码里存在一条实际有效的“罗盘保活链”
## 现象总结
### 失效期
- Android 调试面板里 `Compass Source``无数据`
- iOS 仍可能有 `罗盘` 样本
- 若强行用 `DeviceMotion` 兜底,会出现:
- 指针会转
- 但方向不准
- 自动转图方向错误
### 恢复后
- Android `Compass Source` 恢复为 `罗盘`
- 指北针针头恢复
- 顶部角度数字恢复
- `heading-up` 恢复
## 误判过的方向
以下方向在本次排查中都被考虑过,但最终不是根因或不是主要根因:
### 1. `DeviceMotion` 兜底方案
问题:
- `DeviceMotion` 可以给出设备姿态角
- 但不能稳定代替“指向北”的绝对罗盘
- 用它兜底会导致:
- 能转
- 但方向明显不准
结论:
**`DeviceMotion` 不能作为正式指北针来源。**
### 2. 加速度计 / 其他传感器互斥
曾排查:
- `Accelerometer`
- `Gyroscope`
- `DeviceMotion`
- `Compass`
结论:
- 加速度计在当前微信 Android 环境下不稳定,已放弃
- 但这不是这次罗盘彻底失效的主因
### 3. 算法问题
曾尝试调整:
- 角度平滑
- 设备方向单位解释
- motion fallback 算法
结论:
这些会影响“顺不顺”、“准不准”,但**不能解释 Android 完全无罗盘样本**。
## 真正修复的方法
将之前被清理掉的多处 `this.compassController.start()` 恢复回去。
这些调用点主要分布在:
- `commitViewport(...)`
- `handleTouchStart(...)`
- `animatePreviewToRest(...)`
- `normalizeTranslate(...)`
- `zoomAroundPoint(...)`
- `handleRecenter(...)`
- `handleRotateStep(...)`
- `handleRotationReset(...)`
这些调用在代码审美上看起来像“重复启动”,但在 Android 微信环境里,它们实际上承担了:
**重新拉起 / 保活罗盘监听**
的作用。
## 当前工程判断
本项目当前应当采用以下原则:
### 1. 罗盘主来源只使用 `Compass`
不要再让:
- `DeviceMotion`
- 其它姿态角
参与正式指北针和自动转图的主方向链。
### 2. `DeviceMotion` 只保留为辅助或调试输入
可用于:
- 调试面板显示
- 设备姿态观察
- 未来原生端姿态融合参考
但不要直接驱动指北针。
### 3. Android 端罗盘需要保活
后续不要再把这些 `compassController.start()` 当成纯冗余逻辑随意清掉。
如果要优化代码,应该:
- 保留现有行为
- 将其收口为有明确语义的方法
例如:
- `ensureCompassAlive()`
- `refreshCompassBinding()`
而不是直接删掉。
## 与生命周期相关的硬约束
以下约束必须保持:
### 单实例
页面层必须保证任意时刻只有一个 `MapEngine` 活跃实例。
### 完整销毁
`MapEngine.destroy()` 中必须完整执行:
- `compassController.destroy()`
- 其它传感器 `destroy()`
防止旧监听残留。
### 调试状态不应影响罗盘主链
调试面板开关不应再控制:
- 罗盘是否启动
- 罗盘是否停止
否则容易再次引入平台差异问题。
## 推荐保留的调试字段
以下字段建议长期保留,便于后续定位:
- `Compass Source`
- `sensorHeadingText`
- 顶部角度数字
- `heading-up` 开关状态
其中 `Compass Source` 至少应显示:
- `罗盘`
- `无数据`
避免再次将问题误判为算法问题。
## 后续优化建议
如果后面要继续优化这段代码,推荐方向是:
### 可做
- 将分散的 `compassController.start()` 收口成命名明确的方法
- 为 Android 罗盘链补一层更可读的“保活机制”注释
- 保留当前稳定行为前提下做重构
### 不建议
- 再次移除这些重复 `start()` 调用
-`DeviceMotion` 正式兜底指北针
- 让调试开关影响罗盘主链启动
## 一句话经验
**在微信小程序里Android 罗盘监听的稳定性比 iOS 更脆;某些看似冗余的 `start()` 调用,实际是平台兼容补丁,不应该在没有真机回归的情况下清理。**