【发布时间】:2020-08-11 15:20:35
【问题描述】:
TL;DR;
如何在 iOS 项目中添加两个或多个 kotlin 原生模块而不会出现 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配置为:
- 模块 A
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 {
}
}
}
- 模块 B
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 build gradle 依赖项配置如下,它甚至可以在 android 上运行:
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 的预期一样:
pod 'moduleA', :path => '…/HelloWorld/common/moduleA'
pod 'moduleB', :path => '…/HelloWorld/common/moduleB'
即使运行 pod install,一旦 Xcode 在 Pods 部分显示模块 A 和模块 B,我也会得到成功输出 Pod installation complete! There are 2 dependencies from the Podfile and 2 total pods installed. 。
但是,如果我尝试构建 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 代码可以按预期工作和运行,所以我知道代码本身是正确的,问题是如何管理多个模块,所以问题是,如何添加两者(模块 A和模块 B) 在 iOS 上并让事情正常运行?
附言
我确实尽可能地减少了代码,试图只保留我认为是问题根源的部分,但是,如果您想检查 sn 中缺少的任何内容,可以使用完整的代码 here -ps,或者如果你想运行并尝试解决问题......
【问题讨论】:
标签: android ios kotlin gradle kotlin-multiplatform