Введение: «Двойник» в вашем проекте
Представьте ситуацию: вы пишете код на Kotlin для Android, всё работает отлично. Вы добавляете новую библиотеку, запускаете сборку — и Gradle выдает красную ошибку: «Duplicate class». Знакомо? Если вы хоть раз сталкивались с Android-разработкой, то наверняка видели это сообщение. На Stack Overflow этот вопрос набрал тысячи просмотров, и не зря — ошибка может вывести из себя даже опытного разработчика.
В этой статье мы разберем, что такое Duplicate class в Kotlin Android, почему она возникает, и главное — как её исправить раз и навсегда. Вы узнаете 5 самых частых причин, получите готовые решения и научитесь предотвращать конфликты зависимостей. Поехали!
Что такое Duplicate class и почему это происходит?
Ошибка Duplicate class возникает, когда система сборки (Gradle) находит два или более одинаковых класса с одним полным именем (FQN — Fully Qualified Name). В мире Android это обычно означает, что один и тот же класс присутствует в разных библиотеках или модулях вашего проекта.
Представьте, что вы заказали две одинаковые книги, но от разных издателей. Они лежат на одной полке — и библиотекарь не знает, какую брать. Так и Gradle: он не может решить, какой из дублирующихся классов использовать.
Почему это особенно актуально для Kotlin? Kotlin активно использует стандартную библиотеку Kotlin (kotlin-stdlib), которая может конфликтовать с её же версиями из других источников. Добавьте сюда AndroidX, библиотеки Google, Firebase — и вы получите гремучую смесь.
Топ-5 причин ошибки Duplicate class в Kotlin Android
Мы собрали самые частые сценарии, с которыми вы столкнетесь в реальной разработке. Каждый пункт сопровождается примером кода и решением.
1. Конфликт версий Kotlin stdlib
Это король всех дубликатов. Когда вы подключаете библиотеку, которая тянет свою версию kotlin-stdlib, а у вас в проекте уже есть другая — возникает конфликт.
Пример:
// build.gradle.kts (модуль app)
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0")
implementation("com.some.library:example:2.0.0") // эта библиотека тянет kotlin-stdlib:1.8.0
}
Gradle выдаст что-то вроде:
Duplicate class kotlin.collections.ArraysKt found in modules kotlin-stdlib-1.9.0 (org.jetbrains.kotlin:kotlin-stdlib:1.9.0) and kotlin-stdlib-1.8.0 (org.jetbrains.kotlin:kotlin-stdlib:1.8.0)
Решение: Используйте единую версию Kotlin для всего проекта. Лучший способ — задать её в корневом build.gradle.kts:
// build.gradle.kts (корневой)
plugins {
kotlin("android") version "1.9.0" apply false
}
// build.gradle.kts (модуль app)
plugins {
kotlin("android")
}
Также можно явно исключить зависимость:
implementation("com.some.library:example:2.0.0") {
exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
}
2. Дублирование AndroidX и Support Library
Классика жанра. Если вы используете старые библиотеки Support Library вместе с AndroidX, они содержат одинаковые классы (например, android.support.v4.app.Fragment и androidx.fragment.app.Fragment).
Пример ошибки:
Duplicate class android.support.v4.app.Fragment found in modules support-compat-28.0.0 and fragment-1.6.0
Решение:
- Включите флаг
android.useAndroidX=trueвgradle.properties. - Убедитесь, что все библиотеки переведены на AndroidX. Используйте инструмент миграции в Android Studio (Refactor > Migrate to AndroidX).
- Если библиотека не поддерживает AndroidX, используйте
jetifier:
// gradle.properties
android.useAndroidX=true
android.enableJetifier=true
3. Конфликт из-за разных версий одной библиотеки
Вы подключаете две библиотеки, которые зависят от одного и того же пакета, но разных версий. Например, com.google.android.gms:play-services-maps и com.google.android.gms:play-services-location могут тянуть разные версии play-services-basement.
Пример:
dependencies {
implementation("com.google.android.gms:play-services-maps:18.1.0")
implementation("com.google.android.gms:play-services-location:21.0.1")
// play-services-basement может дублироваться
}
Решение: Принудительно укажите единую версию через force или централизованное управление зависимостями:
// build.gradle.kts
configurations.all {
resolutionStrategy {
force("com.google.android.gms:play-services-basement:18.2.0")
}
}
Или используйте Version Catalog (рекомендуется для больших проектов).
4. Одинаковые классы в разных модулях
Если у вас мультимодульный проект, и два модуля содержат класс с одним и тем же пакетом и именем — Gradle закричит. Это часто случается, когда вы копируете код или используете автосгенерированные файлы.
Пример:
// Модуль :feature:auth
package com.example.data
class UserRepository
// Модуль :feature:profile
package com.example.data
class UserRepository // Дубликат!
Решение:
- Переименуйте классы или используйте разные пакеты.
- Проверьте, не подключаете ли вы один модуль дважды (например, через
implementation projectиapi project). - Используйте
R8/ProGuardдля обфускации, но это не решит проблему на этапе компиляции.
5. Библиотеки, которые включают один и тот же сторонний код
Некоторые библиотеки «запекают» внутрь себя другие библиотеки (fat JAR/AAR). Например, библиотека для работы с сетью может включать OkHttp, а другая — тоже. Если версии разные — получите Duplicate class.
Пример:
dependencies {
implementation("com.example:network-lib:1.0.0") // содержит okhttp:3.12.0
implementation("com.squareup.okhttp3:okhttp:4.10.0") // явно подключен
}
Решение: Используйте ./gradlew :app:dependencies для просмотра дерева зависимостей. Затем исключите дублиру