Как добавить код, специфичный для macOS, в Kotlin Compose Multi Platform?

Вопрос или проблема

Я хочу написать код, специфичный для macOS, такой как разрешение на использование Bluetooth или другой низкоуровневый код, который очень специфичен для macOS и должен быть написан на Objective C или Swift. Создание проекта KMM с помощью мастера проектов создает иерархию проекта следующего вида:

  • commonMain
  • androidMain
  • desktopMain

Как создать папку macos main и редактировать код, специфичный для macOS? Могу ли я сам создать пакет main для macOS или какие правильные конфигурации я должен сделать в своем gradle коде?

Мой текущий файл gradle выглядит следующим образом:

import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
    alias(libs.plugins.kotlinMultiplatform)
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.composeMultiplatform)
    alias(libs.plugins.composeCompiler)
}

kotlin {
    androidTarget {
        @OptIn(ExperimentalKotlinGradlePluginApi::class)
        compilerOptions {
            jvmTarget.set(JvmTarget.JVM_11)
        }
    }
    
    jvm("desktop")
    macosArm64()
    applyDefaultHierarchyTemplate()

    sourceSets {
        val desktopMain by getting
        
        androidMain.dependencies {
            implementation(compose.preview)
            implementation(libs.androidx.activity.compose)
        }
        commonMain.dependencies {
            implementation(compose.runtime)
            implementation(compose.foundation)
            implementation(compose.material)
            implementation(compose.ui)
            implementation(compose.components.resources)
            implementation(compose.components.uiToolingPreview)
            implementation(libs.androidx.lifecycle.viewmodel)
            implementation(libs.androidx.lifecycle.runtime.compose)
        }
        desktopMain.dependencies {
            implementation(compose.desktop.currentOs)
            implementation(libs.kotlinx.coroutines.swing)
        }
        val jvmAndMacos by creating {
            dependsOn(commonMain.get())
        }

        macosArm64Main.get().dependsOn(jvmAndMacos)
        jvmMain.get().dependsOn(jvmAndMacos)
    }
}

android {
    namespace = "com.shekhar.multiplatformapp"
    compileSdk = libs.versions.android.compileSdk.get().toInt()

    defaultConfig {
        applicationId = "com.shekhar.multiplatformapp"
        minSdk = libs.versions.android.minSdk.get().toInt()
        targetSdk = libs.versions.android.targetSdk.get().toInt()
        versionCode = 1
        versionName = "1.0"
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
}

dependencies {
    debugImplementation(compose.uiTooling)
}

compose.desktop {
    application {
        mainClass = "com.shekhar.multiplatformapp.MainKt"

        nativeDistributions {
            targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
            packageName = "com.shekhar.multiplatformapp"
            packageVersion = "1.0.0"
        }
    }
}

Ответ или решение

Чтобы добавить код, специфичный для macOS, в проект Kotlin с использованием Compose Multiplatform (KMP), требуется правильно настроить структуру вашего проекта, чтобы учесть особенности реализации для этой операционной системы. Это может включать доступ к низкоуровневым функциональностям, таким как управление Bluetooth или другие системные вызовы, которые должны быть написаны на Swift или Objective-C.

Шаг 1: Создание структуры каталога для macOS

  1. Добавьте пакет macOS:
    В вашем проекте KMP, который вы уже настроили, создайте новый источник для macosArm64Main. Вы можете сделать это вручную, если соответствующий источник еще не создан и не организован автоматически.

    Создайте структуру каталогов следующим образом:

    - src
     - commonMain
     - androidMain
     - desktopMain
     - macosMain
       - kotlin
         - com
           - shekhar
             - multiplatformapp
               - MacOSSpecificCode.kt

Шаг 2: Обновление Gradle конфигурации

В вашем build.gradle.kts файле, необходимо указать, что вы добавили новый источник macosMain. Вам нужно будет обновить sourceSets, чтобы они включали macOS:

kotlin {
    androidTarget {
        ...
    }

    jvm("desktop")
    macosArm64("macos") // Обратите внимание на добавление идентификатора "macos"
    applyDefaultHierarchyTemplate()

    sourceSets {
        val desktopMain by getting
        val macosMain by getting // Получаем ссылку на макет

        androidMain.dependencies {
            ...
        }

        commonMain.dependencies {
            ...
        }

        macosMain.dependencies {
            implementation(compose.desktop.currentOs) // Убедитесь, что зависимость добавлена
            implementLibs() // И другие зависимости, специфичные для macOS
        }

        // Установите зависимости
        val jvmAndMacos by creating {
            dependsOn(commonMain.get())
        }

        macosMain.dependsOn(jvmAndMacos) // Указываем, что macosMain зависит от общего кода
        jvmMain.get().dependsOn(jvmAndMacos)
    }
}

Шаг 3: Реализация кода специфичного для macOS

Теперь вы можете приступить к написанию кода, специфичного для macOS, в каталоге macosMain. Например, чтобы запросить разрешения на Bluetooth, вы можете использовать библиотеки на Swift. Для этого вам, возможно, потребуется:

  1. Создание интерфейса: Определите общий интерфейс в commonMain, чтобы скрыть реализацию.

    interface BluetoothPermissionService {
       fun requestBluetoothPermission(): Boolean
    }
  2. Написание реализации для macOS:

    В MacOSSpecificCode.kt добавьте соответствующие реализации:

    actual class BluetoothPermissionServiceImpl : BluetoothPermissionService {
       actual fun requestBluetoothPermission(): Boolean {
           // Вызовите Swift/Objective-C код для запроса разрешений
           return requestPermissionThroughSwift()
       }
    
       private fun requestPermissionThroughSwift(): Boolean {
           // Здесь будет вызов на Swift или Objective-C
       }
    }

Заключение

Следуя этим шагам, вы сможете правильно структурировать и настроить ваш проект Kotlin Multiplatform для работы с платформо-специфическим кодом для macOS. Добавление нового модуля позволит вам интегрировать функциональность, которая не доступна через Kotlin, и обеспечивает гибкость в создании кроссплатформенных приложений. Помните о тестировании на каждой из платформ для обеспечения корректной работы функционала в условиях реального использования.

Оцените материал
Добавить комментарий

Капча загружается...