Skip to content

MediaSessionCompat 中 PendingIntent 标志的 Android 12 适配

问题概述

当应用程序以 Android 12(API 级别 31)或更高版本为目标平台时,使用 MediaSessionCompat 可能会遇到以下崩溃错误:

java
java.lang.IllegalArgumentException: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.

这个错误是由于 Android 12 对 PendingIntent 的安全性要求变更引起的。从 Android 12 开始,所有 PendingIntent 必须明确指定可变性标志:FLAG_IMMUTABLEFLAG_MUTABLE

根本原因

在 Android 12 之前,MediaSessionCompat 内部创建的 PendingIntent 可能没有明确指定这些标志。当应用以 Android 12 为目标平台时,系统会强制执行这一新的安全要求,导致应用崩溃。

解决方案

方法一:更新 MediaSessionCompat 的初始化方式

如果您直接使用 MediaSessionCompat,可以手动创建并传递带有适当标志的 PendingIntent

java
override fun onCreate() {
    super.onCreate()
    
    val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON)
    val pendingIntent = PendingIntent.getBroadcast(
        applicationContext,
        0, 
        mediaButtonIntent,
        PendingIntent.FLAG_IMMUTABLE
    )
    
    mediaSession = MediaSessionCompat(this, TAG, null, pendingIntent).apply {
        setCallback(mediaSessionCallback)
        isActive = true
    }
}

方法二:使用条件标志设置

对于需要兼容不同 Android 版本的应用,可以使用条件语句设置适当的标志:

java
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    PendingIntent.FLAG_IMMUTABLE
} else {
    PendingIntent.FLAG_UPDATE_CURRENT // 或其他适用于旧版本的标志
}

val pendingIntent = PendingIntent.getBroadcast(
    context,
    requestCode,
    intent,
    flags
)

标志选择建议

  • FLAG_IMMUTABLE:大多数情况下推荐使用,提供了更好的安全性
  • FLAG_MUTABLE:仅在需要修改 PendingIntent 内容时使用(如内联回复或气泡通知)

方法三:更新相关依赖库

有时问题可能来自间接依赖的旧版本库。更新以下常用库可以解决问题:

gradle
// Kotlin
implementation 'androidx.work:work-runtime-ktx:2.7.1'

// Java
implementation 'androidx.work:work-runtime:2.7.1'

// 媒体库
implementation 'androidx.media:media:1.4.1'

// Google Play 服务广告库
implementation 'com.google.android.gms:play-services-ads:22.2.0'

// Firebase 消息
implementation 'com.google.firebase:firebase-messaging:23.0.0'

方法四:检查并更新所有相关依赖

使用以下命令检查项目中的依赖关系,找出可能使用旧版本 work-runtime 的库:

bash
./gradlew app:dependencies

更新所有使用旧版本 Android WorkManager 的依赖项。

特殊情况处理

使用 Chuck 库的情况

如果您使用了网络调试库 Chuck,请更新到最新版本:

gradle
debugImplementation "com.github.chuckerteam.chucker:library:3.5.2"
releaseImplementation "com.github.chuckerteam.chucker:library-no-op:3.5.2"

Ionic/Cordova 项目

对于混合应用开发,确保插件使用了正确的 Play 服务版本:

xml
<plugin name="cordova-plugin-google-analytics" spec="1.8.6">
    <variable name="PLAY_SERVICES_VERSION" value="18.0.1" />
    <variable name="GMS_VERSION" value="18.0.1" />
</plugin>

版本要求说明

从以下版本开始,AndroidX 媒体库已修复此问题:

  • androidx.media:media:1.3.0-rc02 开始支持 FLAG_IMMUTABLE
  • androidx.media:media:1.4.1 正式修复了此问题

结论

解决 Android 12 中 MediaSessionCompatPendingIntent 问题主要有三种方法:

  1. 直接解决方案:手动创建带有适当标志的 PendingIntent 并传递给 MediaSessionCompat
  2. 依赖更新:确保所有相关库(特别是 work-runtime)都已更新到兼容版本
  3. 条件处理:根据 Android 版本动态选择正确的 PendingIntent 标志

推荐优先考虑更新库的解决方案,因为这通常能解决更深层次的兼容性问题,并提供更好的长期维护性。

注意事项

  • 确保测试应用在所有目标 Android 版本上的兼容性
  • 如果使用 FLAG_MUTABLE,请确保确实需要可变 PendingIntent 的功能
  • 检查所有使用 PendingIntent 的地方,确保都符合 Android 12 的要求