Infinito Nirone 7

白羽の矢を刺すスタイル

Target SDK Version を 31 に上げるときに引っかかるポイント: SparseArray

Kotlin を使用したアプリケーションという前提で、次のような構成のアプリがあり、このアプリの Target SDK Version および Compile SDK Version を 31 (Android 12) に上げることを考えます。

Target SDK Version を上げる前の構成: build.gradle

android {
    compileSdk 30

    defaultConfig {
        applicationId "dev.keithyokoma.sample"
        minSdk 23
        targetSdk 30
    }
}

dependencies {
    implementation 'androidx.core:core-ktx:1.6.0'
}

SparseArray に値をセットする

上記の構成のとき、次のようなコードは正しく意図通り動作します。 注目すべきは SparseArray に値をセットするコードです。AndroidX Core KTX の set 拡張関数 を使うことで、メソッド呼び出しではなく指定した添字への値の代入のように記述できます。

import androidx.core.util.set

val array = SparseArray<String>()
array[0] = "test" // AndroidX Core KTX の set 拡張関数を使っている

Target SDK Version および Compile SDK Version を 31 にあげる

ここで構成を変え、Target SDK Version と Compile SDK Version を最新の 31 に上げます。 するとビルド時にエラーが出力されます。

Call requires API level S (current min is 23): android.util.SparseArray#set

エラーメッセージが示す関数が androidx.core.util.set ではなく android.util.SparseArray#set になっています。これは、Android 12 (API Level 31) から新たに SparseArray#set メソッドが追加されたためです。 この新しい SparseArray#set メソッドを Kotlin で解釈したとき、Java で定義されたメソッドを添え字での値の代入として扱えるようにする仕組みが働き、array[0] = "test" はそのまま正しくコンパイル可能なコードになります。 同時に AndroidX Core KTX の set 拡張関数が使われなくなり(31 に上げると、上記 Kotlin のコードの import 文が unused になります)、minSdkVersion = 31 を要求する新しいメソッドを使っていることになるため、このようなエラーになります。

回避策

Target SDK Version および Compile SDK Version を 31 にした状態では拡張関数が利用できないので、次のように拡張関数が呼び出していた SparseArray#put を使います。

val array = SparseArray<String>()
array.put(0, "test")

類似のケース

実は Android 11 (API 30) 対応でも SparseArray の使用方法で実行時にエラーとなるケースがあったようです。

https://issuetracker.google.com/issues/168724187?pli=1