# 设备 / 无障碍存活监控(device 族) > 所属:device 组(前缀 `/api/v1/device`,源 `app/api/v1/device.py`) | 鉴权:**全部 Bearer**(设备绑登录用户) | [← 返回 API 索引](../README.md) > > 落库:[`device_liveness`](../database/device_liveness.md) 表;后台 `heartbeat_monitor_worker` 据此检出心跳超时的设备并召回。设计见 spec `accessibility-liveness-push.md`(推送版)+ `accessibility-liveness-pull-prompt.md`(后置 pull 提醒版)。#65 新增。 无障碍服务存活监控链路:客户端无障碍服务存活时周期上报心跳,后端发现「曾保护过、现已超时」的设备 → 召回(推送 / 客户端进 App 弹「开启自启动」引导)。 ## POST /register — 注册设备 / 更新推送 token App 前台、拿到极光 push token 时调。按 `(user_id, device_id)` upsert。 **入参(JSON)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `device_id` | string | ✅ | 客户端 `DeviceId.get()` 生成的 per-install id | | `registration_id` | string \| null | ❌ | 极光推送 registration id(`JCollectionAuth` 同意后才有) | | `platform` | string | ❌ | 默认 `android` | | `app_version` | string \| null | ❌ | App 版本 | **出参**:`DeviceOut`(设备当前状态)。 ## POST /heartbeat — 上报心跳 无障碍服务存活时周期调(**心跳也能自注册**)。`accessibility_enabled=true` 时刷新 `last_heartbeat_at`、状态机置 `alive`、清掉线告警。 **入参(JSON)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `device_id` | string | ✅ | 同上 | | `accessibility_enabled` | bool | ✅ | 本机无障碍开关当前是否开 | | `registration_id` | string \| null | ❌ | 顺带更新 push token | **出参**:`{ "ok": true }`。 ## GET /liveness — 查本机掉线告警(后置检测) 客户端进 App 时拉:本机是否被判定掉线过(`kill_alert_pending`)。命中 → 客户端弹「开启自启动」引导,之后调 `/liveness/ack` 清。设备从未注册过 → 返回默认(无告警)。 **入参(query)**:`device_id`(string,必填)。 **出参**:`LivenessOut`(含 `kill_alert_pending` 等)。 ## POST /liveness/ack — 确认已提醒(清掉线告警) 客户端已弹过引导 → 清 `kill_alert_pending`(幂等;下次真掉线 worker 再置)。 **入参(JSON)**:`{ device_id }`。 **出参**:`{ "ok": true }`。 ## 错误 - `401` 未鉴权 / token 失效。 - `422` 缺 `device_id` 或字段类型不符。 ## 说明 - **`kill_alert_pending` 与 `liveness_state` 解耦**:worker 检出掉线置 True,心跳恢复(`/heartbeat`)只重置 state、不动此标记,只由 `/liveness/ack` 清 → 规避「服务随 App 重启先发心跳把 state 重置回 alive、客户端进 App 漏看这次掉线」竞态。 - 心跳超时阈值由 worker 配置决定,不在接口里。