引言:Android 12 及以上版本中“损坏”的播放器
\n想象一下:您自豪地发布了播放器或播客客户端应用的更新。几天后,评论区域出现了愤怒的评论:“更新后音乐无法播放!”,“锁屏按钮不工作!”,“尝试启动曲目时应用崩溃!”。听起来很熟悉?您很可能遇到了困扰全球数千名开发者的那个错误:
\nMediaSessionCompat: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent\n这个问题是 Stack Overflow 上最热门的问题之一(数万次浏览),它直接与 Android 12(API level 31)中的更改相关。好消息是:修复方法很简单,只需不到 10 分钟。在本文中,我们将分析错误原因、正确的 Kotlin 解决方案以及最佳实践,让您的应用再次稳定运行。
\n\n为什么会出现错误?了解 PendingIntent
\n要理解问题的本质,我们需要回顾一下 MediaSessionCompat 的工作原理。这是一个组件,允许您的应用与系统媒体控件交互:耳机按钮、锁屏、通知面板。为此,它会创建一个 PendingIntent——一种用于系统服务的“延迟调用”。系统使用此 Intent 来告诉您的应用:“用户按下了播放/暂停/下一首”。
从 Android 12(API 31)开始,Google 加强了对 PendingIntent 的安全要求。以前,开发者可以不指定 FLAG_IMMUTABLE 或 FLAG_MUTABLE 标志,系统默认使用可变(mutable)版本。现在,您必须明确指定系统在创建后是否可以修改您的 Intent 的内容。如果您不这样做,应用就会崩溃。Android 12+ 根本不允许创建这样的 PendingIntent。
FLAG_IMMUTABLE vs FLAG_MUTABLE:如何选择?
\n- \n
- FLAG_IMMUTABLE(推荐):创建后 Intent 不可修改。这更安全,因为攻击者无法篡改数据。在 90% 的情况下使用此标志,包括用于
MediaSessionCompat。 \n - FLAG_MUTABLE:Intent 可以修改。仅在特殊情况下需要,例如,如果您使用需要动态数据的
NotificationCompat操作,或者在使用AlarmManager时。 \n
对于 MediaSessionCompat 和媒体通知,始终使用 FLAG_IMMUTABLE。这可以提高应用的安全性和稳定性。
Kotlin 逐步修复
\n让我们看看典型导致错误的代码是什么样的,以及如何修复它。最常见的问题出现在您的服务或媒体浏览器的 onCreate() 方法中。
错误代码(会在 Android 12+ 上导致崩溃)
\n// 旧方法——未指定标志\nval pendingIntent = PendingIntent.getActivity(\n this,\n 0,\n Intent(this, MainActivity::class.java),\n 0 // <-- 错误!没有 FLAG_IMMUTABLE 或 FLAG_MUTABLE\n)\n\n正确的 Kotlin 代码(修复)
\n只需在最后一个参数中添加 PendingIntent.FLAG_IMMUTABLE:
val pendingIntent = PendingIntent.getActivity(\n this,\n 0,\n Intent(this, MainActivity::class.java),\n PendingIntent.FLAG_IMMUTABLE // <-- 解决方案!\n)\n如果您的应用支持更旧的 Android 版本(低于 API 31),请使用条件检查以避免在旧设备上崩溃:
\nval flags = if (Build.VERS