事象
Kotlin を2.2.20に上げたあと、ビルド時に以下のエラーが発生しました。
Duplicate class kotlinx.android.parcel.Parcelize found in modules kotlin-android-extensions-runtime-1.7.20.jar and kotlin-parcelize-runtime-2.2.20.jar
kotlinx.android.parcel.* のクラスが重複しているという内容で、依存関係の衝突が疑われました。
そこで原因を特定するために、Gradle が提供している解析タスク dependencyInsight を使うことにしました。dependencyInsight は、特定の依存が どのライブラリ経由で解決されたのか、また 最終的にどのバージョンが選ばれたのか を確認できる便利コマンドです。
今回実行したのは次の通りです。
./gradlew :app:dependencyInsight \
--configuration releaseRuntimeClasspath \
--dependency kotlin-android-extensions-runtime
出力例は次のようになります。
org.jetbrains.kotlin:kotlin-android-extensions-runtime:1.7.20
\--- com.some.lib:example:1.x.x
\--- releaseRuntimeClasspath
調査の結果、外部ライブラリが kotlin-android-extensions-runtime:1.7.20 に依存していることが分かりました。プロジェクト側の kotlin-parcelize-runtime:2.2.20 と同時に解決されてしまい、同じ kotlinx.android.parcel.* を定義するため Duplicate class エラーに繋がっていました。
解決方法
競合している旧ランタイムを依存から除外し、kotlin-parcelize-runtime 側に統一しました。
dependencies {
implementation("com.some.lib:example:1.x.x") {
exclude(group = "org.jetbrains.kotlin", module = "kotlin-android-extensions-runtime")
}
}
除外を設定したら、ビルドを実行して確認します。
その後、dependencyInsight で再度依存を確認し、旧ランタイムが消えていることをチェックします。
./gradlew :app:dependencyInsight \
--configuration releaseRuntimeClasspath \
--dependency org.jetbrains.kotlin:kotlin-android-extensions-runtime
除外が正しく効いていれば、このコマンドの結果は何も表示されません。
つまり kotlin-android-extensions-runtime が依存関係から完全に取り除かれていることを確認できます。
まとめ
- Kotlin 2.x 系では
kotlin-parcelize-runtimeが正式なランタイム。こちらに統一すべき - 古い
kotlin-android-extensions-runtimeが外部ライブラリ経由で混入すると、kotlinx.android.parcel.*が重複して Duplicate class エラーになる -
./gradlew dependencyInsightを使えば、どのライブラリが不要な依存を持ち込んでいるかを特定できる - 対処はシンプルに
excludeを指定して旧ランタイムを除外すること
※ 本記事は私の環境で遭遇した事例の整理です。同じ状況をそのまま再現できるとは限りませんが、 Duplicate class エラーが発生したときの調査・解決の参考になれば幸いです。
参考文献