Где будешь объявлять actual-декларации?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Объявление actual-деклараций в Kotlin Multiplatform
Actual-декларации являются ключевой частью архитектуры Kotlin Multiplatform (KMP) и объявляются в platform-specific модулях, которые соответствуют целевым платформам проекта. Их расположение строго определяется структурой KMP и служит для предоставления конкретных реализаций для объявленных в общем модуле expect-деклараций.
Структура модулей Kotlin Multiplatform и место actual-деклараций
В типичном KMP-проекте структура модулей выглядит следующим образом:
my-multiplatform-project/
├── shared/ # Общий (common) модуль
│ ├── src/
│ │ ├── commonMain/ # Здесь объявляются expect−декларации
│ │ │ └── kotlin/
│ │ └── androidMain/ # НЕ здесь! Это не платформенный модуль.
│ └── build.gradle.kts
├── androidApp/ # Android−специфичный модуль
│ ├── src/
│ │ └── main/ # Здесь объявляются actual−декларации для Android
│ │ └── kotlin/
│ └── build.gradle.kts
├── iosApp/ # iOS−специфичный модуль
│ ├── src/
│ │ └── main/ # Здесь объявляются actual−декларации для iOS
│ │ └── kotlin/
│ └── build.gradle.kts
Actual-декларации должны быть размещены в отдельных Gradle-модулях, предназначенных для конкретной платформы (например, androidApp, iosApp), а не в директориях androidMain, iosMain внутри общего модуля (shared). Эти androidMain/iosMain используются для платформенно-специфичного кода, который уже находится в общем модуле (например, для реализации actual интерфейсов или классов, объявленных как expect в commonMain), но сама структура модулей должна быть разделена.
Пример объявления actual-декларации для Android
Рассмотрим конкретный пример. В общем модуле (shared/src/commonMain/kotlin/) мы объявляем expect-функцию для получения текущего времени:
// В shared/src/commonMain/kotlin/TimeHelper.kt
package com.example.common
expect fun getCurrentTimeMillis(): Long
Теперь, чтобы предоставить реализацию для Android, мы создаем отдельный Android-модуль (androidApp) и объявляем actual-декларацию в его исходном коде:
// В androidApp/src/main/kotlin/TimeHelper.kt
package com.example.common
import java.lang.System
actual fun getCurrentTimeMillis(): Long {
return System.currentTimeMillis()
}
Ключевые правила и лучшие практики
- Строгое соответствие имен и пакетов: Имя
actual-декларации и её пакет должны полностью совпадать с именем и пакетом соответствующейexpect-декларации. Kotlin компилятор использует это для связывания. - Одна actual-декларация для каждой целевой платформы: Для каждой
expect-декларации в общем модуле необходимо предоставить точно однуactual-декларацию в каждом модуле целевой платформы, которая будет использовать этот общий код. - Разделение модулей vs разделение исходных наборов: Важно понимать разницу:
* **Разделение исходных наборов (source sets)** внутри общего модуля (`commonMain`, `androidMain`, `iosMain`) используется, когда весь multiplatform-код находится в одном Gradle-модуле. `actual`-декларации в этом случае пишутся в `androidMain/iosMain`.
* **Разделение модулей (separate Gradle modules)** — более чистая и масштабируемая архитектура для полноценных приложений. `actual`-декларации объявляются тогда в этих отдельных модулях (`androidApp/src/main`, `iosApp/src/main`).
- Проверка зависимостей: В
build.gradle.ktsплатформенного модуля (androidApp) обязательно должна быть объявлена зависимость на общий модуль (shared).
// В androidApp/build.gradle.kts
dependencies {
implementation(project(":shared"))
}
Типичные ошибки в размещении
- Объявление
actualвcommonMain: Это приведет к ошибке компиляции, так какcommonMainне имеет доступа к платформенным API. - Объявление
actualвandroidMainобщего модуля, когда используется архитектура с раздельными модулями: Компилятор не найдет реализации, так как будет искать её в соответствующем платформенном модуле. - Несовпадение пакетов: Самая частая причина ошибки
No actual implementation found for expect declaration.
Таким образом, actual-декларации объявляются в модулях, специфичных для целевой платформы (androidApp, iosApp), в их основной исходной директории (src/main/kotlin/), соблюдая полное соответствие имени и пакета с expect-декларацией из общего модуля. Это обеспечивает четкое разделение логики, корректную компиляцию и масштабируемость проекта Kotlin Multiplatform.