Ошибка "Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6" в Kotlin
Причина ошибки и её объяснение
Ошибка возникает из-за несоответствия между JVM-таргетами (целевыми версиями JVM) для разных модулей или библиотек в вашем проекте. Конкретно: inline-функции Kotlin (например, let, apply, also) при компиляции вставляют свой байт-код непосредственно в место вызова. Если стандартная библиотека Kotlin (или другая библиотека, например, Corda) была скомпилирована с JVM target 1.8, а ваш проект использует JVM target 1.6, то JVM не может вставить байт-код 1.8 в байт-код 1.6, так как форматы байт-кода различаются (например, в 1.8 появились новые инструкции для лямбд и default-методов в интерфейсах).
Как исправить: пошаговое решение
Самый простой и правильный способ — повысить JVM target вашего проекта до 1.8 (или выше). Начиная с Android API 26 (Android 8.0), это стандарт. Вот как это сделать:
- Обновите
build.gradle(уровня модуля):android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } } - Убедитесь, что версия Kotlin совместима: Используйте Kotlin 1.3.72 или новее (в вашем случае всё в порядке).
- Проверьте зависимости: Если вы используете библиотеки, скомпилированные с JVM 1.8 (например, Corda), они будут работать только с JVM target 1.8+.
Почему это работает?
JVM target 1.8 поддерживает все возможности байт-кода, которые используются в inline-функциях Kotlin, включая:
- Инструкции для
invokedynamic(используются для лямбд). - Default-методы в интерфейсах.
- Улучшенную поддержку аннотаций и типов.
После изменения target Gradle перекомпилирует ваш код с правильными инструкциями, и ошибка исчезнет.
Дополнительные советы
- Для Android: Если вы поддерживаете старые версии (ниже API 26), вы всё равно можете использовать JVM 1.8, так как Android Studio и D8/R8 компиляторы умеют преобразовывать байт-код 1.8 в совместимый с API 16+.
- Для non-Android проектов: Убедитесь, что ваша среда выполнения (JRE) поддерживает Java 8. Если нет — обновите её.
- Проверка версии Kotlin: В некоторых старых версиях Kotlin (до 1.2) была проблема с inline-функциями. Обновитесь до последней стабильной версии.
Пример исправленного build.gradle для Android:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 30
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
<<Альтернативный подход: отключение inline-функций или использование ProGuard
Если по каким-то причинам вы не можете повысить JVM target до 1.8 (например, вы работаете с очень старой системой, которая поддерживает только Java 6), есть обходные пути, но они менее предпочтительны:
- Замена inline-функций на обычные: Вместо
let,apply,alsoиспользуйте явные проверки на null или обычные вызовы методов. Например:
Это решит проблему, но лишит вас удобства Kotlin.fun processData(data: String?) { if (data != null) { println("Data is not null: $data") } } - Настройка ProGuard/R8: Включите обфускацию и оптимизацию, которая может переписать inline-функции в обычные вызовы. Добавьте в
build.gradle:
Но это не гарантирует полного исправления и может усложнить отладку.android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } - Использование Kotlin/Native вместо Kotlin/JVM: Если проект не привязан к JVM, можно перейти на Kotlin/Native, который компилируется в нативный код и не имеет проблем с JVM-таргетами. Однако это радикальное изменение.
Важно: Эти методы — временные костыли. Рекомендуется всегда использовать JVM target 1.8 для современных проектов, так как Java 6 устарела и не поддерживается многими библиотеками.