是的,在跨平台项目中,可以使用Kotlin/Native在Kotlin和本地iOS UI代码之间传输数据。这样可以基于Kotlin拥有一个通用的数据模型代码库,同时仍然可以使用本地iOS UI代码。原始证明可以在
https://github.com/justMaku/Kotlin-Native-with-Swift 中找到。该项目展示了必要的步骤:
在Swift UIViewController中,它调用一个包装函数,该函数应该从Kotlin函数接收一个字符串。调用是通过一个C++层来介绍的,该层启动Kotlin运行时,将请求传递给Kotlin函数,从中接收字符串,然后将其返回给Swift UIViewController,然后显示它。
从技术层面上说,该项目包含一个编译Kotlin、C++和Kotlin/Native部分成静态库的脚本,然后可以从本地iOS项目中调用。
为使代码运行,我需要(在克隆git之后)执行“git submodule sync”,然后运行“./setup.sh”。
为了使用基于Kotlin的数据模型传输数据,我想要一个通用函数,可以将数据传递给Kotlin,修改该数据,并将结果返回到本地iOS代码。作为原则性证明,这样的函数可以被构建,我扩展了项目,不仅从Kotlin接收字符串,而且向Kotlin发送字符串,追加它并将结果发送回来。
项目的扩展:
由于在这个看似简单的扩展中存在一些障碍,我列出了步骤供任何有兴趣的人参考。如果您跟着做,您应该能够得到以下显示:
![Kotlin <-> Swift](https://istack.dev59.com/7fWdz.webp)
这段文字可能有些简单,但它告诉你发生了什么。
在函数viewDidAppear中,ViewController.swift中的更改如下:
let swiftMessage: String = "Hello Kotlin, this is Swift!"
let cStr = swiftMessage.cString(using: String.Encoding.utf8)
if let retVal = kotlin_wrapper(cStr) {
let string = String(cString: retVal)
...
}
你可以在包装函数中看到Swift发送给Kotlin的文本(最终,结果变量'string'将被显示)。一个人可以直接将Swift字符串传递给包装器,但我想强调包装器将把输入和输出视为c-strings。实际上,在本机iOS项目中,文件Kotlin Native-Bridging-Header.h现在变成了:
extern const char* kotlin_wrapper(const char* swiftMessage);
它继续前往文件Launcher.cpp。由于
原始文件将KString用作kotlin_main的结果值,因此我尝试了一段时间
将const char*转换为KString并将其传递给kotlin_main。最后我发现,直接将const char*变量传递到Kotlin中要简单得多,并在那里使用Kotlin/Native提供给我们的函数进行转换。
我的Launcher.cpp比原始文件更加紧凑。以下是完整的文件:
#include "Memory.h"
#include "Natives.h"
#include "Runtime.h"
#include "KString.h"
#include <stdlib.h>
#include <string>
extern "C" const char* kotlin_main(const char* swiftMessageChar);
extern "C" const char* kotlin_wrapper(const char* swiftMessageChar) {
RuntimeState* state = InitRuntime();
if (state == nullptr) {
return "Failed to initialize the kotlin runtime";
}
const char* exitMessage = kotlin_main(swiftMessageChar);
DeinitRuntime(state);
return exitMessage;
}
你可以看到,wrapper首先启动Kotlin运行时,然后调用kotlin.kt文件中的函数kotlin_main:
import konan.internal.ExportForCppRuntime
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.cstr
import kotlinx.cinterop.nativeHeap
import kotlinx.cinterop.toKString
@ExportForCppRuntime
fun kotlin_main(cPtr: CPointer<ByteVar>): CPointer<ByteVar> {
val swiftMessage = cPtr.toKString()
val kotlinMessage = "Hello Swift, I got your message: '$swiftMessage'."
val returnPtr = kotlinMessage.cstr.getPointer(nativeHeap)
return returnPtr
}
将指针转换为 Kotlin 字符串,然后用于创建 kotlinMessage (数据转换示例)。然后将结果消息转换回指针,并通过包装器传递回 Swift 的 UIViewController。
接下来该怎么做?
原则上,可以在不再触及 C++ 层的情况下使用此框架。只需定义打包和解包函数,将任意数据类型打包成字符串并在另一侧解包字符串以获取相应的数据类型。这样的打包和解包函数每种语言只需要编写一次,并且如果足够通用,则可以在不同项目中重复使用。实际上,我可能会先重写以上代码以传递二进制数据,然后编写打包和解包函数以将任意数据类型转换为二进制数据并从中进行转换。