TL; DR;
Как добавить два или более kotlin собственных модуля в iOS проект без получения ошибки duplicate symbols
?
Подробный вопрос
Давайте рассмотрим многомодульный проект KMP в следующем виде, где существует собственное приложение для Android и собственное приложение для iOS и два общих модуля для хранения общего kotlin кода.
.
├── android
│ └── app
├── common
│ ├── moduleA
│ └── moduleB
├── ios
│ └── app
Модуль A содержит класс данных HelloWorld и не имеет зависимостей модуля:
package hello.world.modulea
data class HelloWorld(
val message: String
)
Модуль B содержит функцию расширения для класса HelloWorld, поэтому он зависит от модуля A:
package hello.world.moduleb
import hello.world.modulea.HelloWorld
fun HelloWorld.egassem() = message.reversed()
Конфигурация модулей build.gradle:
apply plugin: "org.jetbrains.kotlin.multiplatform"
apply plugin: "org.jetbrains.kotlin.native.cocoapods"
…
kotlin {
targets {
jvm("android")
def iosClosure = {
binaries {
framework("moduleA")
}
}
if (System.getenv("SDK_NAME")?.startsWith("iphoneos")) {…}
}
cocoapods {…}
sourceSets {
commonMain.dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72"
}
androidMain.dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.72"
}
iosMain.dependencies {
}
}
}
apply plugin: "org.jetbrains.kotlin.multiplatform"
apply plugin: "org.jetbrains.kotlin.native.cocoapods"
…
kotlin {
targets {
jvm("android")
def iosClosure = {
binaries {
framework("moduleB")
}
}
if (System.getenv("SDK_NAME")?.startsWith("iphoneos")) {…}
}
cocoapods {…}
sourceSets {
commonMain.dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72"
implementation project(":common:moduleA")
}
androidMain.dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.72"
}
iosMain.dependencies {
}
}
}
Это выглядит довольно просто и даже работает на android, если я сконфигурирую android зависимости gradle сборки следующим образом:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72"
implementation project(":common:moduleA")
implementation project(":common:moduleB")
}
Однако, похоже, это неправильный способ организации нескольких модулей на iOS, потому что при запуске ./gradlew podspec
я получаю BUILD SUCCESSFUL
, как и ожидалось С помощью следующих модулей:
pod 'moduleA', :path => '…/HelloWorld/common/moduleA'
pod 'moduleB', :path => '…/HelloWorld/common/moduleB'
Даже при запуске pod install
я получаю вывод об успешном выполнении Pod installation complete! There are 2 dependencies from the Podfile and 2 total pods installed.
, что выглядит правильно, когда Xcode показывает модуль A и модуль B в разделе модулей.
Однако, если я пытаюсь построить проект iOS, я получаю следующую ошибку:
Ld …/Hello_World-…/Build/Products/Debug-iphonesimulator/Hello\ World.app/Hello\ World normal x86_64 (in target 'Hello World' from project 'Hello World')
cd …/HelloWorld/ios/app
…
duplicate symbol '_ktypew:kotlin.Any' in:
…/HelloWorld/common/moduleA/build/cocoapods/framework/moduleA.framework/moduleA(result.o)
…/HelloWorld/common/moduleB/build/cocoapods/framework/moduleB.framework/moduleB(result.o)
… a lot of duplicate symbol more …
duplicate symbol '_kfun:kotlin.throwOnFailure$stdlib@kotlin.Result<#STAR>.()' in:
…/HelloWorld/common/moduleA/build/cocoapods/framework/moduleA.framework/moduleA(result.o)
…/HelloWorld/common/moduleB/build/cocoapods/framework/moduleB.framework/moduleB(result.o)
ld: 9928 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Мои знания в iOS не так уж и велики, так что, на мой неопытный взгляд, похоже, что каждый Модуль добавляет свою собственную версию вещей вместо того, чтобы использовать какую-то стратегию разрешений, чтобы делиться ею.
Если я использую только модуль А, код работает и запускается, как и ожидалось, поэтому я знаю, что сам код является правильным, проблема заключается в том, как управлять более чем одним модулем, так что вопрос, как добавить оба (модуль A и модуль B) на iOS и сделать все работает?
PS
Я сделал уменьшите код настолько, насколько я мог, стараясь сохранить только те части, которые, как мне кажется, являются источником проблемы, однако полный код доступен здесь , если вы хотите проверить что-либо пропущенное во фрагментах, или если ты Нет, чтобы запустить и попытаться решить проблему ...