☰
Android安卓保活sdk
2026/9/30 20:09:06 网站建设 项目流程

Android 后台存活率提升实战:从"被厂商杀"到推送稳定送达(Android 7–16)

T e l e g r a m \textcolor{red}{Telegram}Telegram:@lily059

开篇:先别急着写代码

“我的应用在小米上被杀得妈都不认识,在华为上活不过两小时。”

这句抱怨我在评论区看过太多次。但大多数人在动手之前,其实连自己的进程是被谁杀的都不知道——于是开始堆各种"保活奇技淫巧",最后既没解决问题,还把自己送进了应用市场的审核黑名单。

这篇文章不讲玄学,只讲三件事:

  1. 用系统 API定位真实死因,而不是猜;
  2. 系统允许你做的合规且有效的手段,以及各自的适用边界;
  3. 哪些做法是红线——技术上"能用",但会带来审核、合规和卸载率的代价。

一、先分清 5 种"死法"

进程被杀不是一件事,是五件事。搞错病因,药就不可能对。

类型触发者典型表现能否用合规手段缓解
LMK(低内存杀手)内核内存吃紧时按 oom_adj 依次回收可以:降低自身占用、提升 oom_adj 优先级
后台执行限制Android 8+ 框架后台startService()抛IllegalStateException;隐式广播收不到可以:前台服务、显式广播、WorkManager
Doze / App Standby系统省电息屏静置后网络、闹钟、任务被延迟可以:setExactAndAllowWhileIdle、电池优化白名单
厂商省电策略MIUI / EMUI / ColorOS / Funtouch…锁屏后清后台、自启动被拦、"关联启动"被禁部分可以:引导用户开白名单,无法代码绕过
用户强停 / 划掉卡片用户最近任务划掉、设置里点"强制停止"不应该缓解——这是用户的明确意图

最后一行请记住:用户强停是用户的权利,不是 bug。后面会专门讲为什么去对抗它是笔亏本买卖。


二、用ApplicationExitInfo定位死因(这是本文最有价值的一段)

Android 11(API 30)之后,系统提供了官方接口查询进程历史退出原因,别再靠"我猜是 MIUI 杀的"了。

