更新记录
1.0.3(2026-08-12)
- Android
location会话默认启用可续期PARTIAL_WAKE_LOCK,支持enableWakeLock/wakeLockTimeoutMs配置。 - 新增 App 前后台、屏幕亮灭、原生 pulse 三组 watcher(共 6 个 API)及对应状态字段。
- Android / iOS / HarmonyOS 分别补齐 WakeLock 兜底、生命周期 pulse、RunningLock 与屏幕状态能力。
- 新增保活诊断(默认关闭):
enableDiagnostics开启后写入应用私有diagnostics目录(4×512 KiB JSONL 循环文件);提供readKeepaliveDiagnostics/clearKeepaliveDiagnostics/exportKeepaliveDiagnostics;Android 导出到Download/Xview/keepalive/;不含坐标与设备标识,插件不上传。
1.0.2(2026-07-28)
- 统一异步回调为
success / fail / complete;状态模型改为state / mode / nativeActive / sceneActive等。 - 默认场景
location;未落地场景返回9030006;错误码扩展到9030008。 - 新增能力查询、权限检查/申请、配额查询、定位与超时监听、恢复事件确认等 API。
- 三端只声明真实定位后台能力;Android 支持前台服务、调度兜底与超时锁;iOS / HarmonyOS 对齐真实定位会话。
- 示例收敛为「权限 → 会话主控 → 通知 / WakeLock / 重连」;启停仅在会话主控页。
1.0.1(2026-07-20)
- 校正 uni-app 与 uni-app x 的系统授权示例:仅 Android 展示电池优化设置与白名单操作,iOS 展示应用设置,Harmony 展示后台运行指引。
- 补全基础前台服务示例,展示
isKeepaliveRunning()与完整状态对象的对照结果。 - 修复 iOS UTS 包装层对 Swift 原生代码的错误模块导入,兼容 HBuilderX 5.06 编译器。
- 同步 README 示例页覆盖说明;公开 API、模块路径与包版本保持不变。
平台兼容性
uni-app(4.87)
| Vue2 | Vue2插件版本 | Vue3 | Vue3插件版本 | Chrome | Safari | app-vue | app-vue插件版本 | app-nvue | app-nvue插件版本 | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 1.0.0 | √ | 1.0.0 | × | × | √ | 1.0.0 | √ | 1.0.0 | 5.0 | 1.0.0 | 12 | 1.0.0 | 5.0+ | 1.0.0 |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | - |
uni-app x(5.0)
| Chrome | Safari | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 | 微信小程序 |
|---|---|---|---|---|---|---|---|---|
| × | × | 5.0 | 1.0.0 | 12 | 1.0.0 | 5.0+ | 1.0.0 | × |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| × | √ | √ |
XView 跨平台前台、后台保活插件
xview-keepalive 是 Android、iOS、HarmonyOS 的 UTS API 插件,用统一契约管理系统策略允许范围内的长时后台运行。
插件当前只对 location 场景提供完整原生工作链路。connectedDevice、mediaPlayback、dataTransfer 作为统一能力名称保留,但没有真实业务引擎时会由原生层返回 9030006,不会通过空任务、静音音频或声明后台类型伪造成功。
后台运行持续时间由系统策略、用户授权、设备电量策略、厂商限制和宿主配置共同决定。插件不承诺永久常驻、用户强退后自启或绝对持续运行。
推荐启动流程
// #ifdef APP
import {
getKeepaliveCapabilities,
checkKeepalivePermission,
requestKeepalivePermission,
startKeepalive,
watchKeepaliveLocation,
watchKeepaliveTimeout,
XviewKeepaliveCapabilities,
XviewKeepaliveFail,
XviewKeepaliveLocation,
XviewKeepalivePermission,
XviewKeepaliveStatus,
XviewKeepaliveTimeoutEvent
} from '@/uni_modules/xview-keepalive'
// #endif
const startLocation = () => {
watchKeepaliveLocation((location : XviewKeepaliveLocation) => {
console.log(location.latitude.toString() + ',' + location.longitude.toString())
})
watchKeepaliveTimeout((event : XviewKeepaliveTimeoutEvent) => {
console.log(event.reason + ': ' + event.message)
})
startKeepalive({
scene: 'location',
title: '后台定位',
content: '定位任务正在运行',
resilient: true,
enableBootRestart: false,
enableDiagnostics: true,
enableWakeLock: true,
wakeLockTimeoutMs: 60000,
location: {
accuracy: 'balanced',
intervalMs: 300000,
distanceFilter: 100
},
success: (status : XviewKeepaliveStatus) => {
console.log(status.state) // 原生链路确认完成后才可能为 active
},
fail: (error : XviewKeepaliveFail) => {
console.log(error.errCode.toString() + ': ' + error.errMsg)
}
})
}
const ensurePermission = () => {
checkKeepalivePermission({
scene: 'location',
success: (permission : XviewKeepalivePermission) => {
if (permission.granted) {
startLocation()
return
}
requestKeepalivePermission({
scene: 'location',
success: (requested : XviewKeepalivePermission) => {
if (requested.granted) {
startLocation()
}
}
})
}
})
}
getKeepaliveCapabilities({
success: (capabilities : XviewKeepaliveCapabilities) => {
if (capabilities.location.supported && capabilities.location.declared) {
ensurePermission()
}
}
})
停止页面监听时必须显式调用:
stopKeepaliveLocationWatch()
stopKeepaliveTimeoutWatch()
全局状态与 pulse 监听
建议在 App.vue / App.uvue 注册状态与 pulse watcher,而不是只绑定在会被卸载的业务页面。每类 watcher 只有一个 callback,重复注册会替换旧 callback。stopKeepalive() 会停止原生 pulse 调度但保留 watcher;重新启动真实会话后自动恢复,只有对应的 stop...Watch() 会清除 callback。
import {
watchKeepaliveAppState,
watchKeepaliveScreenState,
watchKeepalivePulse,
XviewKeepaliveAppStateEvent,
XviewKeepaliveScreenStateEvent,
XviewKeepalivePulseEvent
} from '@/uni_modules/xview-keepalive'
watchKeepaliveAppState((event : XviewKeepaliveAppStateEvent) => {
console.log('app=' + event.state + ' source=' + event.source)
})
watchKeepaliveScreenState((event : XviewKeepaliveScreenStateEvent) => {
console.log('screen=' + event.state + ' supported=' + event.supported.toString())
})
watchKeepalivePulse((event : XviewKeepalivePulseEvent) => {
// pulse 进入这里表示本次原生调度已经真正进入 DCloud JS Runtime。
// 可在此调用第三方 JS SDK 获取数据,再交给现有业务接口上传。
thirdPartySdk.getLatestData().then((data) => {
uploadBusinessData(data)
})
console.log('pulse=' + event.sequence.toString() + ' delay=' + event.delayMs.toString())
}, 10000)
watchKeepalivePulse 最小间隔为 1000ms,只在真实 keepalive 会话运行时派发,不执行第三方脚本本身。原有 setInterval() 可以继续保留作对照:原生 pulse 与 lastNativePulseAt 用于判断原生线程是否仍运行,lastJsPulseDeliveredAt 表示回调是否真正进入 JS。iOS 进程被系统挂起时 pulse 也会暂停;Core Location 回调到达后会补做一次到期检查,但不承诺固定周期。
保活诊断
诊断默认关闭。调用 startKeepalive({ enableDiagnostics: true }) 后,原生层会把开关写入恢复配置;应用冷启动仍需在 App.vue / App.uvue 调用 initializeKeepalive,以恢复诊断会话和内部 JS Runtime 探针。公开 watchKeepalivePulse 的 callback 与间隔不会被诊断探针占用或修改。
import {
readKeepaliveDiagnostics,
clearKeepaliveDiagnostics,
exportKeepaliveDiagnostics,
XviewKeepaliveDiagnosticsResult
} from '@/uni_modules/xview-keepalive'
readKeepaliveDiagnostics({
limit: 200,
success: (result : XviewKeepaliveDiagnosticsResult) => {
console.log('previous=' + result.previousExitReason)
console.log('events=' + result.events.length.toString())
}
})
exportKeepaliveDiagnostics({
success: (result) => {
// Android 10+ 的 path 为 content URI;Android 9 及以下为 Download/Xview/keepalive/ 绝对路径。
console.log(result.path)
}
})
clearKeepaliveDiagnostics({
success: (result) => {
console.log('cleared=' + result.clearedEventCount.toString())
}
})
诊断存储位于应用私有 diagnostics 目录,使用 4 个 JSONL 循环文件,每个最多 512 KiB,总量约 2 MiB。exportKeepaliveDiagnostics 会先把事件合并为 UTF-8 JSONL,再复制到用户可见目录:Android 写入 Download/Xview/keepalive/(Android 10+ 返回 content URI,Android 9 及以下需 WRITE_EXTERNAL_STORAGE 运行时权限);iOS / HarmonyOS 仍导出到应用沙箱。启停、异常、JS 中断/恢复和关键状态变化立即写入;稳定运行每 60 秒写一次检查点。readKeepaliveDiagnostics 默认读取最新 200 条,limit 范围为 1–1000,事件按时间倒序返回。诊断关闭或暂无历史均返回正常空结果,存储、读取或导出异常才返回 9030009。
内部探针每 10 秒尝试进入一次 UTS Runtime;原生检查点仍推进且 30 秒没有探针确认时记录 js_runtime_gap,恢复后记录 js_runtime_recovered。结论按证据区分:系统 API 提供原因时为已确认退出;上一进程标记未正常关闭但没有系统原因时只标记“疑似异常终止”;原生继续推进而 JS 超时只表示“JS Runtime 中断或挂起”;原生和 JS 同时停止且无系统记录时保持 unknown。MetricKit 可能延迟回传,事件中的报告时间与异常时间应分别核对。
日志仅保存进程会话、保活会话、PID、生命周期、保活状态、探针和系统原因摘要,不写入定位坐标、设备唯一标识、完整权限结果或通知正文;系统说明会截断并脱敏。日志不会由插件上传。清空操作保留当前诊断开关,并为仍启用的当前进程重新建立会话记录。
应用启动恢复
App.vue 或 App.uvue 的 onLaunch 应调用 initializeKeepalive。初始化完成后非破坏性读取恢复事件,先派发给业务,再按事件 ID 确认消费。派发或确认失败时,未确认事件仍保留在原生存储中。
initializeKeepalive({
success: () => {
readKeepaliveReconnectEvents({
success: (result : XviewKeepaliveReconnectEventsResult) => {
const events : Array<XviewKeepaliveReconnectEvent> = result.events
const ids : Array<string> = []
events.forEach((event : XviewKeepaliveReconnectEvent) => {
uni.$emit('xview-keepalive:reconnect', event)
ids.push(event.id)
})
if (ids.length > 0) {
confirmKeepaliveReconnectEvents({ ids: ids })
}
}
})
}
})
Android 只有 enableBootRestart: true 的真实定位任务允许注册开机恢复。调度器被系统触发只会生成恢复事件;只有原生服务和定位会话成功启动后,状态才会变为 active。
API
所有异步原生操作使用 success / fail / complete,complete 类型固定为 XviewKeepaliveComplete。除 watcher 外,不再同步返回缓存状态。
| API | 结果类型 | 说明 |
|---|---|---|
initializeKeepalive(options) |
XviewKeepaliveStatus |
应用启动时恢复原生配置并处理系统唤醒 |
startKeepalive(options) |
XviewKeepaliveStatus |
启动真实场景引擎 |
restartKeepalive(options) |
XviewKeepaliveStatus |
读取上次配置并重新启动 |
stopKeepalive(options) |
XviewKeepaliveStatus |
等待原生资源停止并确认 |
updateKeepaliveNotification(options) |
XviewKeepaliveActionResult |
更新 Android/Harmony 通知;无等价能力时失败 |
getKeepaliveStatus(options) |
XviewKeepaliveStatus |
查询权威状态机 |
isKeepaliveRunning(options) |
XviewKeepaliveBooleanResult |
查询原生场景是否活动 |
getKeepaliveLimit(options) |
XviewKeepaliveLimit |
查询限制;estimated=true 表示本地估算 |
getKeepaliveCapabilities(options) |
XviewKeepaliveCapabilities |
查询场景和系统辅助能力 |
checkKeepalivePermission(options) |
XviewKeepalivePermission |
查询场景权限 |
requestKeepalivePermission(options) |
XviewKeepalivePermission |
分阶段申请场景权限 |
requestNotificationPermission(options) |
XviewKeepalivePermission |
申请并返回真实通知权限 |
watchKeepaliveLocation(callback) |
void |
注册保活定位回调 |
stopKeepaliveLocationWatch() |
void |
释放定位回调 |
watchKeepaliveTimeout(callback) |
void |
注册系统超时、权限撤销等事件 |
stopKeepaliveTimeoutWatch() |
void |
释放 timeout 回调 |
watchKeepaliveAppState(callback) |
void |
立即返回并持续监听前后台状态 |
stopKeepaliveAppStateWatch() |
void |
释放前后台状态 callback |
watchKeepaliveScreenState(callback) |
void |
立即返回屏幕状态;iOS 明确返回 unsupported |
stopKeepaliveScreenStateWatch() |
void |
释放屏幕状态 callback |
watchKeepalivePulse(callback, intervalMs) |
void |
注册原生 pulse;最小间隔 1000ms |
stopKeepalivePulseWatch() |
void |
清除 pulse callback 并停止当前调度 |
isNotificationEnabled(options) |
XviewKeepaliveBooleanResult |
查询通知授权 |
openNotificationSettings(options) |
XviewKeepaliveActionResult |
打开原生通知设置 |
isIgnoringBatteryOptimizations(options) |
XviewKeepaliveBooleanResult |
查询 Android 电池优化状态 |
requestIgnoreBatteryOptimizations(options) |
XviewKeepaliveActionResult |
请求 Android 忽略电池优化 |
openBatteryOptimizationSettings(options) |
XviewKeepaliveActionResult |
打开 Android 电池优化设置 |
startWakeLock(options) |
XviewKeepaliveActionResult |
Android 申请 WakeLock;Harmony 按 RunningLock 探测结果执行 |
readKeepaliveReconnectEvents(options) |
XviewKeepaliveReconnectEventsResult |
非破坏性读取原生持久化恢复事件,事件位于 events 字段 |
confirmKeepaliveReconnectEvents(options) |
XviewKeepaliveActionResult |
按 ID 确认并删除已派发的恢复事件 |
addKeepaliveReconnectEvent(options) |
XviewKeepaliveReconnectEvent |
主动写入原生持久化恢复事件 |
readKeepaliveDiagnostics(options) |
XviewKeepaliveDiagnosticsResult |
读取最新 1–1000 条原生诊断事件和上一进程摘要 |
clearKeepaliveDiagnostics(options) |
XviewKeepaliveDiagnosticActionResult |
清空历史并保留当前诊断开关、重建当前会话记录 |
exportKeepaliveDiagnostics(options) |
XviewKeepaliveDiagnosticExportResult |
导出 UTF-8 JSONL;Android 复制到 Download/Xview/keepalive/ |
状态模型
XviewKeepaliveStatus 的核心字段:
state:stopped / starting / active / degraded / stopping / failed。mode:continuous / transient / none。nativeActive:平台后台能力是否已由原生层确认启动。sceneActive:真实场景引擎是否活动。degraded:当前运行质量是否退化。notificationVisible:用户可感知通知是否真实展示。locationActive:原生定位会话是否真实活动。appState / screenState / screenStateSupported:当前前后台与亮灭屏状态及平台支持语义。foregroundServiceActive:Android 同进程前台服务真实实例是否存在;iOS/Harmony 固定为 false。lastNativePulseAt:原生计时器最近一次产生 pulse 的墙钟时间。lastJsPulseDeliveredAt:UTS callback 最近一次真正进入 JS Runtime 的墙钟时间。diagnosticsEnabled:原生诊断持久化是否开启。diagnosticJsProbeActive:独立内部 JS Runtime 探针是否已注册。diagnosticLastPersistedAt:最近一次诊断事件成功落盘的时间戳,尚未落盘时为0。wakeLockHeld:Android WakeLock 或 Harmony RunningLock 的真实持有状态。
state === 'active' && nativeActive && sceneActive 表示完整链路运行;degraded 表示真实 location 会话仍可能运行,但通知或锁等增强条件不完整。插件不会把 degraded 伪装成完整成功。
错误码
| 错误码 | 说明 |
|---|---|
9030001 |
当前平台没有等价原生操作 |
9030002 |
原生启动链路失败 |
9030003 |
原生停止链路失败 |
9030004 |
打开系统设置失败 |
9030005 |
参数或场景名称不合法 |
9030006 |
场景尚未接入真实原生工作负载 |
9030007 |
系统时长配额已耗尽 |
9030008 |
缺少场景必需权限 |
9030009 |
诊断存储、读取或导出失败 |
宿主配置
Android
插件仅声明 location 前台服务类型,服务不配置独立 android:process,与 DCloud JS Runtime 位于应用主进程。目标版本较高时需要按系统要求分阶段处理通知、前台定位和后台定位权限。若宿主修改或合并 Manifest,必须保留插件的 service、receiver、job service 和真实定位权限声明。
华为/vivo 等系统还必须按上文开启厂商后台运行权限;Android 电池优化白名单与厂商“应用启动管理 /
后台高耗电”是两套独立策略,只配置其中一项不能保证 WakeLock 不被厂商代理释放。
Android 11(API 30)及以上会读取上一进程的 ApplicationExitInfo 精简原因与 process-state 摘要;较低版本只有本地会话证据。系统记录也可能受设备实现和历史保留数量限制。
iOS
插件只声明 UIBackgroundModes = location。宿主必须配置符合实际用途的定位权限文案,并对 App Store 审核解释真实后台定位业务。用户主动强退、关闭后台 App 刷新或撤销 Always 权限时,系统可能阻止恢复。
iOS 13 及以上注册 MetricKit subscriber;MXDiagnosticPayload 由 iOS 14 起提供,因此 iOS 14+ 才能接收系统诊断载荷,且报告可能在异常发生后延迟送达。iOS 12–13 以本地生命周期、定位、内存警告和会话标记为主。willTerminate 仅作为线索,不作为正常退出的唯一依据。
HarmonyOS
宿主需要声明 KEEP_BACKGROUND_RUNNING、LOCATION、APPROXIMATELY_LOCATION、LOCATION_IN_BACKGROUND、RUNNING_LOCK,Ability 的 backgroundModes 只包含 location。BACKGROUND RunningLock 已被系统标记 deprecated 且没有公开等价替代,插件会先探测设备能力和权限;不可用或申请失败时继续保留真实 LOCATION 连续任务,但状态返回 degraded、wakeLockHeld=false 和具体原因。插件从 UIAbilityContext 动态读取 bundle、module 和 ability 信息,不依赖示例包名。
HarmonyOS 不引入 AGC 或网络依赖,应用内仅记录 Ability 生命周期、持续任务、定位、RunningLock、屏幕、状态与探针证据;精确 AppKilled/Freeze 原因需将导出 JSONL 的时间戳与 DevEco FaultLog 对照。

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 42
赞赏 0
下载 12525328
赞赏 1944
赞赏
京公网安备:11010802035340号