
手机上开着音乐切到微信歌还在唱导航切到后台语音一路没断可有些App刚离开屏幕不到半分钟再切回来就重新加载启动页了。同样是“切后台”差别为什么这么大答案不在App自己多倔强而在系统把App分成了“前台工作”和“后台工作”两套完全不同的状态各有各的限额和规矩。搞懂这套规矩普通用户能少装一堆清理软件开发者能少写几百行没用的保活代码。这篇文章从系统视角、开发视角和普通用户视角把前后台机制拆开讲重点放在状态切换、后台任务白名单和几个高频踩坑点上适合刚接触App开发的工程师也适合对自己手机后台行为好奇的人。1. 先分清“前台”和“后台”系统眼中的App状态比你想的更严格你一直盯着屏幕操作的那个App叫“前台App”切走之后它进“后台”。但“后台”不是一个大箩筐往里一丢就完事。手机系统为了在“流畅、省电、内存够用”三者之间找平衡给每个App标了优先级。优先级高的优先占用资源优先级低的等内存不够了先被杀。1.1 用户切走App之后系统按什么顺序回收内存Android把一个进程从高到低分了几个级别正常情况下系统不会乱杀只有内存吃紧时才按这个顺序动手进程级别什么时候算系统态度典型场景前台进程屏幕上有Activity正在交互或者持有前台服务最高优先级基本不回收你正在聊天的页面可见进程没有输入焦点但部分界面仍可见高危时才回收被弹窗、分屏遮住一半页面服务进程开了Service在后台跑没有界面内存不足时回收只放音乐不带界面的进程缓存进程用户已经离开页面还在内存里排队内存吃紧时第一个被清理很久没打开的历史页面iOS的说法不太一样它把App的运行状态分成 Active前台活跃、Inactive短暂失焦比如来电、下拉通知栏、Background退到后台代码还能跑一会儿、Suspended挂起代码冻结。Suspended状态很像“缓存进程”进程还在内存里但代码不执行了内存不够时系统直接把它清掉。用餐厅打个比方前台是有客人在桌边等着点菜后厨是备菜师傅还能干活冷藏室里存放的食材算“冻结状态”食材放着没问题但锅不够用、地方不够用时最先扔掉的就是冷藏室里放最久的东西。App被“杀后台”大多数情况下不是它犯了错而是系统内存的压力自己做了取舍。1.2 前后台切换时的生命周期回调App自己知道发生了什么系统切换App状态时会通过一套回调通知App。Android里最常见的是onPause、onStop、onResume这套组合拳。用户按Home键切走当前Activity先走onPause再走onStop用户再切回来会走onRestart和onStart最后onResume。iOS侧对应的是applicationDidEnterBackground和applicationWillEnterForeground近几年还要结合scenePhase这类新API。为什么开发者必须关心这些回调因为它们是 App 保存状态、停掉定时器、释放摄像头麦克风的“最后窗口”。我见过不少App把草稿存在onDestroy里结果用户一按Home键系统把进程杀了草稿根本没机会存——正确做法是在onStop里做持久化。同样从后台回前台时你要在这里刷新数据、判断用户是否离开太久、决定要不要重新上锁。这里面有个很常见的误区生命周期回调不等于进程被杀。用户把App切到后台Android的Activity会立刻走onStop但进程本身多半还活着。所以你不能拿“App在后台”当成“App一定被杀了”。判断“活着还是死了”和判断“前台还是后台”是两件不同的事后面第4章专门讲。2. 前台App到底在忙什么渲染、传感器、网络一肩挑用户正盯着屏幕App要做的事远比想象多。手机屏幕每秒钟要刷新几十上百次哪怕你只是手指头划了一下背后也牵扯一整条流水线。前台状态之所以“特权和吃力并存”是因为系统把所有资源倾斜给你同时也要求你别掉链子。2.1 从触摸到屏幕刷新前台的“主线程”在跑什么你点一下屏幕触摸事件先交给系统再派发给App的主线程也叫UI线程。主线程要做的事包括处理触摸事件、更新界面布局、执行绘制代码然后把画面交还给系统合成并显示。屏幕有固定刷新率60Hz的屏幕每16.7毫秒刷一帧120Hz的屏幕只有8.3毫秒。如果主线程在一帧时间内没干完活这一帧就错过了表现出来就是卡顿、掉帧。所以前台开发的铁律是别在主线程上做耗时操作。网络请求、大文件读写、图片压缩这类活能丢到子线程就丢到子线程。很多App一启动就卡就是因为把一堆初始化任务全堆在onCreate里做用户看到的启动画面被拖得又臭又长。建议把启动时非必要的任务延后加载优先保证首屏能画出来。顺带说一句App退到后台之后系统会降低它的刷新率甚至暂停动画渲染。后台卡不卡用户根本看不到所以省电优先。这也是为什么有些App回前台时会“突然流畅一下”系统在恢复你回前台后的完整渲染能力而已。2.2 前台才能放开用的权限摄像头、麦克风、定位和网络前台App可以直接调摄像头、麦克风、GPS、高频网络请求系统基本不限制因为用户正在使用这些消耗是合理的。但一旦退到后台规则就变了Android从9.0开始限制了后台App访问摄像头和麦克风Android 10之后对后台定位权限收得更紧iOS同样要求App声明后台定位用途否则切后台定位就不回调了。这里有个普通用户能直观感知的点现在很多手机在状态栏显示一个绿点或橙点分别代表摄像头或麦克风正在被调用。你如果发现某个App只在后台却有绿点提示它大概率在前台或者通过前台服务拿到了相机/麦克风权限这时候你要警惕是不是有没必要的偷拍行为。对开发者来说拿到权限只是第一步向用户说清楚“为什么需要”更重要否则审核和口碑都过不去。系统对前台开放权限本质上是一种“信任交换”我信任你在用户眼前做的事是合理的。一旦你滥用退回后台还在拼命采集数据系统就会用限制权限、减少唤醒、杀进程来惩罚你。这也解释了为什么“一直开着定位”的App往往更容易被系统切后台。2.3 App底部一级导航栏为什么是前台体验的“门面”讲个偏产品但和前台直接相关的细节底部一级导航栏。淘宝、美团、微信这类App几乎都是底部几个Tab作为一级入口一般控制在3到5个。为什么是底部因为拇指最好按。为什么是一级因为导航层级越浅用户找到功能的成本越低这是前台体验设计里最朴素的原则。从技术角度看底部Tab切换时每个Tab页面都要处理自己的生命周期。用户在首页切到“我的”再切回来首页经历了类似onPause → onStop → onStart → onResume的过程具体和Fragment/ViewController实现有关。好的App会在这时保存列表滚动位置、避免重复拉数据做得糙的App每次切换都重新请求一遍接口用户体感就是“页面老是刷一下”。这一前一后恰恰是“前台体验”最容易被用户感知的差异之一。还有一种特殊的前台边界场景用户在浏览器里点了“打开App”系统会尝试唤起已安装的App。如果App之前还活着它从后台切回前台要处理浏览器传过来的链接参数如果App已经被系统杀了就得冷启动链路更长。iOS上这几年越来越推荐用Universal Link而不是自定义URL Scheme因为URL Scheme容易被系统拦而且首次安装后域名验证往往有个延迟窗口。这个领域是H5和原生协作的重灾区后面在常见问题表里我单独列一条。3. 后台App凭什么还能干活任务白名单与保活实战很多用户以为“App退到后台还跑就是流氓”其实不完全对。后台任务分合法和非法系统给正规后台任务开了专门的通道不给那些偷偷摸摸的杂活留门。对开发者来说理解这套白名单机制比跟系统对着干管用得多。3.1 后台真正能“合法”执行的任务系统给你列了个清单能够合法在后台跑的任务基本就这几类音频/视频播放、后台定位、后台下载上传、VoIP通话、蓝牙外设交互、推送到达提醒。Android和iOS处理方式不同Android用前台服务Foreground Service来实现。App必须发一条通知栏常驻通知告诉用户“我还在跑”然后系统把进程优先级抬高不容易被杀。iOS在项目里声明UIBackgroundModes声明了哪类后台能力系统才允许你在对应场景下继续执行而且App Store审核时会对用途做检查。我见过一个音乐App为了后台播放Android端没做前台服务结果一锁屏音乐就断。正确做法是启动播放服务时调用startForeground()并绑定通知渠道把“正在播放”的通知挂出来。注意Android 8.0以后要求必须建通知渠道Android 14以后前台服务还要声明具体类型音乐播放、定位、数据同步等类型对不上启动就崩。后台任务类型Android 实现iOS 实现能活多久音乐播放前台服务 媒体通知声明 audio 后台模式持续到用户暂停或服务停止后台定位前台服务 后台定位权限声明 location 后台模式 始终授权持续回调但受系统省电策略影响后台下载WorkManager 或前台服务URLSession 后台会话由系统调度不保证即时完成推送推送服务接收消息APNs 推送只是展示提醒不能后台跑代码普通延时任务不保证建议 WorkManagerbeginBackgroundTask 约30秒很短别指望长期3.2 实例做一个App后台定位需要配置什么后台定位是所有后台任务里踩坑最多的一个我拿 uni-app 跨端开发来演示因为很多人用这套方案做地图、打卡、巡更类App。核心 API 是plus.geolocation.watchPosition它会持续返回位置变化。但“持续”不等于“切后台还能持续”要真正实现后台定位你至少要把下面几件事做齐权限配置Android要声明前台定位权限和后台定位权限ACCESS_BACKGROUND_LOCATION运行时先申请前台定位再引导用户去系统设置里开“允许后台定位”iOS要在manifest.json里声明后台模式location并在App里引导用户把定位授权改成“始终”。启用前台服务Android端后台定位必须配合前台服务用通知栏常驻提示“当前App正在定位”否则很多机型在息屏几秒后就会掐掉定位回调。不同厂商ROM对后台定位还有额外的“自启动”“后台运行”开关经常需要引导用户手动打开。真机验证连接电脑调试时一旦拔掉USB系统对后台行为的限制会明显变严必须拔线后测试。还要留意部分ROM把“省电模式”默认开启定位频率会被拉长到几十秒一次。你调精度的野心再大也顶不住系统想省电的决心。我实测下来Android后台定位稳定运行的前提是前台服务通知别被用户划掉ROM允许自启动后台定位权限开着。缺一个定位就会“时灵时不灵”。iOS侧更简单但也更死板用户没选“始终允许定位”后台就完全不回调选了之后回调频率也不保证系统会根据使用习惯动态调整。3.3 后台能撑多久Android和iOS的时间账开发者和产品经理最关心的问题往往是“我能不能在后台轮询接口每10秒拉一次数据”答案是正规渠道下别这么干。Android的后台进程不保证存活除非你是前台服务或系统白名单iOS的普通App退后台后系统只给一个极短的执行窗口beginBackgroundTask大约30秒左右时间到就挂起之后代码不再执行。所以官方API都在引导开发者用“系统调度”而不是“自己死磕”。Android的 WorkManager 可以在满足条件时执行任务比如“连上WiFi后”“电量充足时”“至少过15分钟”它比你自己写线程稳定得多还省电iOS的 BackgroundTasks 框架也类似把任务交给系统安排时间。把“后台持续跑”当成需求本身往往是产品不成熟的信号——用户真的需要你的App在后台每秒钟都上报位置吗还是只要在有重要变化时通知一次就够了3.4 杀后台软件到底在杀什么很多人手机上装了“杀后台App”或者用系统自带的清理功能。它们的本质是向系统发送指令去终止处于缓存状态的后台进程。注意它杀掉的是系统本来就打算回收的那些进程杀完之后你打开App还是要重新加载省不了多少电反而可能因为频繁冷启动更耗电。“Termux杀后台”这类例子特别典型。Termux是一个终端模拟器类App很多人想在里面挂个监听脚本过夜。如果你不开前台服务通知栏常驻、不给它后台运行权限Android ROM的省电策略大概率在几分钟内就把它杀了。想让它持续跑要么用系统设置里的“允许后台运行”白名单要么让它变成前台服务通知栏一直挂着。这不是App故意坑你而是所有非白名单后台App的共同宿命。我强烈不建议开发者为了“保活”去搞互相拉起、隐藏通知栏、申请一堆无意义权限这些手段。系统判断你的App是“恶意”还是“正常”就是看这些行为模式一旦被判定为高耗电或骚扰型App轻则推送被限制重则应用市场下架。跟系统规则合作远比对抗它长久。4. 开发实操App在前后台切换时如何“感知”和排查“App现在是在前台还是后台”这个问题做埋点、做推送、做音视频通话时马上就会遇到。判断不准就会出现“消息明明来了提示音却不响”“视频通话一切后台就断线”之类的怪问题。4.1 判断App当前在前台还是后台三种常用方案第一种是维护页面生命周期计数。每个Activity或页面启动时计数1销毁时计数-1计数大于0说明至少有一个页面在前台。优点是实现简单缺点是页面A被页面B全屏覆盖时A已经不可见了但计数没变容易误判。第二种是用系统提供的能力。Android可以配合ProcessLifecycleOwner它会监听整个进程的ON_START和ON_STOP事件比手动数页面可靠得多。iOS直接用UIApplication.shared.applicationState返回.background或.active非常直接。跨端开发里判断App切前后台通常封装在框架的生命周期钩子里比如 uni-app 的onHide和onShow前端开发者可以直接拿来用。第三种是更“活”的方案监听系统通知和内存警告。比如 Android 的onTrimMemory能告诉你内存紧张程度iOS 的后台通知能告诉你会不会马上被杀。虽然这类信息不能精确判断前后台但对“要不要在这个时候主动保存数据”很有用。三种方案可以组合使用我建议至少要有生命周期计数和系统API两套兜底。4.2 抓包失败、后台网络断连的排查思路调试App时抓包失败是另一个常见却让人头疼的问题。先说最基础的三步确认网络流量转发工具正常工作、确认手机和电脑在同一网络、确认系统证书被正确信任。iOS上还要多做一步在“设置→通用→关于本机→证书信任设置”里手动把证书开关打开否则装了等于没装。Android 7.0以后有个坑App默认不信任用户安装的证书只信任系统证书。你往手机里装了抓包证书很多App照样不认。调试期可以在network_security_config.xml里给debug环境加trust-anchors把用户证书信任开起来或者把证书装进系统证书目录模拟器上操作相对容易。另外如果App工程里做了SSL Pinning证书锁定常规抓包会直接失败这是App有意加固不是工具问题。网络请求一进后台就断开则多半是系统挂起了socket。iOS的App挂起后网络连接会保持但服务器发数据不会唤起它Android更直接进程都可能被杀。如果你在做即时通讯或长连接建议采用系统推送通道做“离线消息提醒”而不是自己在后台维持一个心跳连接。很多IM的“离线推送收不到”问题根源就是后台进程被系统掐了App自己的长连接断了推送通道又没做好兜底。4.3 后台被杀的现场还原看日志找证据“我的App后台被杀”是最难排查的之一因为你没法在进程死掉之后跟它对话。Android上有两个比较可靠的办法。一是连上adb后主动把App切后台观察logcat里有没有am_kill、ActivityManager: Killing ...这样的输出它会记录被杀原因常见的是cached、empty、trim memory。二是用dumpsys activity processes查看当前进程的adj值adj数字越小优先级越高如果某个时刻你的进程adj值很高说明它离被回收不远了。iOS没有统一的“kill日志”但可以靠 Xcode 的 Energy Log 和 MetricKit 看后台占用和启动原因。你发现某个App频繁“因后台CPU过高被挂起”多半是后台代码里有个死循环或者定时器没被正确停掉。记住系统杀后台不一定是因为你犯了错有时只是它单纯缺内存但如果你每次被杀都伴随高CPU占用那就要反思自己的后台设计了。4.4 前后台开发常见的几个坑我踩过的给你列出来现象可能原因解决思路前台服务一启动就崩溃Android 12以后不允许后台直接启动前台服务通知渠道没创建同类型先建通知渠道再按系统要求给前台服务声明类型区分用户主动操作和后台触发iOS浏览器里点“打开App”没反应Universal Link配置延迟/失效URL Scheme被系统拦截优先配Universal Link做URL Scheme兜底首次安装后别立刻测试域名关联切后台后定位完全不回调用户授权是“仅使用期间”没开前台服务ROM省电策略引导“始终允许”定位Android启用前台服务通知给ROM自启动白名单切后台再回来白屏/重新加载Activity被系统回收状态没保存在onSaveInstanceState保存界面状态用ViewModel/懒加载恢复数据推送到了但声音不响进程被杀导致本地通知逻辑失效推送通道未正确配置服务端推送走系统通道客户端别依赖自己长连接来弹通知抓包工具突然抓不到某个App的包SSL Pinning、证书没信任、网络流量没走系统设置配置调试环境的trust-anchors确认证书信任开关必要时用虚拟网卡方式转发流量这些坑的特点都在于“不是代码逻辑错了而是状态边界没处理好”。前后台切换正好是状态边界最密集的地方建议每次发版都按上面这个表过一遍测试用例。5. 普通用户视角不想让App在后台乱忙怎么管讲了这么多开发视角回到普通用户真正关心的问题我怎么知道有没有App在后台偷跑怎么让它们别乱忙其实不需要装额外工具手机系统自带的设置已经足够。5.1 从系统设置看后台消耗App自己说的不算Android的“设置→电池→耗电排行”会列出各个App的耗电占比很多系统还会标注“前台”和“后台”各占多少。如果你看到某个App后台耗电比前台还高这个App大概率在后台做了什么持续性的工作通常是定位、长连接或者唤醒CPU。iOS的“设置→电池”也有类似的电池用量统计按最近24小时或最近10天查看能列出每个App的前台使用时间和后台使用时间。对照这个信息你就能判断谁在偷偷忙。这里提醒一句不要迷信第三方“省电大师”“清理大师”。它们清理掉缓存进程后App重新冷启动的耗电往往比继续留在后台还高省了个寂寞。系统自己的后台管理策略通常已经比第三方工具强得多偶尔手动清理一次就够了。5.2 后台权限的正确收紧方式而不是一杀了之想让某个App别在后台乱忙最有效的方式不是杀进程而是收紧权限。定位权限建议大多数App都选“仅使用期间”只有地图、导航、运动记录这类真正需要后台定位的才改成“始终”通知权限按需开关尤其是电商、社交类App通知不仅是提醒还会唤醒网络刷新Android还可以在系统设置里限制“后台活动”或“自启动”iOS可以关闭“后台App刷新”。“后台App刷新”关掉之后App是不是就彻底不能更新数据了不是。推送消息依然能收到系统级的通知到达不受影响只是App没法在后台自行刷新内容而已。对绝大多数用户来说关掉后天不会塌下来反而续航会明显变好。有一点要说明如果App确实有合理后台需求音乐、导航、外卖配送更新你强行杀后台只会让它功能失灵。比如导航App如果后台定位权限被关锁屏后播报可能就断了。区分“合理需求”和“偷跑”的最好办法就是看它在后台做了什么持续提供用户明确需要的服务叫正常趁机采集位置、频繁唤醒网络发送数据才叫可疑。最后再分享一个个人体会做App时间越长越觉得“你怎么对待后台后台就怎么对待你”。别跟系统硬刚别把用户当傻子该用前台服务用前台服务该走系统调度走系统调度。你顺着系统的规则走用户会觉得你的App省电、流畅、可靠你非要躲在后台偷偷忙系统自然会收拾你。调试后台定位和保活这类需求时我的建议始终是先看ROM和系统设置再看代码逻辑别一上来就怀疑自己哪行代码写错了——很多时候规矩就在系统那一边。