@RequiresApi(Build.VERSION_CODES.R)fundumpExitReasons(context:Context){valam=context.getSystemService(Context.ACTIVITY_SERVICE)asActivityManager// 参数:packageName(传 null 表示自己)、maxNum、maxNum 上限am.getHistoricalProcessExitReasons(null,0,20).forEach{info->Log.i("ExitInfo",""" time=${info.timestamp}reason=${info.reason.toReadable()}importance=${info.importance}// 被杀时的前台/后台状态desc=${info.description?:"-"}rss=${info.rss}// 峰值内存,排查 LMK 很有用pss=${info.pss}""".trimIndent())// 如果是崩溃/ANR,还能拿到 traceinfo.traceInputStream?.use{/* 交给崩溃平台解析 */}}}@RequiresApi(Build.VERSION_CODES.R)funInt.toReadable():String=when(this){ApplicationExitInfo.REASON_LOW_MEMORY->"LMK 内存不足被杀"ApplicationExitInfo.REASON_USER_REQUESTED->"用户主动结束/强停"ApplicationExitInfo.REASON_OTHER->"系统回收(厂商策略常见)"ApplicationExitInfo.REASON_FREEZER->"被系统冻结后回收(Android 12+)"ApplicationExitInfo.REASON_ANR->"ANR"ApplicationExitInfo.REASON_CRASH->"Java 崩溃"ApplicationExitInfo.REASON_CRASH_NATIVE->"Native 崩溃"ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE->"资源占用超限被回收"ApplicationExitInfo.REASON_DEPENDENCY_DIED->"依赖进程退出连带"ApplicationExitInfo.REASON_INITIALIZATION_FAILURE->"启动初始化失败"else->"其他($this)"}

怎么读这些数据:

  • 大量REASON_LOW_MEMORY→ 你的常驻内存太大,先做内存优化,别急着加服务;
  • 大量REASON_OTHER/REASON_FREEZER→ 大概率是厂商策略,属于"引导用户开白名单"的场景;
  • REASON_USER_REQUESTED占比高 →停下来想想产品体验,用户在用脚投票;
  • REASON_CRASH*/REASON_ANR→ 先修 bug,崩溃的进程谈何存活。

小提示:这套 API 在部分 OEM ROM 上粒度有限,REASON_OTHER占比会偏高。配合"进程启动时间 + 前后台切换时间点"一起埋点,才能还原完整链路。


三、合规且有效的手段(按场景选型)

3.1 前台服务:首选,但类型必须选对

Android 14(API 34)起foregroundServiceType是强制项,且必须声明对应的FOREGROUND_SERVICE_*权限,否则直接崩溃。

<uses-permissionandroid:name="android.permission.FOREGROUND_SERVICE"/><uses-permissionandroid:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/><serviceandroid:name=".SyncService"android:exported="false"android:foregroundServiceType="dataSync"/>
overridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{startForeground(NOTIFY_ID,buildNotification(),// 必须用户可见,别做成透明通知ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC// Android 10+ 可显式指定)returnSTART_STICKY}

几个必须知道的边界:

  • 类型不是随便选的:dataSync用于数据同步,mediaPlayback用于播放,location用于导航——选错类型在市场审核时会被打回;
  • Android 15 起,dataSync/mediaProcessing类型的前台服务有"24 小时内累计 6 小时"的时长上限,超时会收到onTimeout()回调,必须在那里收尾,别装作没看见;
  • 从后台启动前台服务有限制(Android 12+ 收紧了 exception 列表),Android 15 起SYSTEM_ALERT_WINDOW也不再是豁免理由。想靠"悬浮窗权限换后台起服务"的老套路已经不通了。

3.2 推送通道:真正决定"消息能不能到"的,是它

如果你的诉求是"消息别丢",那么长连接和推送通道的权重,远高于进程存活。进程被杀后能被推送拉起,比死撑进程省电得多。

  • 海外:老老实实用FCM;
  • 国内:接入厂商推送(小米、华为 HMS、OPPO、vivo、荣耀、魅族)是硬需求——这些通道在应用被杀后仍可送达,而且不需要你保活;
  • 需要自建长连接时,做好断线重连退避、心跳与厂商通道的互补(在线走长连接,离线走推送)。

一句话:能用推送解决的,不要用保活解决。

3.3 WorkManager:可延迟任务的正确姿势

valrequest=PeriodicWorkRequestBuilder<SyncWorker>(15,TimeUnit.MINUTES).setBackoffCriteria(BackoffPolicy.EXPONENTIAL,10,TimeUnit.MINUTES).build()WorkManager.getInstance(context).enqueueUniquePeriodicWork("sync",ExistingPeriodicWorkPolicy.KEEP,request)
  • 周期任务最小间隔 15 分钟,别指望它做秒级轮询;
  • ExistingPeriodicWorkPolicy.KEEP避免每次启动都重建任务;
  • WorkManager保证会执行,但不保证准时(受 Doze / 电池策略影响),对时效敏感就别用它。

3.4 精确闹钟:注意 Android 12/13 的权限变化

valam=context.getSystemService(AlarmManager::class.java)valtriggerAt=System.currentTimeMillis()+5*60_000valcanExact=if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.S){am.canScheduleExactAlarms()// Android 12+ 必须运行时判断}elsetrueif(canExact){am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,triggerAt,pendingIntent)}else{// 降级为不精确闹钟,同样能穿透 Doze,只是时间有偏差am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,triggerAt,pendingIntent)}

权限上有两个坑:

  • SCHEDULE_EXACT_ALARM(Android 12+):用户可撤销,必须运行时判断canScheduleExactAlarms();
  • USE_EXACT_ALARM(Android 13+):仅限闹钟、日历等以精确时间为核心功能的应用,Google Play 有明确的用途审核,别拿来当"免申请精确闹钟"的后门。

3.5 电池优化白名单:能要,但要说清为什么

valpm=context.getSystemService(PowerManager::class.java)if(!pm.isIgnoringBatteryOptimizations(packageName)){// 先给用户一个"为什么"的说明页,再跳转,转化率会高很多startActivity(Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).setData(Uri.parse("package:$packageName")))}

注意:Google Play 对REQUEST_IGNORE_BATTERY_OPTIMIZATIONS的使用场景有白名单限制(报警、VoIP 等),滥用会被下架。要在隐私政策与商店说明里写清楚用途。

3.6 厂商自启动 / 后台白名单:没有统一 API,只能好好引导

这是国内场景绕不开的一环,但要接受一个现实:没有稳定、官方支持的跳转接口。

  • 各家设置路径都不同(MIUI 自启动、华为"应用启动管理"、OPPO/vivo"后台高耗电"、三星"未监控的应用"…),写死厂商 Activity 的做法会随 ROM 版本失效;
  • 稳妥做法:先try/catch尝试跳转,失败就兜底到本应用详情页,让用户自己找到开关;
// 兜底方案:永远不会失效startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.parse("package:$packageName")))
  • 更好的做法是在 App 内做图文引导(机型识别 + 截图指引),比直接甩一个系统设置页有效得多。

3.7 如果是真有硬件,用CompanionDeviceManager

应用确实要长期和 BLE 设备(手环、车机、健康设备)保持连接时,Android 12+ 的CompanionDeviceService是官方为你准备的正当方案,系统会给予后台运行豁免。

前提是:你真的有配对设备。为了保活伪造一个 BLE 关联,既过不了审核,也拿不到系统信任。

3.8 系统绑定服务:功能必须匹配

NotificationListenerService、AccessibilityService、DeviceAdminService、VpnService都能带来极高的进程优先级,但它们都有强烈的"用途契约":

  • 通知监听 → 你要真的做通知聚合/过滤;
  • 无障碍 → 你要真的有辅助功能(否则属高危,Play 会重点审查);
  • VPN → 你要真的做流量处理,而不是建一个 127.0.0.1 的回环隧道;
  • DeviceAdmin → 你要真的是企业设备管理场景。

"为了保活而申请"是这个领域最常见的自杀行为:要么审核不过,要么被用户投诉后下架。


四、明确劝退的反模式(红线)

下面这些在技术上都"做得到",但我不建议你在任何要上架的产品里使用,理由写在后面。

反模式为什么不要做
1 像素 / 透明 Activity 拉活违反 Android 10+ 后台启动 Activity 限制;"莫名弹出"是用户投诉与"欺骗行为"判定的高发点
播放无声音频抢占音频焦点、显著增加耗电;部分 ROM 直接判定异常进程
空 SyncAdapter / 空账户 只为触发同步账户与同步必须有真实用途,属审核重点
双进程 / 空进程互拉Android 8+ 后台服务限制下已基本失效,且明确被视为滥用
滥用 MediaStyle / CallStyle 绕过POST_NOTIFICATIONS这是绕过权限管控,与 Android 13+ 的通知权限设计初衷冲突,风险极高
反射隐藏 API、直调 AMS、“防强停”用户在设置里点"强制停止"是明确意图;对抗它=更高的卸载率 + 市场审核风险
am instrument拉活滥用测试框架,属明确异常行为

需要特别说明"防强停":这类方案在某些灰色场景(如靠后台复活刷广告曝光)里被当作卖点,但对正经产品它是负资产——你对抗的是掏钱买你服务的用户,赢了一次强停,输掉的是留存和口碑。

合规上还有一条通用红线:Google Play 的Device and Network Abuse、Foreground Service 政策,以及国内各应用市场的后台行为规范,都会对上述行为做拦截或下架处理。


五、落地:指标 + 选型表

5.1 建议埋点的指标

指标采集方式用来判断
进程退出原因分布ApplicationExitInfo死因构成,方向对不对
前后台切换时间点onTrimMemory(TRIM_MEMORY_UI_HIDDEN)/ProcessLifecycleOwner被杀时是否在后台
冷启动次数 / 日启动埋点去重存活率最直观的代理指标
推送到达率推送平台侧数据最终业务指标,比存活率更重要
前台服务时长与超时次数onTimeout()回调Android 15 时长限制是否踩线

5.2 场景 → 方案

场景推荐组合
IM / 社交消息厂商推送 + 前台服务(dataSync)+ WorkManager 兜底
音乐 / 播客播放前台服务(mediaPlayback)+ MediaSession(真播放时)
导航 / 运动轨迹前台服务(location)+ 精准闹钟
IoT / BLE 外设CompanionDeviceService+ 前台服务
企业设备管理Device Owner +DeviceAdminService
天气 / 资讯定时刷新WorkManager(15 分钟 +)
闹钟 / 提醒类精确闹钟 +USE_EXACT_ALARM(符合政策前提)

六、上线前检查清单

  • 已用ApplicationExitInfo统计过真实死因分布,且方向与数据匹配
  • 前台服务:类型选对、FOREGROUND_SERVICE_*权限齐全、通知用户可见
  • Android 15 时长限制场景已实现onTimeout()收尾
  • 已完成 FCM / 厂商推送接入,消息链路不依赖"进程活着"
  • 精确闹钟做了canScheduleExactAlarms()判断与降级
  • 电池优化白名单、自启动引导均有用途说明,且跳转有兜底
  • 未使用第四节表格里的任何反模式
  • 隐私政策、商店说明与申请的权限一一对应
  • 真机矩阵覆盖:小米 / 华为 / OPPO / vivo / 三星 / 原生

结语

后台存活率这件事,核心不是"堆多少种保活手段",而是"用对系统给你的那把钥匙":把消息交给推送通道,把可延迟任务交给 WorkManager,把持续工作交给带正确类型的前台服务,把系统限制的边界用引导和授权去沟通——而不是去绕过它。

你的机型上有遇到过REASON_OTHER特别高的死亡姿势吗?欢迎在评论区贴出你的exitReason分布,一起看看是谁在动手。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询