Файл Kotlin в собственном проекте iOS с Kotlin / Native

Я хотел бы включить файл Kotlin, который выполняет только обработку данных и сетевые операции в существующем проекте iOS, сохраняя собственный код интерфейса iOS.

Хотя я думал, что это может быть достигнуто с помощью Kotlin / Native , образцы iOS ( 1 , 2 ), которые я обнаружил, что использование Kotlin / Native, похоже, также использует код IOS UI.

Включает ли файл Kotlin для передачи данных в iOS с Kotlin / Native, не касаясь кода пользовательского интерфейса, и если да, то каковы шаги для этого?

    Да, в кросс-платформенном проекте можно передавать данные между Kotlin и native IOS UI Code, используя Kotlin / Native. Это позволяет иметь общую базу кода для модели данных на основе Kotlin, в то время как, например, продолжать использовать собственный код пользовательского интерфейса для iOS.

    Исходное доказательство:

    Проект https://github.com/justMaku/Kotlin-Native-with-Swift указал мне в правильном направлении, так как он показывает основные шаги для этого:

    В Swift UIViewController он вызывает функцию-оболочку, которая должна получать строку из функции Kotlin. Вызов опосредуется через слой C ++, который сам запускает время выполнения Kotlin, передает запрос функции Kotlin, получает строку от него и передает его обратно в Swift UIViewController, который затем отображает его.

    На техническом уровне проект содержит скрипт, который компилирует часть Kotlin, C ++ и Kotlin / Native в статическую библиотеку, которую затем можно вызывать из собственного проекта iOS.

    Чтобы запустить код, у меня было (после клонирования из git), чтобы выполнить «git subodule sync» перед запуском «./setup.sh».

    Для передачи данных с помощью модели данных, основанной на Kotlin, я хотел бы иметь общую функцию, которая может передавать данные в Kotlin, изменять эти данные и возвращать результат обратно в исходный код iOS. В качестве доказательства принципа, что такая функция может быть построена, я продлил проект, чтобы не только получить строку из Kotlin, но отправить ее в Kotlin, добавить ее и отправить результат обратно.

    Расширение проекта:

    Поскольку в этом, казалось бы, простом расширении были некоторые препятствия, я излагаю шаги для любого заинтересованного. Если вы следуете, вы должны получить следующее:

    Котлин <-> Свифт

    Текст может быть глупым, но он говорит вам, что происходит. Изменения в ViewController.swift в функции viewDidAppear:

    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-строки. В самом деле, файл Kotlin Native-Bridging-Header.h внутри собственного проекта iOS теперь становится:

     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; } 

    Вы видите, как обертка сначала запускает время выполнения 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 ++. Просто определите функции пакета и распаковки, которые упаковывают произвольные типы данных в строку и распаковывают строку на соответствующий тип данных с другой стороны. Такие функции пакетной и распаковки должны быть записаны только один раз на один язык и могут быть повторно использованы для разных проектов, если они сделаны достаточно универсальными. На практике я, вероятно, сначала переписал бы приведенный выше код для передачи двоичных данных, а затем записывал пакеты и распаковывал функции для преобразования произвольных типов данных в двоичные данные и из них.

    Intereting Posts
    Каково поведение Iterable # all & Why Kotlin Char :: class.java! = Char.javaClass В чем разница между () -> единицей и (единицей) -> типами единиц? Как использовать `filterValues` на вложенной итерации Hashmap в Котлин? Как создать библиотеку в Kotlin и использовать ее из проектов, предназначенных для javascript или java? Есть ли способ вложить enum в класс данных в Котлин? Дженкинс град строит неудачу из-за приложения: compileDebugKotlin 5.1 Сбой – основной цвет задачи TaskDescription должен быть непрозрачным Как отправить уведомление от IntentService на Android с помощью Kotlin Почему вызовы должны быть вызваны с помощью вызова класса класса? runOnUiThread не вызывает В kotlin, Когда я перегружаю оператор inc (), я получаю ошибку Использование константы java в параметре аннотации Kotlin Почему модификатор Kotlin «open» несовместим с «данными»? Как инициализировать свойство массива аннотации в Котлине Как использовать рекурсивный тип в Котлине