在Xcode中使用KMM共享库会在构建Xcode 时发出几个警告
背景信息
首先,让我解释一下我做了什么,以便更好地了解我做了些什么,以及在使用Xcode构建共享KMM库时遇到的一些问题。
我在我的Windows PC上为手机、电视和Wear设备创建了一个使用Android Studio的Android项目,这三个设备都使用了一个共享模块。我还想构建一个iOS应用程序,所以我在Mac上使用Android Studio创建了一个新的KMM应用程序。我已经将我的共享模块添加到这个KMM应用程序中,并开始构建iOS应用程序。成功后,我添加了一个在Apple Watch上运行的应用程序,所以我使用Xcode手动添加了一款适用于iOS应用程序的(文件->新->目标…)手表应用程序。我配置了它,做了一些基本的编码/管道,构建了它,一切都很好。
共享模块略有更改,使其与Xcode结合使用Android,我已将其添加到Podfile
中(我在项目中也使用Firebase):
target 'XYZ' do
use_frameworks!
platform :ios, '15.0'
pod 'shared', :path => '../shared'
# add pods for desired Firebase products
# https://firebase.google.com/docs/ios/setup#available-pods
pod 'Firebase/Messaging'
pod 'Firebase/Analytics'
pod 'Firebase/InAppMessaging'
end
target 'WatchXYZ' do
use_frameworks!
platform :watchos, '8.0'
pod 'shared', :path => '../shared'
# add pods for desired Firebase products
# https://firebase.google.com/docs/ios/setup#available-pods
pod 'Firebase/Messaging'
#pod 'Firebase/Analytics'
#pod 'Firebase/InAppMessaging'
end
target 'WatchXYZ WatchKit Extension' do
use_frameworks!
platform :watchos, '8.0'
pod 'shared', :path => '../shared'
# add pods for desired Firebase products
# https://firebase.google.com/docs/ios/setup#available-pods
pod 'Firebase/Messaging'
#pod 'Firebase/Analytics'
#pod 'Firebase/InAppMessaging'
end
在共享的src目录中,有四个子目录:androidMain、commonMain、iosMain和watchosMain。此目录中的build.gradle.kts
如下所示:
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
kotlin("multiplatform")
kotlin("native.cocoapods")
id("com.android.library")
id("kotlin-parcelize")
kotlin("plugin.serialization") version "1.4.10"
}
version = "1.0"
kotlin {
android()
val iosTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget = when {
System.getenv("SDK_NAME")?.startsWith("iphoneos") == true -> ::iosArm64
System.getenv("NATIVE_ARCH")?.startsWith("arm") == true -> ::iosSimulatorArm64
else -> ::iosX64
}
iosTarget("ios") {}
watchos()
cocoapods {
summary = "Some description for the Shared Module"
homepage = "Link to the Shared Module homepage"
ios.deploymentTarget = "15.0"
watchos.deploymentTarget = "8.0"
framework {
baseName = "shared"
}
podfile = project.file("../iosApp/Podfile")
}
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
implementation("io.ktor:ktor-client-core:1.6.7")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting {
dependencies {
implementation("com.google.android.material:material:1.4.0")
implementation("io.ktor:ktor-client-android:1.6.7")
}
}
// Workaround for:
//
// The Kotlin source set androidAndroidTestRelease was configured but not added to any
// Kotlin compilation. You can add a source set to a target's compilation by connecting it
// with the compilation's default source set using 'dependsOn'.
// See https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#connecting-source-sets
//
// This workaround includes `dependsOn(androidAndroidTestRelease)` in the `androidTest` sourceSet.
val androidAndroidTestRelease by getting
val androidTest by getting {
dependsOn(androidAndroidTestRelease)
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.13.2")
}
}
val iosMain by getting {
dependencies {
//implementation("io.ktor:ktor-client-ios:1.6.7")
}
}
val iosTest by getting
val watchosMain by getting {
dependencies {
//implementation("io.ktor:ktor-client-ios:1.6.7")
}
}
val watchosTest by getting
}
}
android {
compileSdk = 30
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdk = 28
targetSdk = 30
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
}
虽然我用旧版本的Android Studio创建了KMM应用程序,但当前版本是Arctic Fox 2020.3.1补丁4。有了Xcode 13.2.1,我可以构建这个项目,在iOS 15.2的iPhone 7设备上运行,并在模拟器中运行。Mac是一款搭载macOS Monterey 12.1的iMac(Retina 5K,27英寸,2015年末)。我还没有苹果手表。
执行像pod install
和/或pod update
这样的命令可以帮助我让共享库在Xcode中工作。所有的建筑和工作都很漂亮,到目前为止没有任何问题。
在Xcode中构建时的警告和错误
当为设备、手机或手表模拟器构建时,我会收到一些警告。我想知道这些是否不好,是否可以修复。
当为iPhone设备构建时,我收到5100多条警告,类似于:warning: (arm64) could not find object file symbol for symbol _kfun:io.ktor.utils.io.<get-EXPECTED_CAPACITY>#internal
和warning: (arm64) could not find object file symbol for symbol _kfun:io.ktor.utils.io.ByteChannelSequentialBase#<get-writable>(){}io.ktor.utils.io.core.BytePacketBuilder
这里唯一需要注意的是,当为iOS或watchOS模拟器构建时,我会收到两个警告:
来自"XYZ"应用程序:warning: (x86_64) could not find object file symbol for symbol __Konan_init_io.ktor:ktor-io-cinterop-sockets
来源于"WatchXYZ WatchKit扩展":
2ld: warning: ignoring file /Users/bash/AndroidStudioProjects/XYZ/shared/build/cocoapods/framework/shared.framework/shared, building for watchOS Simulator-arm64 but attempting to link with file built for watchOS Simulator-x86_64
当我开始在watchOS应用程序中使用共享库时,只需用共享库中的Class1实例实例化一个新变量,构建就会失败,并出现上述警告和错误:
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_SharedClass1", referenced from:
objc-class-ref in XYZApp.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
解决问题的可能措施
我尝试了以下操作:
仅构建活动体系结构在"XYZ"项目的"构建设置"中将"是"设置为"发布"("调试"已设置为"是")。在此之后,Xcode的行为变得不可预测。在重新启动并执行iPhone的构建命令后,我得到了4个类似的错误。
错误(仅列出一个,其他类似):
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_SharedClass1", referenced from:
objc-class-ref in MyView.o
来回更改设置并执行另一个构建可以解决此错误。但重启后,它又回来了。为了解决这个问题,我不得不完全删除设置。只有到那时我才能回到原点。
我的警告有多糟糕?这些问题能以某种方式解决吗?错误可能与警告有关。
===更新===
上面的组合似乎很难预测。我尝试了很多不同的东西,花了一段时间才弄清楚。在随后的几次构建请求之后,相同的代码和设置在Xcode中成功构建,并可以在iPhone和iWatch上运行。我不知道为什么一次尝试后它没有正确构建。
这对我来说很好,直到上周安卓工作室大黄蜂补丁1更新。或者可能是由于安卓Gradle或Gradle的更新,但我似乎又回到了原点。如果我遵循以下步骤,我就可以在Xcode中正确构建它,并在实际的iWatch设备上运行应用程序:
- 在Xcode中的iPhone应用程序方案和iPhone设备
- 选择"清除生成文件夹">
- 关闭Xcode
- 在Android Studio中选择"清理项目"one_answers"构建项目">
- 在终端中运行pod更新命令
- 启动Xcode并构建项目(它抱怨找不到共享模块)
- 再次在终端中运行pod更新
- 在Xcode中重新构建(构建再次失败)
- 在Xcode中重新构建,现在应该会成功
- 选择手表应用程序方案和iWatch设备
- 选择在iWatch上运行应用程序
如果我需要更改代码并想再次运行代码,我必须从步骤1重新开始。如果我做了一些不同的事情,它就不会构建和运行。我不明白为什么它如此不可预测,为什么它失败了很多次,然后突然建立起来。我不会对设置或代码进行任何更改以使其生成或不生成。
如果有人能向我解释为什么这是一种不可预测的行为。。。开发某种东西几乎是不可能的。
===更新===
安装安卓工作室大黄蜂2021.1.1补丁2后的另一次更新。它现在似乎和以前一样有效。我仍然需要为iPhone编译3次,然后才能成功地在iWatch上构建和运行。我可以再次更改代码并立即再次运行它,而无需执行上一次更新中描述的整个过程。
看起来工作得很好。还有一些怪癖,但让我们看看我是否能在不久的将来成功部署到AppStore。
=====更新=====
我最终离开了Cocoapods,并将我的共享库链接为一个框架。在一些其他问题之后,这些问题得到了解决,一切都很好。
我只得到了;(arm64)找不到对象文件符号";调试生成的错误。在经历了一番折腾和咬牙切齿之后,到目前为止,我发现唯一对我有效的方法是通过xcodeConfigurationToNativeBuildType
映射强制构建KMM共享框架以供发布。
具体来说,在build.gradle.kts中,在kotlin
>cocopods
:
xcodeConfigurationToNativeBuildType["Debug"] =
org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType.RELEASE