问题也是很显然的,如果你也尝试这样做了,一定被这些映射过来的接口函数的签名给搞晕过: public final var RegisterNatives: kotlinx.cinterop.CPointer <kotlinx.cinterop.CFunction<(kotlinx.cinterop.CPointer<platform.android.JNIEnvVar /* = kotlinx.cinterop.CPointerVarOf <platform.android.JNIEnv /* = kotlinx.cinterop.CPointer<platform.android.JNINativeInterface> */> */>? /* = kotlinx.cinterop.CPointer<out kotlinx.cinterop.CPointed>? */, kotlinx.cinterop.CPointer<platform.android.JNINativeMethod>?
ViewController类的源码如下: import kotlinx.cinterop.ExportObjCClass import kotlinx.cinterop.ObjCAction import kotlinx.cinterop.ObjCOutlet import platform.Foundation.NSCoder import platform.UIKit.* import kotlinx.cinterop.initBy
iOS 则是通过 cinterop 这个能力生成 Kotlin 识别的三方库头文件实现能力调用的。 cinterop 是 Kotlin Native 支持的能力,KMM 工程的编译使用了 gradle 工具链,其中对 iOS 来说,我们使用了 Kotlin CocoaPods 插件。 pod 脚本写好库和版本,接着执行 gradle sync,其中会执行两个关键的 task,第一个是 podGen,它会把我们需要依赖的库通过 pod 拉到本地,生成一个壳工程,然后会执行对应库的 cinterop
这个是我们刚刚引入的 KotlinCMakeModule 当中定义的函数,大家有兴趣可以点进去看下它的实现 # 目的与 Gradle 当中的 interop(...){ ... } 一样,配置 C Api cinterop # C Api 兼容模块的名称 NAME tensorflow # C Api 兼容配置文件路径 DEF_FILE src/main/cinterop
后面我们可能会把精力花在研究一下 cinterop 这个工具以及 iOS 的构建系统上。 如果能用 cinterop 搞定对已有的 iOS Framework 或 .a 文件的依赖,我们可以基于许多已有的 Objective-C 库和 Java 库封装出许多实用的 KMM 库,而暂时不必用
kotliner/cn_kotliner.bc -o build/kotliner/kotliner.kexe kotliner.kt.bc : kotliner.bc kotliner.def cinterop org.jetbrains.kotlin.backend.konan.LinkStage.link(LinkStage.kt:261) 3.3 def 文件的路径 如果你使用前面的 makefile 进行编译,cinterop 调用时传入的 def 文件的路径一定不能写成下面这样 cinterop -def kotliner.def -o build/kotliner/kotliner.kt.bc kotliner.def 这个问题是因为 cinterop 最终会调用 clang 去编译一个动态生成的 c 文件,而调用时传入的 workdir 是 def 文件的父目录,如果我们传入 def 文件时写了形如 “-def kotliner.def
frameworkName = "alog" pod("CocoaLumberjack") } 通过cinterop一些gradle Task会自动生成头文件给iosMain使用,比如生成alog-cinterop-CocoaLumberjack.klib
然后随便创建一个文件,写一个全局函数,并用 CName 进行标注如下: import kotlinx.cinterop.* import platform.android.* @CName("Java_com_example_hellojni_HelloJni_stringFromJNI
Suppress("UNUSED_EXPRESSION", "UNUSED_VARIABLE") package ckotlinor import konan.SymbolName import kotlinx.cinterop bin目录 bin目录下面是执行命令行 cinterop klib konanc kotlinc kotlinc-native run_konan package_kotlin.text.regex │ ├── package_kotlin.util │ ├── package_kotlinx │ ├── package_kotlinx.cinterop package_kotlin.text.regex │ ├── package_kotlin.util │ ├── package_kotlinx │ ├── package_kotlinx.cinterop package_kotlin.text.regex │ ├── package_kotlin.util │ ├── package_kotlinx │ ├── package_kotlinx.cinterop
要做到这点需要完成3个步骤,首先是创建 .def 文件,然后用cinterop 工具生成 bindings,最后编译Kotlin / Native 项目。
图16-3 编译器konan目录结构 打开Kotlin Native编译器的bin目录可以发现,bin文件主要由cinterop、jsinterop、klib、konanc、kotlinc、kotlinc-native kotliner/cn_kotliner.bc -o build/kotliner/kotliner.kexe kotliner.kt.bc : kotliner.bc kotliner.def cinterop
这里仅列举 iOS 集成过程中的若干场景问题: 2.2.1 cinterop 官方提供的 cinterop 工具可以将指定的 C/Objective-C 库的所有公开 API 封装转译为 Kotlin 配置示例: target.compilations["main"].cinterops.create(name) { defFile = project.file("src/nativeInterop/cinterop 在 iOS 平台如下: actual typealias MMKV = xxx.xxx.ios.MMKV iOS 上没有包名的概念,xxx.xxx.ios 是使用 cinterop 等工具生成 Kotlin
最后我们来看一下 nativeMain 下的源码结构: cinterop 包包含所有对 SQLite C 函数直接互操作的代码,通过单独的包将其与其它代码隔离;platform 包则存放所有待平台实现的相关代码