具有Objective-C框架的Kotlin多平台/本机互操作性

ole*_*men 7 kotlin kotlin-interop kotlin-native kotlin-multiplatform

我试图在多平台项目中从Kotlin调用Swift / Objective-C代码。调用平台代码没有问题。但是,当我尝试调用某个库(或框架,因为我不是iOS开发人员而不确定如何正确调用它)时,它将失败。Docs指出,如果正确导出,可以调用Objective-C代码和Swift:

Kotlin / Native提供与Objective-C的双向互操作性。如果正确导入到构建中,则可以在Kotlin代码中使用Objective-C框架和库(默认情况下会导入系统框架)。请参阅Gradle插件文档中的“使用cinterop”。如果Swift库的API已通过@objc导出到Objective-C,则可以在Kotlin代码中使用它。尚不支持Pure Swift模块。

但这并没有说明如何正确导入它们。它仅指向gradle插件描述,该描述描述了gradle插件的旧版本。因此它对我不起作用。最后,我发现了某种可能是导入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'
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

生成运行不会失败,但是不会导入任何内容。我究竟做错了什么?是否可以完全导入这样的库?

UPD:

在这里,我找到了一个使用cinterop工具示例,如下所示:

cd samples/gitchurn
../../dist/bin/cinterop -def src/main/c_interop/libgit2.def \
 -compilerOpts -I/usr/local/include -o libgit2
Run Code Online (Sandbox Code Playgroud)

看来cinterop工具应该/dist/bin/在我的项目的文件夹中,但是没有这样的文件夹。我在哪里可以获得cinterop工具?

ole*_*men 6

cinterops在 build.gradle结束了这个部分

    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"
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

结束这个.def文件:

language = Objective-C
headers = FirebaseCore.h FirebaseDatabase.h
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?Cocopods 框架放置Pods在您的 Xcode 项目的目录中。稍微浏览一下这个文件夹,你会找到你需要的东西。我不确定是否有一些标准但 firebase 将主头文件放在Public文件夹中。并且它包含对它需要的其他头文件的引用......所以你在你的.def文件中的 headers 部分指定这些文件名。

接下来,您需要指定在何处查找这些文件以及它们引用的其他文件。您可以在.def文件中includeDirs或文件中执行此build.gradle操作。我更喜欢使用 build.gradle 文件,因为它可以使用变量。所以你指定这些Public文件夹的路径。(这足以让 kotlin 看到库 API,但为了能够运行应用程序,您需要编译和链接这个库......)

然后编译器和链接器需要知道库/框架在哪里。因此,您可以在其中指定框架根文件夹的路径,compilerOptslinkerOpts-F其为框架或-L库时为其添加前缀。