Как правильно импортировать многоплатформенный проект Kotlin (и запускать только те задачи, которые необходимы при сборке)
Возможно ли, чтобы все задачи iOS (kotlin / Native) (cinterop + cocoapods) не выполнялись, когда я разрабатываю приложение для Android с импортированным многоплатформенным проектом Kotlin?
Наша текущая структура проекта KMP (SharedLibrary):
SharedLibrary
- build.gradle.kts
- settings.gradle.kts
- ...
- shared
- build.gradle.kts
- commonMain
- androidMain (android library target)
- ...
У нас есть отдельный проект Android (SomeApp) со следующими настройками для импорта нашей общей библиотеки.
// settings.gradle.kts
include ":shared"
project(":shared").projectDir = file("../SharedLibrary/shared")
Дело в том, что ... это довольно раздражающий шаблон разработки, особенно потому, что артефакты iOS (cinterop + cocoapods и т. Д.) Перестраиваются каждый раз, когда происходит изменение, даже если меня интересует только артефакт библиотеки Android.
Что я пробовал:
- Я попытался переключиться на составную сборку, но получаю ошибки, связанные с тем, что gradle не может найти многоплатформенный плагин.
- Я подумываю перейти на использование локального maven, но это определенно замедлит процесс разработки, поэтому я сопротивляюсь.
Это проблема с нашей настройкой? Или задачи просто зависят друг от друга и выхода нет?
3 ответа
Сразу хочу сказать несколько слов о проблеме с точки зрения болельщика.
Я обнаружил эту проблему YouTrack, которая кажется связанной: https://youtrack.jetbrains.com/issue/KT-43796 . Пожалуйста, проверьте, правильно ли это описывает вашу проблему, и прокомментируйте, если это не так. Кроме того, это лучшее место для получения обновленной информации о статусе проблемы.
Вы можете исключить цель iOS из сборки следующим образом:
kotlin {
android()
// kotlin.native.cocoapods.target property passed by cocoapods build from Xcode
val shouldBuildIos = project.findProperty("kotlin.native.cocoapods.target") != null
if (shouldBuildIos) {
ios()
cocoapods {
// ...
}
}
sourceSets {
// ...
if (shouldBuildIos) {
val iosMain by getting {
libDependencies(
"ktor.client.engine.ios",
)
}
}
}
}
Но в этом случае у вас не будет предложений кода в IDE. Также будьте осторожны, потому что в этом случае ваш podspec будет удален.
Если вы работаете только над частью Android, а другой разработчик работает с iOS, вы можете создать собственное свойство в local.properties и убедиться, что вы не будете нажимать удаление файла podspec (или просто проигнорируете его)
Но если вы один разработчик, это не лучший вариант. Я тоже столкнулся с долгим временем сборки cocoapods и решил перенести его из мультиплатформенного модуля.
Каждый раз, когда мне это нужно, я создаю интерфейс в общем коде и передаю экземпляр, реализующий его, или функцию «генератор» (если вы не хотите создавать объект, если он не нужен) из части iOS.
в части y iOS это выглядит примерно так:
featureProvider = FeatureProvider(
context: .init(
rootController: rootViewController,
application: application,
launchOptions: launchOptions
),
providerGenerator: { socialNetwork, context -> CredentialProvider in
switch socialNetwork {
case .facebook:
return FacebookProvider(context: context)
case .google:
return GoogleProvider(context: context)
default: fatalError()
}
}
)
Если вы думаете об этом, при создании вашего общего модуля
gradle
на самом деле не знает, кто это будет употреблять, правда?
Я могу придумать два способа решения вашей проблемы:
- У вас может быть
tasks.getByName("build").dependsOn(packForXcode)
из официального руководства, вы можете просто удалить это и запуститьpackForXcode
вручную для создания фреймворков iOS - Вы можете проверить, есть ли задача по созданию
android
только цель, если ее нет, вы можете создать ее (просто сгруппируйте соответствующие задачи для Android с помощьюdependsOn
, затем запустите только это)