使用Kotlin / Native

时间:2017-12-01 15:01:50

标签: ios kotlin native

我想包含一个Kotlin文件,该文件仅在现有iOS项目中执行数据处理和网络操作,同时保留原生iOS UI代码。

虽然我认为使用Kotlin/Native可以实现这一点,但我发现使用Kotlin / Native的iOS示例(12)似乎接管了iOS UI代码同样。

在Kotlin / Native中包含一个用于iOS数据传输的Kotlin文件,而无需触及UI代码,如果是这样,有什么步骤可以做到这一点?

2 个答案:

答案 0 :(得分:5)

是的,在跨平台项目中,可以使用Kotlin / Native在Kotlin和本机iOS UI代码之间传输数据。这允许基于Kotlin具有用于数据模型的公共代码库,例如,继续使用iOS的原生UI代码。

原始证明:

项目https://github.com/justMaku/Kotlin-Native-with-Swift指出了我正确的方向,因为它显示了这样做的基本步骤:

在Swift UIViewController中,它调用一个包装器函数,该函数将从Kotlin函数接收一个字符串。调用是通过C ++层调解的,C ++层本身启动Kotlin运行时,将请求传递给Kotlin函数,从中接收字符串,然后将其传递回Swift UIViewController,然后显示它。

在技术层面上,该项目包含一个脚本,可以将Kotlin,C ++和Kotlin / Native部分编译成静态库,然后可以从本机iOS项目中调用它。

为了让代码运行,我(在从git克隆之后)执行了一个" git子模块同步"在运行" ./ setup.sh"。

之前

要使用基于Kotlin的数据模型传输数据,我希望有一个通用函数,可以将数据传递给Kotlin,修改该数据,并将结果返回到本机iOS代码。作为原理的证明,可以构建这样的函数,我将项目扩展为不仅从Kotlin接收字符串,而且将一个字符串发送给Kotlin,附加它,并将结果发回。

项目的扩展:

由于在这个看似简单的扩展中存在一些障碍,我为任何感兴趣的人布置了步骤。如果您继续,则应显示以下内容:

Kotlin <-> Swift

文字可能很愚蠢,但它会告诉你,会发生什么。 函数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的文本(最后,将显示生成的&#39;字符串&#39;变量)。可以直接将Swift String传递给包装器,但我想强调包装器会将输入和输出视为c-strings。实际上,本机iOS项目中的文件Kotlin Native-Bridging-Header.h现在变为:

extern const char* kotlin_wrapper(const char* swiftMessage);

在它上面转到文件Launcher.cpp。由于original file使用KString作为kotlin_main的结果值,我尝试了一段时间convert const char* to 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;
}

你看到包装器如何首先启动Kotlin运行时,然后调用函数kotlin_main,它位于文件kotlin.kt中:

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 ++层。只需定义pack和unpack函数,将任意数据类型打包成字符串,然后将字符串解压缩到另一端的相应数据类型。这种打包和解包函数必须每种语言只写一次,如果做得足够通用,可以重复用于不同的项目。在实践中,我可能会首先重写上面的代码来传递二进制数据,然后编写pack和unpack函数来将任意数据类型转换为二进制数据和从二进制数据转换。

答案 1 :(得分:2)

如果需要,您可以使用kotlin作为框架,因此kotlin代码保留在框架文件中,因此您可以在Android和iOS上使用一些通用代码,而无需在kotlin中编写完整的iOS应用程序。

使用gradle在objc / swift兼容框架中构建你的kotlin代码

在build.gradle文件中

buildscript {
    ext.kotlin_native_version = '0.5'
    repositories {
        mavenCentral()
        maven {
            url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies"
        }
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:$kotlin_native_version"
    }
}
group 'nz.salect'
version '0.1'
apply plugin: "konan"
konan.targets = ["iphone", "iphone_sim"]
konanArtifacts {
    framework('nativeLibs')
}

它将生成两个.framework文件,一个用于实际设备的模拟器,将框架放入项目中,并将其链接到您的项目,与任何其他第三方框架一样。

Cmd: ./gradlew build
  

注意:每次更改kotlin文件时都会构建并替换你的   框架文件(您可以创建一个shell脚本并将其添加到   建立自动完成的阶段。)

干杯!!!