Ошибка "Default interface methods are only supported starting with Android 7.0" в Kotlin: как исправить?
Причина ошибки
Проблема в том, что хотя Kotlin сам по себе компилируется в байт-код Java 6/7 по умолчанию, дефолтные методы интерфейсов (методы с телом) — это фича Java 8. На Android до версии 7.0 (API 24) нет поддержки Java 8 в рантайме. Даже если вы используете Kotlin, компилятор всё равно генерирует байт-код с дефолтными методами, которые требуют Java 8 на устройстве.
Как это работает под капотом
Когда вы пишете интерфейс с методом по умолчанию в Kotlin:
interface Clickable {
fun showToast() { println("Clicked!") }
}
Компилятор Kotlin создаёт в байт-коде интерфейс с методом, помеченным как default (в терминах JVM). Это эквивалент Java 8 default method. На Android 6.0 такой байт-код не распознаётся — отсюда и ошибка.
Решение 1: Использовать абстрактный класс вместо интерфейса
Самый простой и обратно-совместимый способ — заменить интерфейс на абстрактный класс:
abstract class Clickable {
abstract fun onClick()
fun showToast() { println("Clicked!") }
}
class Button : Clickable() {
override fun onClick() {
showToast()
}
}
Минус: в Kotlin и Java нельзя наследоваться от нескольких абстрактных классов.
Решение 2: Включить поддержку Java 8 в Gradle (для Android 7+)
Если ваше приложение нацелено на Android 7.0 и выше, просто укажите в build.gradle:
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
Но это не решит проблему на старых устройствах.
Решение 3: Использовать Kotlin-расширения (Extension functions)
Можно вынести реализацию в extension-функции, которые не требуют наследования:
interface Clickable {
fun onClick()
}
fun Clickable.showToast() {
println("Clicked!")
}
class Button : Clickable {
override fun onClick() {
showToast() // extension function
}
}
Extension-функции не являются методами интерфейса и компилируются в статические методы — они работают на любых версиях Android.
Решение 4: Desugaring от Android Gradle Plugin (рекомендуемое)
Лучший способ — включить desugaring (дешугаринг) Java 8 для старых API. Добавьте в build.gradle:
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
}
Этот механизм заменяет вызовы Java 8 API (включая дефолтные методы интерфейсов) на обратно-совместимые реализации. Важно: проверьте, что ваш compileSdk 34+ и используется AGP 7.4+.
Проверка совместимости
После включения desugaring ваш код с дефолтными методами будет работать на Android 5.0+ (API 21). Убедитесь, что вы используете последнюю версию библиотеки desugar_jdk_libs (на момент написания — 2.1.5).
Итог: если вам нужна поддержка Android 6.0 и ниже — используйте extension-функции или абстрактные классы. Если можно поднять minSdk до 24 — просто включите Java 8. Если хотите максимальную совместимость и современный код — используйте desugaring.
<<Альтернативный подход: делегирование через companion object
Ещё один способ обойти ограничение — использовать companion object внутри интерфейса и вызывать его методы. Это не требует изменения структуры наследования:
interface Clickable {
fun onClick()
companion object {
fun showToast() {
println("Clicked!")
}
}
}
class Button : Clickable {
override fun onClick() {
Clickable.showToast() // статический вызов
}
}
Такой код компилируется в обычные статические методы Java, которые работают на всех версиях Android. Минус — теряется полиморфизм (метод нельзя переопределить в наследнике).
Дополнение: используйте аннотацию @RequiresApi
Если вы пишете библиотеку и хотите явно указать, что метод требует Android 7+, добавьте аннотацию:
@RequiresApi(Build.VERSION_CODES.N)
interface Clickable {
fun showToast() { println("Clicked!") }
}
Это предупредит других разработчиков о требованиях, но не решит проблему на старых устройствах — они всё равно упадут. Используйте только в сочетании с проверкой версии в рантайме.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Тестирование в Java: unit, integration, e2e — полное руководство