10、前台服务与通知:Android 13通知权限变更,前台服务类型声明

聊到前台服务,很多开发者的第一反应就是「加个通知就行了」。嗯,在 Android 13 之前,确实差不多是这样。但到了 Android 13(API 33),事情变得复杂了不少。我个人习惯把这次变更称为「前台服务的合规化运动」——系统开始认真管你了。

10.1 通知权限的变更:从「默认允许」到「运行时申请」

先说说最直观的变化。Android 13 引入了一个新的运行时权限:POST_NOTIFICATIONS。这意味着你的应用如果想弹出通知,必须像申请定位、相机那样,弹窗让用户同意。

你可能会问:「那我的前台服务怎么办?前台服务不是必须要有通知吗?」

没错,这是个死循环。前台服务必须显示通知,但通知又需要用户授权。如果用户拒绝了通知权限,你的前台服务就启动不了。我在项目中遇到过这个坑,当时测试机升级到 Android 13 后,后台下载服务直接崩溃了,日志显示是 ForegroundServiceStartNotAllowedException

注意: 如果用户拒绝了通知权限,调用 startForeground() 会抛出异常。你需要捕获这个异常,或者提前检查权限状态。

解决方案其实不复杂。你需要在启动前台服务之前,先检查并申请通知权限。代码示例如下:

// 检查通知权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
    != PackageManager.PERMISSION_GRANTED) {
    // 申请权限
    ActivityCompat.requestPermissions(activity,
        new String[]{Manifest.permission.POST_NOTIFICATIONS},
        REQUEST_CODE_NOTIFICATION);
} else {
    // 权限已授予,启动前台服务
    startForegroundService(intent);
}

这里有个细节:如果你的应用 targetSdkVersion 低于 33,系统会帮你自动授予通知权限。但一旦你升级到 33,就必须走申请流程。我建议尽早适配,别等到用户反馈说「你的应用怎么不工作了」才去改。

10.2 前台服务类型声明:dataSync、camera 等

Android 13 还引入了一个新要求:前台服务必须声明类型。说白了,你得告诉系统「我这个前台服务是干嘛用的」。系统会根据类型来施加不同的限制。

目前官方定义的类型包括:

类型 用途 典型场景
dataSync 数据同步/上传/下载 文件下载、备份、同步
camera 相机预览/录制 拍照、视频录制
microphone 麦克风录制 录音、语音识别
location 位置追踪 导航、运动追踪
connectedDevice 与外部设备通信 蓝牙、NFC、USB
mediaPlayback 媒体播放 音乐播放、视频播放
phoneCall 通话相关 VoIP、电话
health 健康监测 心率、步数

声明方式很简单,在 AndroidManifest.xml<service> 标签里加上 android:foregroundServiceType 属性:

<service
    android:name=".DownloadService"
    android:foregroundServiceType="dataSync"
    android:exported="false" />

如果你的服务同时做多件事,可以用 | 分隔:

<service
    android:name=".MediaService"
    android:foregroundServiceType="mediaPlayback|microphone"
    android:exported="false" />
关键点: 从 Android 14 开始,如果你没有声明 foregroundServiceType,系统会直接拒绝启动前台服务。所以现在适配 Android 13 其实是在为未来铺路。

10.3 前台服务类型的运行时检查

除了在 Manifest 中声明,你还可以在运行时检查当前服务支持的类型。这个 API 是 Service.getForegroundServiceType(),返回一个整数掩码。我个人习惯在调试时打印出来看看:

int type = getForegroundServiceType();
if ((type & FOREGROUND_SERVICE_TYPE_DATA_SYNC) != 0) {
    Log.d(TAG, "当前服务支持 dataSync 类型");
}

为什么要做运行时检查?因为有些厂商定制 ROM 可能会对前台服务类型做额外限制。我曾经遇到过某款国产手机,明明声明了 dataSync,但系统还是把服务给杀了。后来发现是厂商自己加了一套白名单机制。

10.4 前台服务启动流程(Android 13 适配版)

把上面的知识点串起来,一个完整的适配流程应该是这样的:

  1. 在 Manifest 中声明 foregroundServiceType
  2. 检查并申请 POST_NOTIFICATIONS 权限
  3. 创建通知渠道(Notification Channel)
  4. 构建通知并调用 startForeground()
  5. 在服务结束时调用 stopForeground()stopSelf()

这里我贴一个完整的服务启动代码片段:

public class SyncService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 1. 检查通知权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)
                != PackageManager.PERMISSION_GRANTED) {
                stopSelf();
                return START_NOT_STICKY;
            }
        }

        // 2. 创建通知渠道
        createNotificationChannel();

        // 3. 构建通知
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("正在同步数据")
            .setContentText("请保持应用运行")
            .setSmallIcon(R.drawable.ic_sync)
            .build();

        // 4. 启动前台服务
        startForeground(NOTIFICATION_ID, notification);

        // 5. 执行实际任务
        doSyncWork();

        return START_STICKY;
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                CHANNEL_ID,
                "数据同步",
                NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }
}
小技巧: 前台服务的通知建议使用 IMPORTANCE_LOWIMPORTANCE_MIN,这样不会发出声音打扰用户。如果是媒体播放类服务,可以用 IMPORTANCE_LOW 配合媒体样式。

10.5 知识体系总览

为了让你更直观地理解 Android 13 前台服务的整体变化,我画了一张流程图:

Android 13 前台服务适配流程 1. 声明 foregroundServiceType 2. 检查 POST_NOTIFICATIONS 已授权? 申请权限 3. 创建通知渠道 4. startForeground() 5. 执行后台任务

10.6 避坑指南

最后,分享几个我踩过的坑:

  • 不要忘记声明类型:Android 14 会强制检查,但 Android 13 只是警告。别等到用户升级系统才发现问题。
  • 权限拒绝后的降级方案:如果用户拒绝了通知权限,你可以考虑用 WorkManager 替代前台服务,或者提示用户手动开启权限。
  • 测试要覆盖所有类型:不同厂商对 cameralocation 等敏感类型的处理方式不同。我曾经在某个品牌手机上发现,声明了 camera 类型后,系统会额外弹一个隐私提示。
  • 通知渠道的重要性:Android 8.0 之后就必须创建通知渠道了。如果你忘了,前台服务通知可能根本不会显示。

嗯,以上就是 Android 13 前台服务适配的核心内容。说白了就是两件事:申请通知权限、声明服务类型。但这两件事做不好,你的应用在 Android 13+ 设备上就会出问题。我建议你现在就去检查一下项目里的前台服务,看看有没有遗漏的声明。


公众号:蓝海资料掘金营,微信deep3321