Коммит 560b2b54 создал по автору Зарубин Виталий Викторович's avatar Зарубин Виталий Викторович
Просмотр файлов

Merge branch 'hello-world' into 'master'

feat: add "Hello, QtBindings!"

See merge request oss/kmp/docs!4
владельцы fefe4d5d 4b0932c2
# IDE
.idea
.vscode
# MdBook
/book
......@@ -50,6 +50,11 @@ a:hover {
border-radius: 10px;
}
.preview2 {
border-radius: 10px;
border: 1px solid var(--quote-border);
}
.table-wrapper table {
width: 100%;
text-align: left;
......@@ -112,6 +117,12 @@ a:hover {
color: white;
}
blockquote {
border-radius: 6px;
border: var(--quote-border);
padding: 1px 20px;
}
/* Hide Index */
.chapter strong,
.chapter > .chapter-item:first-child {
......
# Hello, Qt world!
# Hello, QtBindings!
Здесь будет описан процесс как создать приложение с походом Qt/Qml + QtBindings для ОС Аврора.
> В этом разделе описан процесс создания приложения с использованием
> **QtBindings** и нативного для Linux таргета (_linuxX64_ и _linuxArm64_) для ОС Аврора.
>
> Уже установили необходимые зависимости в [local maven](./connection.md)?
> Время написать первое приложение на KMP для ОС Аврора!
### Структура
```rust
// This is a comment, and is ignored by the compiler.
// You can test this code by clicking the "Run" button over there ->
// or if you prefer to use your keyboard, you can use the "Ctrl + Enter"
// shortcut.
#### [Часть 1: Проект Kotlin Multiplatform](#1-Проект-kotlin-multiplatform)
// This code is editable, feel free to hack it!
// You can always return to the original code by clicking the "Reset" button ->
Подготовка библиотеки Multiplatform с общей бизнес логикой проекта.
// This is the main function.
fn main() {
// Statements here are executed when the compiled binary is called.
#### [Часть 2: Проект ОС Аврора](#2-Проект-ОС-Аврора)
// Print text to the console.
println!("Hello World!");
Подготовка приложения для ОС Аврора на Qt/Qml.
#### [Часть 3: Объединение проектов](#3-Объединение-проектов)
Добавление QtBindings в библиотеку Multiplatform и интеграция с приложением ОС Аврора.
#### [Часть 4: Выполнение метода](#4-Выполнение-метода)
Выполнение синхронного метода из библиотеки Multiplatform с использованием QtBindings.
#### [Часть 5: Использование Coroutines](#5-Использование-coroutines)
Использование QtBindings для выполнения [suspend](https://kotlinlang.org/docs/composing-suspending-functions.html) функций.
### 1. Проект Kotlin Multiplatform
Проект будет содержать типичную библиотеку Multiplatform с целями сборки `linuxX64` и `linuxArm64`.
Самый простой способ ее создать - воспользоваться сайтом [Kotlin Multiplatform Wizard](https://kmp.jetbrains.com/).
Необходимый шаблон библиотеки называется **Multiplatform Library**:
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw1.png"/>
</p>
Скачав его, вы увидите все доступные платформы, но для проекта ОС Аврора необходимо оставить только цель `linuxX64Main`.
Все лишнее можно удалить.
После правок проект должен выглядеть так:
```shell
.
├── build.gradle.kts
├── .gitignore
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── library
│   ├── build.gradle.kts
│   └── src
│   ├── commonMain
│   │   └── kotlin
│   │   └── CustomFibi.kt
│   └── linuxX64Main
│   └── kotlin
│   └── fibiprops.linuxX64.kt
├── README.md
└── settings.gradle.kts
9 directories, 13 files
```
Название библиотеки будет часто фигурировать в проекте ,
для удобства название библиотеки можно поместить в `library/gradle.properties`:
```properties
#Library
libName=demo_kmp
```
На данный момент в шаблоне есть цель `linuxX64`, для поддержки архитектуры `aarch64` необходимо добавить цель `linuxArm64`.
В названия целей можно обозначить задачу создания библиотеки Multiplatform для ОС Аврора.
```kotlin
plugins {
alias(libs.plugins.kotlinMultiplatform)
}
group = "ru.auroraos.demo"
version = "0.0.1"
kotlin {
linuxX64("auroraX64") {
binaries {
staticLib {
baseName = findProperty("libName").toString()
}
}
}
linuxArm64("auroraArm64") {
binaries {
staticLib {
baseName = findProperty("libName").toString()
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
//put your multiplatform dependencies here
}
}
}
}
```
Необходимо создать директории `auroraArm64Main` и `auroraX64Main` из существующей в шаблоне `linuxX64Main`.
Обратите название на директории и названия файлов в них.
После правок целей структура проекта должна выглядеть так:
```shell
.
├── build.gradle.kts
├── .gitignore
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── library
│   ├── build.gradle.kts
│   └── src
│   ├── auroraArm64Main
│   │   └── kotlin
│   │   └── fibiprops.auroraArm64.kt
│   ├── auroraX64Main
│   │   └── kotlin
│   │   └── fibiprops.auroraX64.kt
│   └── commonMain
│   └── kotlin
│   └── CustomFibi.kt
├── README.md
└── settings.gradle.kts
11 directories, 14 files
```
После правок можно собрать проект, убедившись что все правки внесены верно:
```shell
./gradlew linkReleaseStaticAuroraX64 # linkReleaseStaticAuroraArm64
```
В конце лога сборки должно быть выведено сообщение: `BUILD SUCCESSFUL`.
Шаблон под разработку библиотеки с бизнес-логикой приложения для ОС Аврора готов.
Позже добавим все необходимое для того, чтобы выполнять функции из библиотеки в приложении ОС Аврора.
Но сначала создадим приложение для ОС Аврора.
### 2. Проект ОС Аврора
Аврора IDE позволяет создавать приложение из доступных шаблонов.
Для этого необходимо открыть Aurora IDE, нажать `New` в разделе `Welcome` -> `Projects`.
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw2.png"/>
</p>
После конфигурации проекта структура проекта должна выглядеть:
```shell
.
├── icons
│   ├── 108x108
│   │   └── ru.auroraos.demo_kmp.png
│   ├── 128x128
│   │   └── ru.auroraos.demo_kmp.png
│   ├── 172x172
│   │   └── ru.auroraos.demo_kmp.png
│   └── 86x86
│   └── ru.auroraos.demo_kmp.png
├── qml
│   ├── cover
│   │   └── DefaultCoverPage.qml
│   ├── demo_kmp.qml
│   ├── icons
│   │   └── demo_kmp.svg
│   └── pages
│   ├── AboutPage.qml
│   └── MainPage.qml
├── rpm
│   └── ru.auroraos.demo_kmp.spec
├── ru.auroraos.demo_kmp.desktop
├── ru.auroraos.demo_kmp.pro
├── src
│   └── main.cpp
└── translations
├── ru.auroraos.demo_kmp-ru.ts
└── ru.auroraos.demo_kmp.ts
13 directories, 15 files
```
Попробуем собрать проект, нажав 🔨 (слева в низу).
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw3.png"/>
</p>
Если проект собрался без ошибок, можно заняться объединением проектов.
### 3. Объединение проектов
#### Подготовка библиотеки Multiplatform
Основным фреймворком разработки приложений для ОС Аврора является `Qt/Qml`.
Kotlin Multiplatform для целей Linux позволяет собрать библиотеку которую можно использовать в `Qt`.
Библиотека содержит большой низкоуровневый C хедер, с которым сложно работать напрямую.
Для простоты взаимодействия с С-библиотекой, собранной средствами Kotlin Multiplatform,
был разработан плагин **QtBindings**, позволяющий автоматически сгенерировать Qt привязки, для Multiplatform библиотеки.
Плагин необходимо подключить к проекту.
> Как создать локальный maven репозиторий смотрите [здесь](./start.md).
В файле `gradle/libs.versions.toml` добавим плагин **QtBindings** и [KSP](https://kotlinlang.org/docs/ksp-overview.html), необходимый для генерации привязок:
```toml
[versions]
kotlin = "2.1.10"
qtbindings = "0.1.0"
devtoolsKsp = "2.1.10-1.0.31"
[plugins]
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
qtBindings = { id = "ru.aurora.kmp.qtbindings", version.ref = "qtbindings" }
devtoolsKsp = { id = "com.google.devtools.ksp", version.ref = "devtoolsKsp" }
```
Добавим плагины в `build.gradle.kts`:
```kotlin
plugins {
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.qtBindings) apply false
alias(libs.plugins.devtoolsKsp) apply false
}
```
Добавим плагины в `library/build.gradle.kts`:
```kotlin
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.qtBindings)
alias(libs.plugins.devtoolsKsp)
}
```
Плагину **QtBindings** необходимо указать название библиотеки:
```kotlin
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.qtBindings)
alias(libs.plugins.devtoolsKsp)
}
qtBindings {
libName = findProperty("libName").toString()
}
```
**Аннотация @QtExport**
В демонстрационной функции шаблона библиотеки используется `sequence`:
```kotlin
fun generateFibi() = sequence {
var a = firstElement
yield(a)
var b = secondElement
yield(b)
while (true) {
val c = a + b
yield(c)
a = b
b = c
}
}
```
Этот функционал на данный момент не поддерживается,
можно добавить промежуточную функцию `generateFibiWrapper` и включить ее экспорт в привязки:
```kotlin
import ru.aurora.kmp.qtbindings.QtExport
@QtExport
fun generateFibiWrapper(take: Int): List<Int> {
return generateFibi().take(take).toList()
}
```
> Более подробно с информацией о поддержке можно ознакомиться [здесь](@todo).
Все необходимое для генерации привязок в наличии, запустим сборку библиотеки Multiplatform:
```shell
./gradlew linkReleaseStaticAuroraX64 # linkReleaseStaticAuroraArm64
```
После добавления **QtBindings** и сборки будут созданы привязки, которые можно добавить к проекту для ОС Аврора:
- `library/build/generated/ksp/auroraArm64/auroraArm64Main/resources/*`
- `library/build/generated/ksp/auroraX64/auroraX64Main/resources/*`
```shell
.
├── io
│   └── github
│   └── kotlin
│   └── fibonacci
│   ├── CustomFibi.cpp
│   └── CustomFibi.hpp
└── ru
└── aurora
└── kmp
└── qtbindings
├── CallbackContext.cpp
├── CallbackContext.hpp
├── CoroutineException.cpp
├── CoroutineException.hpp
├── CoroutineLauncher.cpp
├── CoroutineLauncher.hpp
├── CoroutineOperation.hpp
└── cruntime.h
9 directories, 10 files
```
#### Подготовка приложения ОС Аврора
Привязки - это файлы C++ `*.hpp` и `*.cpp`.
Их можно добавить напрямую в проект, но удобнее отделить их от основного проекта.
Для этого в проекте можно сделать субдиректорию.
В корне проекта ОС Аврора:
1. Создать директорию `ru.auroraos.demo_kmp` - для основного приложения.
2. Создать директорию `kmp.bindings` - директория для сгенерированных Qt привязок.
3. Создать директорию `kmp.libs` - директория для C библиотек Kotlin Multiplatform.
Далее необходимо перенести основной проект ОС Аврора в директорию `ru.auroraos.demo_kmp`.
Структура проекта ОС Аврора примет следующий вид:
```shell
.
├── kmp.bindings
├── kmp.libs
├── rpm
│   └── ru.auroraos.demo_kmp.spec
└── ru.auroraos.demo_kmp
├── icons
│   ├── 108x108
│   │   └── ru.auroraos.demo_kmp.png
│   ├── 128x128
│   │   └── ru.auroraos.demo_kmp.png
│   ├── 172x172
│   │   └── ru.auroraos.demo_kmp.png
│   └── 86x86
│   └── ru.auroraos.demo_kmp.png
├── qml
│   ├── cover
│   │   └── DefaultCoverPage.qml
│   ├── demo_kmp.qml
│   ├── icons
│   │   └── demo_kmp.svg
│   └── pages
│   ├── AboutPage.qml
│   └── MainPage.qml
├── ru.auroraos.demo_kmp.desktop
├── ru.auroraos.demo_kmp.pro
├── src
│   └── main.cpp
└── translations
├── ru.auroraos.demo_kmp-ru.ts
└── ru.auroraos.demo_kmp.ts
16 directories, 16 files
```
В корень проекта ОС Аврора необходимо добавить файл `demo_kmp.pro` со следующим содержимым:
```pro
TEMPLATE = subdirs
OTHER_FILES += $$files(rpm/*)
SUBDIRS += \
kmp.bindings \
ru.auroraos.demo_kmp \
ru.auroraos.demo_kmp.depends = kmp.bindings
CONFIG += ordered
```
Затем в Аврора IDE можно открыть файл `demo_kmp.pro` и указать необходимые цели сборки:
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw4.png"/>
</p>
#### Объединение проектов
После модификации библиотеки Multiplatform требуется ее пересобрать.
Это изменит привязки, хедер библиотеки и саму библиотеку.
Для того, чтобы не переносить изменения самостоятельно, это можно автоматизировать через Gradle задачи.
Чтобы получить относительные пути копирования необходимых файлов,
можно совместить проект библиотеки Multiplatform и приложения для ОС Аврора:
```shell
.
├── auroraApp
│   ├── demo_kmp.pro
│   ├── kmp.bindings
│   ├── kmp.libs
│   ├── rpm
│   │   └── ru.auroraos.demo_kmp.spec
│   └── ru.auroraos.demo_kmp
│   ├── icons
│   │   ├── 108x108
│   │   │   └── ru.auroraos.demo_kmp.png
│   │   ├── 128x128
│   │   │   └── ru.auroraos.demo_kmp.png
│   │   ├── 172x172
│   │   │   └── ru.auroraos.demo_kmp.png
│   │   └── 86x86
│   │   └── ru.auroraos.demo_kmp.png
│   ├── qml
│   │   ├── cover
│   │   │   └── DefaultCoverPage.qml
│   │   ├── demo_kmp.qml
│   │   ├── icons
│   │   │   └── demo_kmp.svg
│   │   └── pages
│   │   ├── AboutPage.qml
│   │   └── MainPage.qml
│   ├── ru.auroraos.demo_kmp.desktop
│   ├── ru.auroraos.demo_kmp.pro
│   ├── src
│   │   └── main.cpp
│   └── translations
│   ├── ru.auroraos.demo_kmp-ru.ts
│   └── ru.auroraos.demo_kmp.ts
└── library
├── build.gradle.kts
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── library
│   ├── build.gradle.kts
│   └── src
│   ├── auroraArm64Main
│   │   └── kotlin
│   │   └── fibiprops.auroraArm64.kt
│   ├── auroraX64Main
│   │   └── kotlin
│   │   └── fibiprops.auroraX64.kt
│   └── commonMain
│   └── kotlin
│   └── CustomFibi.kt
├── README.md
└── settings.gradle.kts
28 directories, 28 files
```
#### Добавление задач Gradle
Для автоматизации процесса обновления привязок и библиотеки в библиотеке Multiplatform
зарегистрируем задачу. Эта задача выполнит следующее.
1. Соберет статические C библиотеки для архитектур: x86_64 и aarch64.
2. Скопирует собранные библиотеки в проект ОС Аврора.
3. Скопирует привязки QtBindings в проект ОС Аврора.
4. Создаст pro файл для компиляции Qt привязок в приложении ОС Аврора.
5. Выведет информацию по подключению библиотек к приложению ОС Аврора.
```kotlin
interface Injected {
@get:Inject val fs: FileSystemOperations
@get:Inject val layout: ProjectLayout
@get:Inject val objects: ObjectFactory
}
tasks.register("buildAuroraLibs") {
// Injected
val libName = findProperty("libName").toString()
val injected = project.objects.newInstance<Injected>()
// Task depends
dependsOn("linkReleaseStaticAuroraX64", "linkReleaseStaticAuroraArm64")
// Copy kmp lib x64
doLast {
injected.fs.delete {
delete("${injected.layout.projectDirectory}/../../auroraApp/kmp.libs/x64")
}
injected.fs.copy {
from(injected.layout.buildDirectory.dir("bin/auroraX64/releaseStatic")) { include("**/*.a", "**/*.h") }
into("${injected.layout.projectDirectory}/../../auroraApp/kmp.libs/x64")
}
}
// Copy kmp lib arm64
doLast {
injected.fs.delete {
delete("${injected.layout.projectDirectory}/../../auroraApp/kmp.libs/arm64")
}
injected.fs.copy {
from(injected.layout.buildDirectory.dir("bin/auroraArm64/releaseStatic")) { include("**/*.a", "**/*.h") }
into("${injected.layout.projectDirectory}/../../auroraApp/kmp.libs/arm64")
}
}
// Copy kmp bindings
// The target is not important where we will get the bindings from
doLast {
injected.fs.delete {
delete("${injected.layout.projectDirectory}/../../auroraApp/kmp.bindings")
}
injected.fs.copy {
from(injected.layout.buildDirectory.dir("generated/ksp/auroraX64/auroraX64Main/resources"))
into("${injected.layout.projectDirectory}/../../auroraApp/kmp.bindings")
}
}
// Gen pro bindings
doLast {
val search = injected.layout.buildDirectory.dir("generated/ksp/auroraX64/auroraX64Main/resources")
val headers = mutableListOf<String>()
val sources = mutableListOf<String>()
val includes = mutableListOf<String>()
injected.objects.fileTree().from(search).forEach {
when {
it.path.endsWith(".h") || it.path.endsWith(".hpp") -> {
headers.add(it.path.replace("${search.get().asFile}/", ""))
}
it.path.endsWith(".cpp") -> {
sources.add(it.path.replace("${search.get().asFile}/", ""))
}
}
}
headers.forEach {
includes.add(it.replaceAfterLast("/", ""))
}
val file = File("${injected.layout.projectDirectory}/../../auroraApp/kmp.bindings/kmp.bindings.pro")
file.writeText("""
|TEMPLATE = lib
|TARGET = kmpbindings
|CONFIG += staticlib warn_off
|
|HEADERS += \
|${headers.joinToString("\n") { " $it \\" }}
|
|SOURCES += \
|${sources.joinToString("\n") { " $it \\" }}
|
|contains(QMAKE_HOST.arch, armv7l): {
| error("Unsupported architecture armv7l")
|}
|contains(QMAKE_HOST.arch, x86_64): {
| LIB_DEMO_KMP=kmp.libs/x64
|}
|contains(QMAKE_HOST.arch, aarch64): {
| LIB_DEMO_KMP=kmp.libs/arm64
|}
|
|INCLUDEPATH += $${'$'}PWD/../${'$'}${'$'}{LIB_DEMO_KMP}
|${includes.distinct().joinToString("\n") { "INCLUDEPATH += $${'$'}PWD/$it" }}
""".trimMargin())
file.createNewFile()
// Print what needs to be added to the pro file of the application
println("""
|Check your application pro file:
|################################
|# kmp.targets
|contains(QMAKE_HOST.arch, armv7l): {
| error("Unsupported architecture armv7l")
|}
|contains(QMAKE_HOST.arch, x86_64): {
| LIB_DEMO_KMP=kmp.libs/x64
|}
|contains(QMAKE_HOST.arch, aarch64): {
| LIB_DEMO_KMP=kmp.libs/arm64
|}
|
|# kmp.bindings
|${includes.distinct().joinToString("\n") { "INCLUDEPATH += $${'$'}PWD/../kmp.bindings/$it" }}
|LIBS += -L${'$'}${'$'}OUT_PWD/../kmp.bindings -lkmpbindings
|
|# kmp.libs
|INCLUDEPATH += ${'$'}${'$'}PWD/../${'$'}${'$'}{LIB_DEMO_KMP}
|LIBS += -L${'$'}${'$'}PWD/../${'$'}${'$'}{LIB_DEMO_KMP} -l${libName}
|################################
""".trimMargin())
}
}
```
> В задаче `buildAuroraLibs` привязки копируются с учетом их идентичности для целей, но это может быть не так.
> Если в вашем приложении они отличаются, следует доработать задачу, согласно вашей логике.
Вывод задачи Gradle:
```
# kmp.targets
contains(QMAKE_HOST.arch, armv7l): {
error("Unsupported architecture armv7l")
}
contains(QMAKE_HOST.arch, x86_64): {
LIB_DEMO_KMP=kmp.libs/x64
}
contains(QMAKE_HOST.arch, aarch64): {
LIB_DEMO_KMP=kmp.libs/arm64
}
# kmp.bindings
INCLUDEPATH += $$PWD/../kmp.bindings/ru/aurora/kmp/qtbindings/
INCLUDEPATH += $$PWD/../kmp.bindings/io/github/kotlin/fibonacci/
LIBS += -L$$OUT_PWD/../kmp.bindings -lkmpbindings
# kmp.libs
INCLUDEPATH += $$PWD/../$${LIB_DEMO_KMP}
LIBS += -L$$PWD/../$${LIB_DEMO_KMP} -ldemo_kmp
```
Вывод из Gradle следует добавит в конец файла `auroraApp/ru.auroraos.demo_kmp/ru.auroraos.demo_kmp.pro` проекта ОС Аврора.
Теперь ОС Аврора проект можно собрать:
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw5.png"/>
</p>
### 4: Выполнение метода
На данный момент, проект содержит:
1. Библиотеку Multiplatform.
2. Приложение Qt/Qml для ОС Аврора.
3. Задачу buildAuroraLibs, автоматизирующий процесс синхронизации.
4. Статическую библиотеку с привязками, интегрированную с приложением.
Теперь есть возможность выполнить метод `generateFibiWrapper`, добавленный в привязки аннотацией `@QtExport`.
Метод помещен в namespace соответственно пакету:
```cpp
namespace io {
namespace github {
namespace kotlin {
namespace fibonacci {
QList<int> generateFibiWrapper();
} /* namespace fibonacci */
} /* namespace kotlin */
} /* namespace github */
} /* namespace io */
```
В шаблоне приложения ОС Аврора можно найти функцию `main`,
в ней можно проверить работоспособность привязок и библиотеки Multiplatform:
```cpp
#include <auroraapp.h>
#include <QtQuick>
#include <QDebug>
#include "CustomFibi.hpp"
int main(int argc, char *argv[])
{
// Run from library Multiplatform
qDebug() << io::github::kotlin::fibonacci::generateFibiWrapper(5);
// Qt/Qml application
QScopedPointer<QGuiApplication> application(Aurora::Application::application(argc, argv));
application->setOrganizationName(QStringLiteral("ru.auroraos"));
application->setApplicationName(QStringLiteral("demo_kmp"));
QScopedPointer<QQuickView> view(Aurora::Application::createView());
view->setSource(Aurora::Application::pathTo(QStringLiteral("qml/demo_kmp.qml")));
view->show();
return application->exec();
}
```
После запуска приложения в логах можно наблюдать выполнение функции `generateFibiWrapper` привязок **QtBindings** из библиотеки Multiplatform:
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw6.png"/>
</p>
### 5: Использование Coroutines
**QtBindings** позволяет работать с [Kotlin Coroutines](https://kotlinlang.org/docs/coroutines-overview.html) через Qt:
- Ожидать завершение `suspend` функции;
- Отменить при необходимости;
- Получать исключения.
В библиотеке Multiplatform есть синхронная функция `generateFibiWrapper`, которая была вызвана ранее.
Для демонстрации работы с асинхронными функциями давайте добавим `suspend` функцию:
```kotlin
@QtExport
suspend fun generateFibiWrapperAsync(take: Int): List<Int> {
delay(5000L)
return generateFibi().take(take).toList()
}
```
**QtBindings** из `suspend` функции создаст [QFuture](https://doc.qt.io/archives/qt-5.6/qfuture.html),
который можно использовать с [QFutureWatcher](https://doc.qt.io/archives/qt-5.6/qfuture.html),
что позволит использовать весь основной функционал [Coroutines](https://kotlinlang.org/docs/coroutines-overview.html).
Вызвать функцию из Qt можно так:
```cpp
auto fibiWrapperAsync = new QFutureWatcher<QList<int>>();
auto feature = io::github::kotlin::fibonacci::generateFibiWrapperAsync(5);
fibiWrapperAsync->setFuture(feature);
QObject::connect(fibiWrapperAsync, &QFutureWatcher<QList<int>>::finished, [=]() {
qDebug() << fibiWrapperAsync->result();
fibiWrapperAsync->deleteLater();
});
```
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw7.png"/>
</p>
**QtBindings** позволяет завершать запросы и получать исключения из `suspend` функций.
Добавим метод, на котором можно это проверить:
```kotlin
@QtExport
suspend fun testCatchAsync(isError: Boolean): Boolean {
delay(5000L)
if (isError) {
throw RuntimeException("My custom error")
}
return true
}
```
Вызовем функцию и остановим при получении сигнала отмены:
```cpp
auto testCatchAsyncCancel = new QFutureWatcher<bool>();
auto featureCancel = io::github::kotlin::fibonacci::testCatchAsync(false);
testCatchAsyncCancel->setFuture(featureCancel);
QObject::connect(testCatchAsyncCancel, &QFutureWatcher<bool>::canceled, [=]() {
qDebug() << "testCatchAsyncCancel - canceled";
});
// Отмена
testCatchAsyncCancel->cancel();
```
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw8.png"/>
</p>
Для перехвата ошибки в функции `testCatchAsync` укажем параметр `isError`, как `true`, и воспользуемся `try/catch`:
```cpp
auto testCatchAsyncError = new QFutureWatcher<bool>();
auto featureError = io::github::kotlin::fibonacci::testCatchAsync(true);
testCatchAsyncError->setFuture(featureError);
QObject::connect(testCatchAsyncError, &QFutureWatcher<bool>::canceled, [=]() {
try {
auto value = testCatchAsyncError->result();
qDebug() << value;
} catch (Aurora::Kmp::QtBindings::CoroutineException& ex) {
qDebug() << ex.message();
}
});
```
<p>
<img class="preview2" src="/assets/images/qt_bindings/hw9.png"/>
</p>
#### Заключение
QtBindings позволяют взаимодействовать с библиотекой Multiplatform нативными средствами Qt.
Добавление привязок не сложнее, чем на других платформах.
Это серьезно упрощает разработку приложений без необходимости погружаться в низкоуровневую логику С-библиотеки.
Развитие поддержки Kotlin Multiplatform в ОС Аврора только начинается,
но уже можно писать приложения с использованием целей `linuxX64` и `linuxArm64` на ОС Аврора!
**Демонстрационный проект доступен [GitLab](@todo).**
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать