android - 从多平台 kotlin 项目访问 C/C++ 库
问题描述
我第一次使用 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
文件kotlin
夹.kt
。
ping.klib
-ping-build
manifest.properties
-natives
cstubs.bc
-kotlin
-com
-exercise
-pinglib
pinglib.kt
如何使用cinterop
在我的 kotlin-multiplatform 项目中创建的库?
我找到了不同的方法来导入它,但我没有找到任何关于如何做到这一点的完整描述。 在这里他们说我可以使用类似的东西:
implementation files("ping.klib")
我是为 iOS 项目做的,但我仍然不知道如何在 Android 和 iOS 上访问 kotlin 类。
这是我的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
编辑
我改变了这个问题,因为最初,我认为这cinterop
不是创建 klib 库,但这只是一个错误:我正在查看ping-build
文件夹,但文件在该文件夹之外。所以我解决了一半的问题。
EDIT2
我添加了build.script
解决方案
I'm glad to see that everything is fine with the KLIB, now about the library use.
First of all, I have to mention that this library can be utilized only by Kotlin/Native compiler, meaning it will be available for some targets(see list here). Then, if you're going to include C library use into an MPP project, it is always better to produce bindings via the Gradle script. It can be done inside of a target, see this doc for example. For your iOS target it should be like:
kotlin {
iosX64 { // Replace with a target you need.
compilations.getByName("main") {
val ping by cinterops.creating {
defFile(project.file("ping.def"))
packageName("c.ping")
}
}
}
}
This snippet will add cinterop task to your Gradle, and provide module to include like import c.ping.*
inside of the corresponding Kotlin files.
推荐阅读
- android - 如何解决错误膨胀类 android.support.design.widget.FloatingActionButton
- proxy - 如何将 Google Cloud PubSub 与代理一起使用?
- jquery - jQuery选择并取消选中一个复选框
- c# - 启用具有 2.0 框架的 IIS 应用程序以通过 TLS 1.2 工作
- java - 安装到google play时出错
- ios - 调用中的额外参数“数据”
- rx-java - RxJava 中的冷可观察
- python - 提取数据框中的公共信息
- mybatis - MyBatis resultMap 中是否需要'jdbcType'?
- powershell - 无法通过 Powershell 在 ARM 模板中传递数组类型参数