7、后台限制:Android 9+的后台限制演进
说起后台限制,我脑子里第一个蹦出来的词就是「猫鼠游戏」。
Android 从 9 开始,对后台的管控越来越严。说白了,就是系统不想让 App 在后台偷偷干活。你想想看,如果每个 App 都在后台跑服务、定位置、弹通知,用户的手机电量撑不过半天。
我个人习惯把后台限制分为三个阶段:9.0 的初步收紧、10.0 的细化规则、11+ 的彻底锁死。下面我带你一个个看。
核心观点:Android 后台限制的本质是「权限收缩」——系统不再信任 App 的后台行为,除非你通过前台服务或高优先级消息证明自己「值得被信任」。
7.1 后台服务限制
Android 9 开始,系统对后台服务下了狠手。具体来说:应用进入后台后,几秒钟内系统就会停止它的后台服务。除非你把它变成前台服务(带通知栏通知的那种)。
我在项目中遇到过一个问题:某个音乐播放器,用户切到后台后音乐就停了。排查下来发现,开发同学直接用 startService() 启动了一个普通 Service,没有调用 startForeground()。嗯,这在 Android 9 之前没问题,但 9 之后直接被杀。
避坑指南:我曾经在适配 Android 9 时,把所有后台服务都改成了前台服务。但要注意——前台服务必须在 5 秒内调用 startForeground(),否则系统会抛出 RemoteServiceException 并崩溃。所以我的习惯是:在 onStartCommand() 里第一行就调用 startForeground()。
代码示例(前台服务标准写法):
public class MyForegroundService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 必须在 5 秒内调用 startForeground
Notification notification = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("服务运行中")
.setContentText("正在后台执行任务")
.setSmallIcon(R.drawable.ic_notification)
.build();
startForeground(1, notification);
// 执行实际任务...
return START_STICKY;
}
}
7.2 后台位置限制
位置权限是后台限制的重灾区。Android 9 开始,后台获取位置信息需要额外权限:ACCESS_BACKGROUND_LOCATION。而且用户可以在设置里随时关闭。
你想想看,如果外卖 App 在后台一直定位,你的电量会掉得飞快。所以系统要求:只有用户明确授予「始终允许」权限,App 才能在后台获取位置。
我记得有一次做地图导航 App,用户反馈「为什么我切到后台后导航就不动了?」。查了日志发现,用户只给了「仅在使用期间允许」权限。这在 Android 10 之后是正常行为——后台位置权限必须单独申请。
警告:千万不要在用户拒绝后台位置权限后反复弹窗。Google Play 会判定为「权限滥用」,直接下架。我见过一个健身 App 因为这个被下架了,开发者花了三周才重新上架。
后台位置权限申请流程(Android 10+):
- 先申请前台位置权限(
ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION) - 用户同意后,再申请后台位置权限(
ACCESS_BACKGROUND_LOCATION) - 如果用户拒绝,不能再次自动弹窗,只能引导用户去设置页面手动开启
7.3 后台启动限制
这个限制很有意思。Android 9 开始,后台应用不能随意启动 Activity 或 Service。比如,你收到一条推送,点击后想跳转到一个 Activity——如果 App 在后台,系统会拦截这个启动请求。
为什么会这样?因为很多恶意 App 会在后台偷偷启动广告页面,或者诱导用户点击。系统干脆一刀切:后台应用不能启动任何组件,除非满足特定条件。
我个人的经验是:后台启动 Activity 的唯一可靠方式是通过 Notification 的 PendingIntent。用户点击通知时,系统会认为这是用户主动操作,允许启动。
关键点:Android 10 进一步收紧了后台启动 Activity 的规则。只有以下场景允许后台启动:
- 应用拥有可见窗口(比如画中画模式)
- 应用拥有前台服务
- 应用接收到高优先级推送(FCM 的 high_priority)
- 用户主动点击通知或快捷方式
代码示例(通过通知启动 Activity 的正确方式):
Intent intent = new Intent(this, TargetActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Notification notification = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("新消息")
.setContentText("点击查看详情")
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_notification)
.build();
7.4 后台限制的演进总结
我把 Android 9 到 11 的后台限制变化整理成了表格,方便你对照:
| 限制类型 | Android 9 | Android 10 | Android 11+ |
|---|---|---|---|
| 后台服务 | 后台应用几秒后停止服务 | 同上,但增加白名单机制 | 前台服务必须显示通知 |
| 后台位置 | 需要后台位置权限 | 权限分离,需单独申请 | 强制用户授权才能获取 |
| 后台启动 Activity | 基本禁止 | 仅限特定场景 | 几乎完全禁止 |
| 后台启动 Service | 禁止(除前台服务) | 禁止(除白名单) | 禁止(除系统组件) |
说实话,这些限制对普通用户是好事。但对开发者来说,适配起来确实有点头疼。我的建议是:尽早适配,不要等到用户反馈问题再改。因为一旦用户手机升级到新系统,你的 App 可能直接无法正常工作。
个人技巧:我习惯在开发阶段就用 Android 11 或 12 的真机测试。模拟器有时候表现和真机不一样。尤其是后台限制,真机上更严格。我曾经在模拟器上测试没问题,结果真机上后台服务直接被杀,排查了半天才发现是模拟器没有正确模拟后台限制。
最后说一句:后台限制只会越来越严。Android 12 和 13 又增加了「休眠」和「极致省电」模式。所以,设计 App 架构时,尽量把核心逻辑放在前台服务或 WorkManager 中,不要依赖后台常驻服务。这是未来的趋势。
公众号:蓝海资料掘金营,微信deep3321