【问题标题】:Kotlin Multiplatform Mobile can't find klib packageKotlin Multiplatform Mobile 找不到 klib 包
【发布时间】:2021-06-25 07:28:50
【问题描述】:

我已经阅读了这些 SO 帖子 123,它们面临着类似的问题。我正在尝试在我的 KMM Android 项目中使用.klib。 Klib 是从library.h C 标头构建的。这是我所做的:

我构建了 Kotlin 库

在 KMM shared 项目中使用以下 Gradle 块:

kotlin {
    ...
    androidNativeArm64 { // target
        compilations.getByName("main") {
            val mylib by cinterops.creating {
                defFile(project.file("mylib.def"))

                packageName("c.mylib")
                // Options to be passed to compiler by cinterop tool.
                compilerOpts("-I/home/me/CLionProjects/mylib/")

                // Directories for header search (an analogue of the -I<path> compiler option).
                includeDirs.allHeaders("/home/me/CLionProjects/mylib/")

                // A shortcut for includeDirs.allHeaders.
                includeDirs("/home/me/CLionProjects/mylib/")
            }
        }
        binaries {
            sharedLib() // https://kotlinlang.org/docs/mpp-build-native-binaries.html#declare-binaries
        }
    }
}

带有mylib.def 文件

headers = /home/me/CLionProjects/mylib/library.h
headerFilter = /home/me/CLionProjects/mylib/*
package = c.mylib

在构建时,.klib 和 build 文件夹出现在共享项目的classes 目录中,如下所示:

Platform下面的红线是错误的:

预期的类 'Platform' 在模块 MyApplication.shared.androidNativeArm64Main for Native 中没有实际声明

但显然that may just be a system glitch(不确定-“创建实际类...”的 Alt+Enter 解决方案似乎没有做任何事情)。假设这不是问题,我继续...

我查看.klib详情

运行 .konan/.../bin/klib info mylib.klib 我没有将 c.mylib 作为包名,而是将 com.example.myapplication:shared-cinterop-mylib 改为(见下文)。我可以忍受(虽然不确定为什么它不是我在 Gradle 中指定的)

Resolved to: /home/me/AndroidStudioProjects/MyApplication/shared/build/classes/kotlin/androidNativeArm64/main/shared-cinterop-mylib
Module name: <com.example.myapplication:shared-cinterop-mylib>
ABI version: 1.4.1
Compiler version: 1.4.10
Library version: null
Metadata version: 1.4.0
IR version: 1.0.0
Available targets: android_arm64

我尝试将包包含在我的 androidApp Gradle 中

我想访问我的androidApp 项目中的.klib。我尝试了c.mylibcom.example.myapplication:shared-cinterop-mylib 两个包。

我尝试将implementation("com.example.myapplication:shared-cinterop-mylib") 添加到我的androidApp Gradle 文件中,但出现错误:

无法确定任务 ':androidApp:lintVitalRelease' 的依赖关系。 无法解析配置“:androidApp:debugCompileClasspath”的所有工件。 找不到 com.example.myapplication:shared-cinterop-mylib:。 要求: 项目:androidApp 可能的解决方案:

我不确定提示是否能解决问题,但我尝试使用例如将文件添加到 androidApp Gradle repositories { ... }

    maven {
        url = uri("/home/me/AndroidStudioProjects/MyApplication/shared/build/classes/kotlin/androidNativeArm64/main/shared-cinterop-mylib.klib")
    }

但我不确定这是将文件添加到存储库的正确方法。

问题

谁能帮我让androidApp 中的包裹得到认可?我会继续努力的。

【问题讨论】:

    标签: android-studio gradle kotlin-multiplatform kotlin-native kmm


    【解决方案1】:

    您可能对针对不同平台的不同 Kotlin 版本感到困惑。详情请查看the documentation,我将尝试在这里解释基本概念。

    Kotlin Multiplatform 通常由三种不同的编译器组成:一种用于为 JVM 构建,一种用于转译为 JS,另一种用于编译特定于平台的本机二进制文件(可执行文件、静态或共享库)。 KMM 技术是关于在两个不同的平台(iOS 和 Android)之间共享您的代码。

    这里的重要细节是,KMM 旨在让开发人员更容易将此共享代码包含到他们现有的代码库中——通常是 Swift 或 Objective-C 用于 iOS 和 Java 或 Kotlin/JVM 用于 Android。这很重要,因为这个项目是使用 Kotlin/Native 和 Kotlin/JVM 构建的。

    在您的代码中,我看到了一个额外的平台声明。 androidNativeArm64,这是一个 Kotlin/Native 目标,而不是经典的 Android 目标。它使用另一个编译器,并因此生成一个共享库。这就是原因

    1. 您可以定义一个 cinterop 块,为标头创建绑定,但是
    2. 这些绑定仅适用于 Kotlin/Native 编译的一部分。

    您在此处创建的 KLIB 本身不是库,而是本地库的一组绑定 (mylib)。它使您能够使用 Kotlin 代码中的 mylibs API,该代码编写在 androidNativeArm64Main 源代码集中。由于您目前没有设置这样的源,您的项目无法正确构建,并显示有关 missing actual declaration 的警告。

    结束上述所有内容。以下是项目当前状态下可以做和不能做的事情:

    可以

    • 使用 Kotlin/Native 代码中的绑定(将文件添加到 shared/src/androidNativeArm64Main/kotlin/
    • 使用这些绑定到共享库(.so 文件)编译代码
    • 按照 Android NDK 文档中的说明使用此共享库 (here)

    • shared/src/androidMain/kotlin/ 处删除 Kotlin/Native Android 目标和不使用 C API 的代码

    不能

    • 依赖于 Kotlin/JVM 模块中的 KLIB(例如,一般的 androidApp 项目或 androidMainshared 中设置的源代码)
    • 发布绑定并且不关心将生成的工件与 C 库链接
    • 使用从 Kotlin/Native 编译的共享库或静态库比使用 C/C++ 本地库更容易(抱歉,您可能会在此处尝试避免使用相同的 JNI 方法

    抱歉,答案冗长而复杂,如有任何问题,请在下面的评论部分与我联系。我很乐意纠正我的任何错误或不准确之处。

    【讨论】:

    • 感谢您的回答,我会进一步考虑。我想要实现的是将我的 C/C++ 库编译为单个 Kotlin 库,并在 iOS 和 Android 项目中使用该单个 API,而无需在 Android 中使用 JNI 或在 iOS 中使用其他包装器。我认为 KMM 可以让我将 C++ 代码编译为 Kotlin 库,并在 Android 和 iOS 中使用该库。但你的最后一点让我认为这是不可能的?
    • 是的,现在这不是一个选项。 KMM 使用 Kotlin/Native 编译器,它允许您从 Kotlin 代码使用 C 库(尚无 C++ 互操作,但一些类似 C 的头文件也可以工作)并将结果二进制文件与这些库链接。或者,它允许您生成本机库,并从 C/C++ 中使用它。
    • 嗨,Artyom。你的最后一句话让我颠覆了我的想法。你是说我可以创建一个通用的shared Kotlin API,其中包含expectedactual 函数(在各自的iOSAndroid 子项目中实现的实际函数),然后编译和构建该Kotlin API 并通过它复制到我的 C/C++ 核心代码的两个副本,每个副本都位于 iOSAndroid 子项目中?如果这是可能的,那么我认为这将解决我的问题,我可能一直在错误地考虑 KMM。
    • 是的,如果您使用 Kotlin/Native 目标(参见 here,对于 android 则需要 androidNative 一个),您可以将项目设置为生成静态或动态库(参见this doc)。结果将从 C/C++ 代码中获得,就像从 C 源代码构建的库一样。这种方式不太流行,只能参考this老教程。您可以随时在这里或 kotlinlang Slack 向人们寻求建议。
    猜你喜欢
    • 2021-02-01
    • 2023-01-30
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    • 2022-12-30
    • 2019-12-01
    • 2021-06-22
    • 1970-01-01
    相关资源
    最近更新 更多