从多平台kotlin项目访问C / C ++库

时间:2020-03-15 10:58:30

标签: android c++ kotlin kotlin-multiplatform kotlin-native

我第一次使用Android Studio构建一个多平台项目。我创建了一个Android应用程序模块,该模块在Android上使用多平台库。 我还使用XCode构建了一个在iOS上使用多平台库的iOS应用。 一切正常,我可以使用由不同expect fun实施的actual fun来安装Android和iOS。

我还用C ++创建了一个暴露C接口的库。

#ifndef PINGLIB_LIBRARY_H
#define PINGLIB_LIBRARY_H

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    long long elapsed;
} PingInfo;

typedef void (*PingCallback)(PingInfo pingInfo);
typedef struct
{
    PingCallback pingUpdate;
} PingObserver;

void* ping(const char * url, const PingCallback *pingCallback);
void subscribe(void* pingOperation);
void unsubscribe(void* pingOperation);

#ifdef __cplusplus
}
#endif

#endif //PINGLIB_LIBRARY_H

我使用CLion构建C ++代码。 我已经创建了一个.def文件,用于使用cinterop来构建库。

package = com.exercise.pinglib
headers = PingLibrary.h
linkerOpts.linux = -L/usr/lib/x86_64-linux-gnu
compilerOpts = -std=c99 -I/Users/username/myproject/ping/ping/header
staticLibraries = libping.a
libraryPaths = /opt/local/lib /Users/username/myproject/ping/cmake-build-debug

libping.a是使用C ++代码创建的库。它是在文件夹/Users/username/myproject/ping/cmake-build-debug

中创建的

当我运行命令cinterop -def ping.def -o ping时,它将创建klib文件和一个包含manifest.properties文件的文件夹以及一个natives子文件夹,该子文件夹包含一个cstubs.bc文件和一个{{1 }}子文件夹和一个kotlin文件。

.kt

如何在我的kotlin-multiplatform项目中使用ping.klib -ping-build manifest.properties -natives cstubs.bc -kotlin -com -exercise -pinglib pinglib.kt 创建的库?

我找到了导入它的不同方法,但是我没有找到关于它的完整描述。 Here他们说我可以使用类似的东西:

cinterop

我在iOS项目中做到了这一点,但我仍然不知道如何在Android和iOS上都不访问kotlin类。

这是我的 implementation files("ping.klib")

build.gradle

编辑 我已经改变了这个问题,因为起初我以为apply plugin: 'com.android.library' apply plugin: 'kotlin-multiplatform' android { compileSdkVersion 28 defaultConfig { minSdkVersion 15 } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } kotlin { targets { final def iOSTarget = System.getenv('SDK_NAME')?.startsWith('iphoneos') ? presets.iosArm64 : presets.iosX64 fromPreset(iOSTarget, 'ios') { binaries { framework('shared') } } fromPreset(presets.android, 'android') } sourceSets { // for common code commonMain.dependencies { api 'org.jetbrains.kotlin:kotlin-stdlib-common' } androidMain.dependencies { api 'org.jetbrains.kotlin:kotlin-stdlib' } iosMain.dependencies { implementation files("ping.klib") } } } configurations { compileClasspath } task packForXCode(type: Sync) { final File frameworkDir = new File(buildDir, "xcode-frameworks") final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG' final def framework = kotlin.targets.ios.binaries.getFramework("shared", mode) inputs.property "mode", mode dependsOn framework.linkTask from { framework.outputFile.parentFile } into frameworkDir doLast { new File(frameworkDir, 'gradlew').with { text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n" setExecutable(true) } } } tasks.build.dependsOn packForXCode 并不是在创建klib库,但这只是一个错误:我在cinterop文件夹中查找,但是文件不在该文件夹中。所以我解决了一半的问题。

EDIT2 我添加了ping-build

1 个答案:

答案 0 :(得分:1)

我很高兴看到KLIB一切正常,现在有关库的使用。
首先,我要提到的是,该库只能由Kotlin / Native编译器使用,这意味着它将可用于某些目标(请参见列表here)。然后,如果要将C库的使用包含到MPP项目中,最好通过Gradle脚本生成绑定。它可以在目标内部完成,例如,请参见this文档。对于您的iOS目标,它应该像这样:

kotlin {
    iosX64 {  // Replace with a target you need.
        compilations.getByName("main") {
            val ping by cinterops.creating {
                defFile(project.file("ping.def"))
                packageName("c.ping")
            }
        }
    }
}

此代码段会将cinterop任务添加到您的Gradle中,并提供将import c.ping.*之类的模块包含在相应Kotlin文件中的功能。