Kotlin 与 Objective-C 框架的多平台/本机互操作性
Posted
技术标签:
【中文标题】Kotlin 与 Objective-C 框架的多平台/本机互操作性【英文标题】:Kotlin multiplatform/native interoperability with Objective-C framework 【发布时间】:2019-05-29 01:11:30 【问题描述】:我正在尝试在多平台项目中从 Kotlin 调用 Swift/Objective-C 代码。调用平台代码没有问题。但是,当我尝试调用某个库(或框架,由于我不是 ios 开发人员而不确定如何正确调用它)时,它会失败。 Docs 表示,如果正确导出,可以调用 Objective-C 代码和 Swift:
Kotlin/Native 提供与 Objective-C 的双向互操作性。如果将 Objective-C 框架和库正确导入构建(默认导入系统框架),则可以在 Kotlin 代码中使用 Objective-C 框架和库。参见例如Gradle 插件文档中的“使用 cinterop”。如果使用 @objc 将 Swift 库的 API 导出到 Objective-C,则可以在 Kotlin 代码中使用 Swift 库。尚不支持纯 Swift 模块。
但它没有说明如何正确导入它们。它只指向描述旧版本 gradle 插件的gradle plugin description。所以它对我不起作用。最后我想出了一些可能是导入Objective-C代码的方法:
fromPreset(presets.iosX64, 'ios')
compilations.main.outputKinds('FRAMEWORK')
compilations.main
cinterops
firebase
def pods = '$System.getProperty("user.home")/Projects/kmpp/iosApp/Pods/'
includeDirs '$podsFirebase/CoreOnly/Sources',
'$podsFirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers'
构建运行没有失败,但它不导入任何东西。我究竟做错了什么?是否可以导入这样的库?
更新:
here 我找到了一个使用cinterop
工具的示例,如下所示:
cd samples/gitchurn
../../dist/bin/cinterop -def src/main/c_interop/libgit2.def \
-compilerOpts -I/usr/local/include -o libgit2
看起来cinterop
工具应该在我的项目中的/dist/bin/
文件夹中,但没有这样的文件夹。我在哪里可以得到cinterop
工具?
【问题讨论】:
【参考方案1】:我最终在 build.gradle 中找到了这个 cinterops
部分
fromPreset(presets.iosX64, 'ios')
// This preset is for iPhone emulator
// Switch here to presets.iosArm64 (or iosArm32) to build library for iPhone device
compilations.main
outputKinds('FRAMEWORK')
cinterops
firebase
defFile "$projectDir/src/iosMain/cinterop/firebase.def"
includeDirs
allHeaders "$projectDir/../iosApp/Pods/FirebaseCore/Firebase/Core/Public",
"$projectDir/../iosApp/Pods/FirebaseDatabase/Firebase/Database/Public"
compilerOpts "-F$projectDir/../iosApp/Pods/Firebase -F$projectDir/../iosApp/Pods/FirebaseCore -F$projectDir/../iosApp/Pods/FirebaseDatabase"
linkerOpts "-F$projectDir/../iosApp/Pods/Firebase -F$projectDir/../iosApp/Pods/FirebaseCore -F$projectDir/../iosApp/Pods/FirebaseDatabase"
结束这个.def
文件:
language = Objective-C
headers = FirebaseCore.h FirebaseDatabase.h
这里发生了什么? Cocopods 框架位于 Xcode 项目的Pods
目录中。稍微浏览一下这个文件夹,你会找到你需要的。我不确定Public
文件夹中是否有一些标准但firebase 放置主头文件。它包含对它需要的其他头文件的引用......所以你在你的 .def
文件的 headers 部分中指定这些文件名。
接下来,您需要指定在何处查找这些文件以及它们引用的其他文件。您可以在includeDirs
或build.gradle
文件中的.def
文件中执行此操作。我更喜欢使用 build.gradle 文件,因为它可以使用变量。因此,您指定这些Public
文件夹的路径。 (这足以让 kotlin 看到库 API,但是为了能够运行应用程序,您需要编译和链接这个库......)
然后编译器和链接器需要知道库/框架在哪里。因此,您在 compilerOpts
和 linkerOpts
中指定框架根文件夹的路径,如果它是一个框架,则在它们前面加上 -F
,如果它是一个库,则在它们前面加上 -L
。
【讨论】:
直接从 kotlin native 使用 objectiv-c 静态方法导致我出现此错误 Undefined symbols for architecture x86_64。示例:FIRAnalytics.logEventWithName("value", null)
或 FIRApp.configure()
或 FIRDatabase.database()
从 iOS 实际的 kotlin 类运行上述示例将失败,并出现 Undefined symbols for architecture x86_64 你遇到过这个错误吗?如何从 kotlin 调用“cinteroped”objective-c 静态方法?
我遇到了与@JoãoZão 相同的错误。有人有解决办法吗?
@JoãoZão 您是否将FirebaseAnalytics
添加到您的.def
文件、includeDirs
和编译器/链接器选项?在我的示例中,只有数据库可用...
Firebase 由许多部分组成,您必须指定要使用的每一部分。
FIRDatabase.database()
会发生这种情况。我发现在 linkerOpts 中,我们需要通过 -F
选项将路径传递给框架(就像你正在做的那样),我们还必须通过框架文件本身通过-framework
选项使用def文件示例:language = Objective-C
headers = FirebaseCore.h FirebaseDatabase.h
linkerOpts = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/10.0.0/lib/darwin/libclang_rt.osx.a -F $fullpath-to-frameworks-dir -framework FirebaseDatabase
抱歉格式错误。【参考方案2】:
看起来您将使用 cocoapods 库。目前 Gradle 插件不支持开箱即用的 cocapods。但可能是对您的库的依赖可以“手动”配置。您能否分享一个指向您的项目的链接?
【讨论】:
是的,那是 cocoapods。我的项目没有什么特别的,所以我没有把它推送到 github。它只是 IDEA 创建的默认多平台项目,我在其中添加了 firebase lib,如下所述:firebase.google.com/docs/ios/setup 如果 gradle 插件不支持开箱即用的 cocoapods,是否可以手动执行?例如通过创建 .def 文件并运行 cinterop 工具?顺便说一句,我也一直在尝试这样做,但没有奏效。我的终端无法识别 cinterop 命令。 我猜是的,可以手动完成,但我现在无法检查。我会在可能的情况下检查并回复您。以上是关于Kotlin 与 Objective-C 框架的多平台/本机互操作性的主要内容,如果未能解决你的问题,请参考以下文章
Objective-C:Swift Package 函数中的多参数方法语法