Kotlin multiplatform/native 与 Objective-C 框架的互操作性
Kotlin multiplatform/native interoperability with Objective-C framework
我正在尝试在多平台项目中从 Kotlin 调用 Swift/Objective-C 代码。调用平台代码没有问题。但是,当我尝试调用某个库(或框架,不确定如何正确调用它,因为我不是 iOS 开发人员)时,它失败了。 Docs 声明可以调用 Objective-C 代码和 Swift 如果正确导出:
Kotlin/Native provides bidirectional interoperability with Objective-C. Objective-C frameworks and libraries can be used in Kotlin code if properly imported to the build (system frameworks are imported by default). See e.g. "Using cinterop" in Gradle plugin documentation. A Swift library can be used in Kotlin code if its API is exported to Objective-C with @objc. Pure Swift modules are not yet supported.
但它没有说明如何正确导入它们。它只指向描述旧版本 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 '${pods}Firebase/CoreOnly/Sources',
'${pods}FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers'
}
}
}
}
Build 运行没有失败,但它没有导入任何东西。我究竟做错了什么?是否可以完全导入这样的库?
更新:
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
工具?
看来您要使用 cocoapods 库。目前 Gradle 插件不支持开箱即用的 Cocapods。但是可能是依赖你的库可以配置"manully"。你能分享一个 link 到你的项目吗?
我在 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 放置主 header 文件。它包含对它需要的其他 header 文件的引用...因此您在 headers 部分的 .def
文件中指定这些文件名。
接下来,您需要指定在何处查找这些文件以及它们引用的其他文件。您可以在 includeDirs
或 build.gradle
文件中的 .def
文件中执行此操作。我更喜欢使用 build.gradle 文件,因为它可以使用变量。因此,您指定了这些 Public
文件夹的路径。 (这足以让 kotlin 查看库 API,但是为了能够 运行 您需要编译的应用程序和 link 这个库...)
然后编译器和 linker 需要知道 library/framework 在哪里。因此,您在 compilerOpts
和 linkerOpts
中指定框架根文件夹的路径,如果它是框架,则在它们前面加上 -F
前缀,如果它是库,则在它们前面加上 -L
前缀。
我正在尝试在多平台项目中从 Kotlin 调用 Swift/Objective-C 代码。调用平台代码没有问题。但是,当我尝试调用某个库(或框架,不确定如何正确调用它,因为我不是 iOS 开发人员)时,它失败了。 Docs 声明可以调用 Objective-C 代码和 Swift 如果正确导出:
Kotlin/Native provides bidirectional interoperability with Objective-C. Objective-C frameworks and libraries can be used in Kotlin code if properly imported to the build (system frameworks are imported by default). See e.g. "Using cinterop" in Gradle plugin documentation. A Swift library can be used in Kotlin code if its API is exported to Objective-C with @objc. Pure Swift modules are not yet supported.
但它没有说明如何正确导入它们。它只指向描述旧版本 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 '${pods}Firebase/CoreOnly/Sources',
'${pods}FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers'
}
}
}
}
Build 运行没有失败,但它没有导入任何东西。我究竟做错了什么?是否可以完全导入这样的库?
更新:
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
工具?
看来您要使用 cocoapods 库。目前 Gradle 插件不支持开箱即用的 Cocapods。但是可能是依赖你的库可以配置"manully"。你能分享一个 link 到你的项目吗?
我在 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 放置主 header 文件。它包含对它需要的其他 header 文件的引用...因此您在 headers 部分的 .def
文件中指定这些文件名。
接下来,您需要指定在何处查找这些文件以及它们引用的其他文件。您可以在 includeDirs
或 build.gradle
文件中的 .def
文件中执行此操作。我更喜欢使用 build.gradle 文件,因为它可以使用变量。因此,您指定了这些 Public
文件夹的路径。 (这足以让 kotlin 查看库 API,但是为了能够 运行 您需要编译的应用程序和 link 这个库...)
然后编译器和 linker 需要知道 library/framework 在哪里。因此,您在 compilerOpts
和 linkerOpts
中指定框架根文件夹的路径,如果它是框架,则在它们前面加上 -F
前缀,如果它是库,则在它们前面加上 -L
前缀。