PendingIntent mutability flag
Android 12(API レベル 31)以降をターゲットとするアプリケーションでPendingIntent
を使用する場合、mutability flag(変更可能性フラグ)の明示的な指定が必要になります。この変更により、「Missing PendingIntent mutability flag」というリンター警告が表示される問題とその解決方法について詳しく説明します。
問題の概要
Android 12(targetSdkVersion 31以上)では、PendingIntent
の作成時にFLAG_IMMUTABLE
またはFLAG_MUTABLE
のいずれかのフラグを明示的に指定する必要があります。これまでデフォルトで変更可能とされていたPendingIntent
の動作が変更され、セキュリティが強化されました。
// Android 12以降では以下のコードは警告が発生
val pendingIntent = PendingIntent.getActivity(
context,
requestCode,
intent,
PendingIntent.FLAG_UPDATE_CURRENT // 警告: Missing mutability flag
)
解決方法
基本的な解決策
ほとんどの場合、FLAG_IMMUTABLE
を使用することを推奨します。これはPendingIntent
の内容が変更されないことを保証します。
// Kotlinでの実装例
val pendingIntent = PendingIntent.getActivity(
context,
requestCode,
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
// Javaでの実装例
int flags = PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT;
PendingIntent pendingIntent = PendingIntent.getActivity(
context,
requestCode,
intent,
flags
);
バージョン互換性の考慮
Android 12以前のバージョンとの互換性を保つための実装方法:
fun createPendingIntent(context: Context, intent: Intent, requestCode: Int): PendingIntent {
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
return PendingIntent.getActivity(context, requestCode, intent, flags)
}
Mutable PendingIntentが必要な場合
インライン返信やバブルのような機能でPendingIntent
の内容を変更する必要がある場合は、FLAG_MUTABLE
を使用します。
val mutablePendingIntent = PendingIntent.getActivity(
context,
requestCode,
intent,
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
WARNING
FLAG_MUTABLE
は必要な場合にのみ使用してください。セキュリティ上の理由から、可能な限りFLAG_IMMUTABLE
を使用することが推奨されます。
ライブラリ関連の問題と解決策
WorkManagerの更新
この問題は多くの場合、サードパーティライブラリ(特にWorkManager)の古いバージョンが原因で発生します。WorkManagerを最新バージョンに更新してください。
dependencies {
def work_version = "2.8.1"
// Java
implementation "androidx.work:work-runtime:$work_version"
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"
// RxJava2サポート
implementation "androidx.work:work-rxjava2:$work_version"
}
Firebaseの更新
Firebaseを使用している場合、古いバージョンがこの問題を引き起こす可能性があります。
implementation 'com.google.firebase:firebase-messaging:23.4.0'
Navigationコンポーネントの更新
Navigationコンポーネントを使用している場合も、最新バージョンに更新してください。
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
ユーティリティクラスの作成
さまざまな種類のPendingIntent
を扱う場合、以下のようなユーティリティクラスを作成すると便利です。
object PendingIntentCompat {
@JvmStatic
@JvmOverloads
fun getActivity(
context: Context,
requestCode: Int,
intent: Intent,
flags: Int,
isMutable: Boolean = false
): PendingIntent {
return PendingIntent.getActivity(
context,
requestCode,
intent,
addMutabilityFlags(isMutable, flags)
)
}
@JvmStatic
@JvmOverloads
fun getService(
context: Context,
requestCode: Int,
intent: Intent,
flags: Int,
isMutable: Boolean = false
): PendingIntent {
return PendingIntent.getService(
context,
requestCode,
intent,
addMutabilityFlags(isMutable, flags)
)
}
private fun addMutabilityFlags(isMutable: Boolean, flags: Int): Int {
var updatedFlags = flags
if (isMutable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
updatedFlags = flags or PendingIntent.FLAG_MUTABLE
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
updatedFlags = flags or PendingIntent.FLAG_IMMUTABLE
}
}
return updatedFlags
}
}
よくあるエラーと解決策
リモート入力付きアクションでのクラッシュ
通知の返信アクションなどのリモート入力を使用する場合は、FLAG_MUTABLE
が必要です。
fun getPendingIntentFlags(isMutable: Boolean = false): Int {
return when {
isMutable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ->
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
!isMutable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ->
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
else -> PendingIntent.FLAG_UPDATE_CURRENT
}
}
// 使用例
val quickReplyPendingIntent = PendingIntent.getBroadcast(
context,
notificationId,
replyIntent,
getPendingIntentFlags(true) // リモート入力の場合は mutable を true に
)
まとめ
Android 12以降では、PendingIntent
の作成時にmutability flagの明示的な指定が必須となりました。ほとんどのケースではFLAG_IMMUTABLE
を使用し、必要な場合のみFLAG_MUTABLE
を使用してください。また、サードパーティライブラリが古い場合は更新することで、この問題を解決できる場合があります。
TIP
Android 12の変更に対応する際は、アプリのすべてのPendingIntent
作成箇所を確認し、適切なmutability flagを追加することを忘れないでください。