# 罗盘问题排查记录 ## 背景 本项目在微信小程序中使用罗盘驱动: - 指北针针头 - 指北针顶部角度数字 - `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()` 调用,实际是平台兼容补丁,不应该在没有真机回归的情况下清理。**