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" />
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 适配版)
把上面的知识点串起来,一个完整的适配流程应该是这样的:
- 在 Manifest 中声明
foregroundServiceType - 检查并申请
POST_NOTIFICATIONS权限 - 创建通知渠道(Notification Channel)
- 构建通知并调用
startForeground() - 在服务结束时调用
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_LOW 或 IMPORTANCE_MIN,这样不会发出声音打扰用户。如果是媒体播放类服务,可以用 IMPORTANCE_LOW 配合媒体样式。
10.5 知识体系总览
为了让你更直观地理解 Android 13 前台服务的整体变化,我画了一张流程图:
10.6 避坑指南
最后,分享几个我踩过的坑:
- 不要忘记声明类型:Android 14 会强制检查,但 Android 13 只是警告。别等到用户升级系统才发现问题。
- 权限拒绝后的降级方案:如果用户拒绝了通知权限,你可以考虑用
WorkManager替代前台服务,或者提示用户手动开启权限。 - 测试要覆盖所有类型:不同厂商对
camera、location等敏感类型的处理方式不同。我曾经在某个品牌手机上发现,声明了camera类型后,系统会额外弹一个隐私提示。 - 通知渠道的重要性:Android 8.0 之后就必须创建通知渠道了。如果你忘了,前台服务通知可能根本不会显示。
嗯,以上就是 Android 13 前台服务适配的核心内容。说白了就是两件事:申请通知权限、声明服务类型。但这两件事做不好,你的应用在 Android 13+ 设备上就会出问题。我建议你现在就去检查一下项目里的前台服务,看看有没有遗漏的声明。