Android 保活机制详解 —— 从概念到实践
记录在 3568主板 人脸支付终端上对接设备 SDK,实现 App 保活的全过程。
一、背景
我们的 App 跑在 3568 人脸支付终端上,这是一个无人值守的自助点餐机。在这种场景下,App 必须7×24 小时稳定运行,不能出现"App 挂了没人知道,客人来了点不了餐"的情况。
这就要求 App 具备"保活"能力。
二、保活 ≠ 自启动,很多人搞混
这是最容易混淆的两个概念:
| 对比项 | 开机自启动 | 保活(Keep-Alive) |
|---|---|---|
| 触发时机 | 只在开机瞬间触发一次 | 持续监控,每隔 N 秒检测一次 |
| App 崩溃后 | ❌ 不会自动拉起来 | ✅ 自动重启 |
| 被系统杀掉后 | ❌ 不会自动拉起来 | ✅ 自动重启 |
| 按 Home 回到桌面 | — | ✅ 进程还在,不会干预 |
| 切到系统设置 | — | ✅ 正常后台切换不受影响 |
简单理解:
- 自启动只管"开机那一下",开完就不管了。
- 保活像一个保安,24 小时盯着你的 App,发现不在了就立刻拉回来。
三、普通 Android 搞保活有多难
在标准 Android 系统上做保活,基本是地狱模式:
1. 常规手段(基本没用)
// 方式1:双进程守护 —— 两个 App 互相监控,被杀一个另一个拉回来
// 问题:Android 5.0+ 系统会一起杀,双进程同归于尽
// 方式2:前台 Service + 常驻通知栏
startForeground(NOTIFICATION_ID, notification);
// 问题:通知栏挂在那里用户看着烦,而且某些 ROM 还是会杀
// 方式3:1 像素 Activity
// 问题:Android 8.0+ 后台限制,几乎无效
// 方式4:JobScheduler / WorkManager 定时唤醒
// 问题:间隔越来越长(Doze 模式),最终可能几小时才唤醒一次
2. 为什么这么难
- Android 8.0+ 引入了后台执行限制,App 在后台跑 Service 受到严格管控。
- Android 9.0+ 引入 App Standby Buckets,不常用的 App 几天才能唤醒一次。
- 各大厂商(华为/小米/OPPO/vivo)还有自己的省电策略,比原生更激进。
结论:普通 App 想在标准 Android 上做真正可靠的保活,基本不可能。
四、为什么我们的设备可以?
因为我们用的是定制系统设备。
3568 设备基于 Rockchip 平台,系统层面内置了 QZhengIFManager 服务,提供了系统级的保活接口:
// 设备 SDK 提供的保活接口
new QZhengIFManager(context).setMonitorApp(packageName, true, intervalSeconds);
- packageName — 要守护的 App 包名
- true — 开启监控
- intervalSeconds — 检测间隔(秒),比如填 5 就是每 5 秒检查一次
这背后是系统级的守护进程在工作,不是 App 自己在挣扎,所以非常可靠。
五、实际操作:代码怎么加
5.1 引入 SDK
把设备 SDK 提供的 q-zhenglib.aar 放到 android/app/libs/ 目录下。
build.gradle 中已有自动加载配置:
implementation fileTree(dir: "libs", include: ["*.aar"])
所以放进去就能用,不需要额外配置。
5.2 在 MainActivity 中初始化
选择放在 MainActivity.onCreate(),因为这个 SDK 需要 Activity 上下文:
import com.q_zheng.QZhengIFManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
// ... 其他初始化代码 ...
// 只在对应用设备上启用保活
if (is3568FacepayDevice(...)) {
try {
boolean result = new QZhengIFManager(this)
.setMonitorApp(getPackageName(), true, 5);
Log.i("MainActivity", "setMonitorApp result = " + result);
} catch (Throwable e) {
Log.e("MainActivity", "setMonitorApp failed", e);
}
}
}
5.3 为什么要判断设备型号
你的 APK 可能运行在三种设备上:
| 设备 | 型号标识 | 有 QZhengIFManager 吗 |
|---|---|---|
| Pad 平板 | k62v1_8s / alps | ❌ 没有 |
| 工位机 | 3576SE / Shimeta | ❌ 没有 |
| 人脸支付终端 | xf108fw-y / rk3568 | ✅ 有 |
如果不做判断,在 Pad 或工位机上运行时会因为找不到 QZhengIFManager 类而崩溃。
5.4 为什么不走 RN 桥接?
因为保活是一次性设置,App 启动时调一次就行,后续不需要 JS 层关闭或切换。直接放在原生 onCreate() 最简单可靠。
如果你的场景需要在设置页开关保活、动态改间隔,那才需要做 React Native 桥接。
六、常见疑问解答
Q1:保活后 App 能退到后台吗?
可以。保活监控的是进程是否存活,不是"是否在前台"。你按 Home 回桌面、进系统设置,进程还活着,不会被强制拉回前台。
Q2:开机后 App 会自己启动吗?
会。setMonitorApp 是告诉系统守护进程"帮我盯着这个 App"。开机后守护进程检测到 App 没在运行,会自动拉起来。插电开机即可,不用人点。
Q3:被人手动强制停止呢?
这取决于设备实现。多数这类 SDK 的守护进程运行在系统层面(system_server),即使你在设置里"强制停止"App,守护进程仍会检测到并重新拉起。
Q4:5 秒检测一次耗电吗?
不耗电。这是进程存活状态检查,不是 CPU 密集型操作。对于常年插电的人脸支付终端,功耗完全不是问题。
七、总结
| 知识点 | 一句话 |
|---|---|
| 保活 vs 自启动 | 自启动只管开机那一下,保活是持续守护 |
| 标准 Android | 几乎没有可靠的保活手段,系统省电策略通常很激进 |
| 定制设备优势 | 设备提供系统级守护接口,可靠且简单 |
| 实战落点 | 放在 MainActivity.onCreate(),仅 3568 设备执行 |
| 不需要桥接 | 一次性设置,不需要 JS 开关,原生做了最省事 |
一句话记住:保活就是系统帮你盯着,App 死了就立刻叫醒。对无人值守设备来说这是必需能力,对定制安卓设备来说通常是现成能力。