7、后台限制:Android 9+的后台限制演进

说起后台限制,我脑子里第一个蹦出来的词就是「猫鼠游戏」。

Android 从 9 开始,对后台的管控越来越严。说白了,就是系统不想让 App 在后台偷偷干活。你想想看,如果每个 App 都在后台跑服务、定位置、弹通知,用户的手机电量撑不过半天。

我个人习惯把后台限制分为三个阶段:9.0 的初步收紧10.0 的细化规则11+ 的彻底锁死。下面我带你一个个看。

核心观点:Android 后台限制的本质是「权限收缩」——系统不再信任 App 的后台行为,除非你通过前台服务或高优先级消息证明自己「值得被信任」。

Android 9+ 后台限制演进 Android 9 初步收紧 • 后台服务限制 • 后台位置限制 • 后台启动限制 (后台运行的应用 不能随意启动服务) Android 10 细化规则 • 后台启动 Activity 限制 • 后台位置访问权限 • 后台服务白名单机制 (只有特定场景 才能启动 Activity) Android 11+ 彻底锁死 • 后台位置权限强制 • 后台启动强制限制 • 前台服务通知要求 (所有前台服务 必须显示通知)

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+):

  1. 先申请前台位置权限(ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION
  2. 用户同意后,再申请后台位置权限(ACCESS_BACKGROUND_LOCATION
  3. 如果用户拒绝,不能再次自动弹窗,只能引导用户去设置页面手动开启

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