Skip to Content
核心概念前台服务健康状况

前台服务健康状况

在 Android 上,持久的前台服务可以保持后台位置 活着追踪。但是 要求 跟踪 (Tracelet.start()) 与 操作系统授予正在运行的前台服务。在 Android 12+ 上 前台服务启动可以“推迟”或“拒绝”——即使您的应用程序 认为跟踪已启用。

Tracelet.getForegroundServiceHealth() 缩小了这一差距。它报告了 前台服务的权威本机状态,以便您可以告诉 “请求跟踪”“跟踪实际上是 运行”——当它们出现分歧时做出反应。

3.6.6 中的新增功能。 这补充了中的前台服务可靠性修复 3.6.5 (#253 ) 和 3.6.6 (#254 ) 通过使服务的 从 Dart 中可观察到的实际状态。


为什么 enabled 还不够

Tracelet.getState().enabled所需 状态 — 持续的意图 追踪。它回答*“应用程序是否要求跟踪?”,而不是“操作系统实际上是 现在正在运行前台服务吗?”*.

这些可能会有所不同,特别是在 Android 12+ (API 31+) 上,在其中启动 location 前台服务从后台受到限制:

  • 启动可以被推迟——Android 在应用程序启动时拒绝它 后台运行,当应用程序下次返回时 Tracelet 会自动重试 前景。
  • 启动可能会彻底失败——例如缺少权限,或者 未翻译。
  • 系统可以提升该服务,然后停止

在所有这些情况下,enabled 保持 true,但后台跟踪不是 操作。位置时间戳看门狗最终可以注意到陈旧性,但是 它无法告诉您为什么——是否升级失败、服务被停止,或者 提供商只是在等待新的修复。不翻译迟到 给你真实、权威的理由。


应用程序编程接口

final health = await Tracelet.getForegroundServiceHealth();

返回具有以下键的 Map<String, Object?>

关键类型意义
不翻译迟到不翻译晚点持续的所需跟踪状态(与 getState().enabled 相同)。
不翻译迟到不翻译晚点活动配置是否运行前台服务。
不翻译迟到不翻译晚点本机位置服务进程是否存活。
不翻译迟到不翻译晚点服务是否当前提升到前台(上次 startForeground() 成功,并且此后尚未降级/停止)。
不翻译迟到不翻译晚点促销时的通知ID;否则null
不翻译迟到不翻译晚点successdeferredfailed — 最近一次升级尝试的结果(任何尝试之前的 null)。
不翻译迟到不翻译晚点上次失败/延迟升级的异常类(例如 ForegroundServiceStartNotAllowedException)。
不翻译迟到不翻译晚点异常消息。
不翻译迟到不翻译晚点上次升级转换的纪元毫秒数。
不翻译迟到不翻译晚点androidios 或 NOTTRANS4LATE。

地图形状在每个平台上都故意相同,因此跨平台代码 可以统一读取。每个平台仅有所不同(见下文)。


解读促销结果

serviceForegroundlastForegroundPromotionResult 结合告诉您 整个故事:

不翻译迟到不翻译晚点不翻译2晚解读
不翻译迟到不翻译晚点任何跟踪已关闭 — 无需担心。
不翻译迟到不翻译晚点不翻译2晚健康 — 前台服务正在运行并提升。
不翻译迟到不翻译晚点不翻译2晚延迟 — Android 在后台拒绝启动;当应用程序返回前台时,Tracelet 将重试。
不翻译迟到不翻译晚点不翻译2晚失败——晋升失败;后台跟踪运行。检查故障类别/消息。
不翻译迟到不翻译晚点不翻译2晚⌛ 已请求但尚未确认(暂时的 - 很快会再次投票)。

跟踪健康指标

最常见的用途:向用户(或您的遥测数据)显示诚实的状态 而不是盲目相信 enabled

Future<String> describeTrackingHealth() async { final h = await Tracelet.getForegroundServiceHealth(); if (h['desiredEnabled'] != true) return 'Tracking off'; // iOS/web have no foreground service — enabled tracking is as good as it gets. if (h['platform'] != 'android') return 'Tracking active'; if (h['serviceForeground'] == true) return 'Tracking active'; switch (h['lastForegroundPromotionResult']) { case 'deferred': return 'Waiting to start — reopen the app to resume background tracking'; case 'failed': final reason = h['lastForegroundPromotionFailureMessage'] ?? 'unknown'; return 'Background tracking failed to start: $reason'; default: return 'Starting…'; } }

复苏看门狗

将运行状况检查与定期计时器配对以检测故障并从故障中恢复 促销 - 例如,提示用户重新打开应用程序,或重新请求 缺少许可。

Timer.periodic(const Duration(minutes: 1), (_) async { final h = await Tracelet.getForegroundServiceHealth(); final desired = h['desiredEnabled'] == true; final foreground = h['serviceForeground'] == true; final result = h['lastForegroundPromotionResult']; if (desired && !foreground && result == 'failed') { // Background tracking is not operational. Log it, alert your backend, // or guide the user to fix permissions / battery settings. await reportTrackingDegraded( failureClass: h['lastForegroundPromotionFailureClass'], failureMessage: h['lastForegroundPromotionFailureMessage'], ); } });

serviceForeground 反映了最后的 促销 结果,而不是实时民意调查 操作系统每毫秒。 start() 后立即推出促销活动 稍后 — 如果您需要最新值,则在短暂延迟(1-2 秒)后再次轮询。


平台行为

平台行为
安卓完全填充了实时前台服务状态和升级历史记录。
iOS没有任何前台服务会在事后失败,因此 serviceForegroundfalseforegroundServiceEnabledfalse,升级字段是 nulldesiredEnabledserviceRunning 反映跟踪是否处于活动状态。 NOTTRANS7LATE 是 NOTTRANS8LATE。
网络无前台服务。返回反映所需状态的最小映射; NOTTRANS0LATE 是 NOTTRANS1LATE。

这就是为什么 iOS 没有受到前台服务升级竞赛的影响。 在 #253  中针对 Android 进行了修复 #254 : iOS 没有单独的 可以提升然后拆除的前台服务进程。


在 Tracelet 医生中

您不必自己构建任何这些来“看到”它。这 tracelet_doctor 覆盖现在包含 前景 服务卡准确呈现此信息 - 期望与实际, 升级结果以及任何失败类别/消息 - 具有颜色编码状态 (正常/延迟/失败/不活动)。

tracelet_doctor 是一个 开发依赖 (flutter pub add dev:tracelet_doctor),所以 用 kDebugMode 保护它:

import 'package:flutter/foundation.dart' show kDebugMode; import 'package:tracelet_doctor/tracelet_doctor.dart'; if (kDebugMode) { TraceletDoctor.show(context); // includes the Foreground Service card }

错误报告 (TraceletBugReport.build()) 中也捕获了相同的字段, 因此粘贴的报告显示前台服务是否实际上在运行 问题发生的时间——通常是“跟踪停止在 背景”报道。


很高兴知道

  • 只读且便宜。 该调用仅读取内存中的本机状态;它从来没有 开始、停止或改变跟踪。
  • ready() 之前是安全的。 它返回一个合理的默认快照而不是 如果 SDK 尚未初始化,则抛出该异常。
  • **期望与实际才是重点。**继续使用 getState().enabled 您的应用程序的意图;使用 getForegroundServiceHealth() 验证操作系统是否 尊重这一意图。
Last updated on