compass-debugging-notes.md 4.7 KB

罗盘问题排查记录

背景

本项目在微信小程序中使用罗盘驱动:

  • 指北针针头
  • 指北针顶部角度数字
  • 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() 调用,实际是平台兼容补丁,不应该在没有真机回归的情况下清理。