Создание и публикация многоплатформенной библиотеки — учебник
В этом учебнике вы узнаете, как создать многоплатформенную библиотеку для JVM, JS и нативных платформ, написать общие тесты для всех платформ и опубликовать библиотеку в локальном репозитории Maven.
Эта библиотека преобразует исходные данные — строки и массивы байтов — в формат Base64. Она может быть использована на Kotlin/JVM, Kotlin/JS и любой доступной платформе Kotlin/Native.
Вы будете использовать различные способы реализации преобразования в формат Base64 на разных платформах:
Для JVM — класс
java.util.Base64.Для JS — функция
btoa().Для Kotlin/Native — ваша собственная реализация.
Вы также протестируете свой код с помощью общих тестов и затем опубликуете библиотеку в вашем локальном репозитории Maven.
Настройка среды
Вы можете выполнить этот учебник на любой операционной системе. Скачайте и установите последнюю версию IntelliJ IDEA с последним плагином Kotlin.
Создание проекта
В IntelliJ IDEA выберите Файл | Новый | Проект.
В левой панели выберите Kotlin Multiplatform.
-
Введите имя проекта, затем в разделе Многоплатформенный выберите Библиотека в качестве шаблона проекта.

Выберите DSL Gradle – Kotlin или Groovy.
Укажите JDK, который необходим для разработки проектов Kotlin.
Нажмите Далее, а затем Готово.
- Дополнительная настройка проекта
-
Для более сложных проектов, возможно, потребуется добавить больше модулей и целей:
Для добавления модулей выберите Проект и нажмите на значок +. Выберите тип модуля.
Для добавления целевых платформ выберите библиотеку и нажмите на значок +. Выберите целевую платформу.
-
Настройте параметры целевой платформы, такие как версия целевой JVM и фреймворк для тестирования.
-
При необходимости укажите зависимости между модулями:
Многоплатформенные и Android модули
Многоплатформенные и iOS модули
Модули JVM

Мастер создаст пример многоплатформенной библиотеки со следующей структурой:
Написание кроссплатформенного кода
Определите классы и интерфейсы, которые вы собираетесь реализовать в общем коде.
В директории
commonMain/kotlinсоздайте пакетorg.jetbrains.base64.Создайте файл
Base64.ktв новом пакете.-
Определите интерфейс
Base64Encoder, который преобразует байты в форматBase64:package org.jetbrains.base64 interface Base64Encoder { fun encode(src: ByteArray): ByteArray } -
Определите объект
Base64Factoryдля предоставления экземпляра интерфейсаBase64Encoderобщему коду:expect object Base64Factory { fun createEncoder(): Base64Encoder }
Объект-фабрика помечен ключевым словом expect в кроссплатформенном коде. Для каждой платформы вы должны предоставить реализацию actual объекта Base64Factory с платформоспецифическим кодером. Подробнее о платформоспецифических реализациях.
Предоставление платформоспецифических реализаций
Теперь вы создадите платформоспецифические реализации объекта actual для каждой платформы:
JVM
В директории
jvmMain/kotlinсоздайте пакетorg.jetbrains.base64.Создайте файл
Base64.ktв новом пакете.-
Предоставьте простую реализацию объекта
Base64Factory, которая делегирует классуjava.util.Base64:package org.jetbrains.base64 import java.util.* actual object Base64Factory { actual fun createEncoder(): Base64Encoder = JvmBase64Encoder } object JvmBase64Encoder : Base64Encoder { override fun encode(src: ByteArray): ByteArray = Base64.getEncoder().encode(src) }
Достаточно просто, не так ли? Вы предоставили платформоспецифическую реализацию, используя прямое делегирование сторонней реализации.
JS
Реализация JS будет очень похожа на JVM.
В директории
jsMain/kotlinсоздайте пакетorg.jetbrains.base64.Создайте файл
Base64.ktв новом пакете.-
Предоставьте простую реализацию объекта
Base64Factory, которая делегирует функцииbtoa().package org.jetbrains.base64 import kotlinx.browser.window actual object Base64Factory { actual fun createEncoder(): Base64Encoder = JsBase64Encoder } object JsBase64Encoder : Base64Encoder { override fun encode(src: ByteArray): ByteArray { val string = src.decodeToString() val encodedString = window.btoa(string) return encodedString.encodeToByteArray() } }
Native
К сожалению, для всех целей Kotlin/Native нет сторонней реализации, поэтому вам нужно написать её самостоятельно.
В директории
nativeMain/kotlinсоздайте пакетorg.jetbrains.base64.Создайте файл
Base64.ktв новом пакете.-
Предоставьте свою собственную реализацию для объекта
Base64Factory:package org.jetbrains.base64 private val BASE64_ALPHABET: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" private val BASE64_MASK: Byte = 0x3f private val BASE64_PAD: Char = '=' private val BASE64_INVERSE_ALPHABET = IntArray(256) { BASE64_ALPHABET.indexOf(it.toChar()) } private fun Int.toBase64(): Char = BASE64_ALPHABET[this] actual object Base64Factory { actual fun createEncoder(): Base64Encoder = NativeBase64Encoder } object NativeBase64Encoder : Base64Encoder { override fun encode(src: ByteArray): ByteArray { fun ByteArray.getOrZero(index: Int): Int = if (index >= size) 0 else get(index).toInt() // 4n / 3 is expected Base64 payload val result = ArrayList<Byte>(4 * src.size / 3) var index = 0 while (index < src.size) { val symbolsLeft = src.size - index val padSize = if (symbolsLeft >= 3) 0 else (3 - symbolsLeft) * 8 / 6 val chunk = (src.getOrZero(index) shl 16) or (src.getOrZero(index + 1) shl 8) or src.getOrZero(index + 2) index += 3 for (i in 3 downTo padSize) { val char = (chunk shr (6 * i)) and BASE64_MASK.toInt() result.add(char.toBase64().code.toByte()) } // Fill the pad with '=' repeat(padSize) { result.add(BASE64_PAD.code.toByte()) } } return result.toByteArray() } }
Тестирование вашей библиотеки
Теперь, когда у вас есть actual реализации объекта Base64Factory для всех платформ, пришло время протестировать вашу кроссплатформенную библиотеку.
Чтобы сэкономить время на тестировании, вы можете написать общие тесты, которые будут выполняться на всех платформах вместо тестирования каждой платформы по отдельности.
Предварительные условия
Перед написанием тестов добавьте метод encodeToString с реализацией по умолчанию в интерфейс Base64Encoder, который определён в commonMain/kotlin/org/jetbrains/base64/Base64.kt. Эта реализация преобразует массивы байтов в строки, что гораздо проще тестировать.
interface Base64Encoder {
fun encode(src: ByteArray): ByteArray
fun encodeToString(src: ByteArray): String {
val encoded = encode(src)
return buildString(encoded.size) {
encoded.forEach { append(it.toInt().toChar()) }
}
}
}
Вы также можете предоставить более эффективную реализацию этого метода для определённой платформы, например, для JVM в jvmMain/kotlin/org/jetbrains/base64/Base64.kt:
object JvmBase64Encoder : Base64Encoder {
override fun encode(src: ByteArray): ByteArray = Base64.getEncoder().encode(src)
override fun encodeToString(src: ByteArray): String = Base64.getEncoder().encodeToString(src)
}
Одним из преимуществ кроссплатформенной библиотеки является наличие реализации по умолчанию с опциональными платформенно-специфичными переопределениями.
Написание общих тестов
Теперь у вас есть API, основанный на строках, который можно покрыть базовыми тестами.
В каталоге
commonTest/kotlinсоздайте пакетorg.jetbrains.base64.Создайте файл
Base64Test.ktв новом пакете.-
Добавьте тесты в этот файл:
package org.jetbrains.base64 import kotlin.test.Test import kotlin.test.assertEquals class Base64Test { @Test fun testEncodeToString() { checkEncodeToString("Kotlin is awesome", "S290bGluIGlzIGF3ZXNvbWU=") } @Test fun testPaddedStrings() { checkEncodeToString("", "") checkEncodeToString("1", "MQ==") checkEncodeToString("22", "MjI=") checkEncodeToString("333", "MzMz") checkEncodeToString("4444", "NDQ0NA==") } private fun checkEncodeToString(input: String, expectedOutput: String) { assertEquals(expectedOutput, Base64Factory.createEncoder().encodeToString(input.asciiToByteArray())) } private fun String.asciiToByteArray() = ByteArray(length) { get(it).code.toByte() } } -
В терминале выполните задачу Gradle
check:./gradlew check
Тесты будут выполняться на всех платформах (JVM, JS и Native).
Добавление платформенно-специфичных тестов
Вы также можете добавить тесты, которые будут выполняться только для определённой платформы. Например, вы можете добавить тесты UTF-16 на JVM:
В каталоге
jvmTest/kotlinсоздайте пакетorg.jetbrains.base64.Создайте файл
Base64Test.ktв новом пакете.-
Добавьте тесты в этот файл:
package org.jetbrains.base64 import kotlin.test.Test import kotlin.test.assertEquals class Base64JvmTest { @Test fun testNonAsciiString() { val utf8String = "Gödel" val actual = Base64Factory.createEncoder().encodeToString(utf8String.toByteArray()) assertEquals("R8O2ZGVs", actual) } }
Этот тест будет автоматически выполняться на платформе JVM помимо общих тестов.
Опубликовать библиотеку в локальный репозиторий Maven
Ваша кроссплатформенная библиотека готова к публикации, чтобы вы могли использовать её в других проектах.
Для публикации библиотеки используйте плагин Gradle maven-publish.
-
В файле
build.gradle(.kts)примените плагинmaven-publishи укажите группу и версию вашей библиотеки:plugins { kotlin("multiplatform") version "1.7.20" id("maven-publish") } group = "org.jetbrains.base64" version = "1.0.0"plugins { id 'org.jetbrains.kotlin.multiplatform' version '1.7.20' id 'maven-publish' } group = 'org.jetbrains.base64' version = '1.0.0' -
В терминале запустите задачу Gradle
publishToMavenLocal, чтобы опубликовать вашу библиотеку в локальный репозиторий Maven:./gradlew publishToMavenLocal
Ваша библиотека будет опубликована в локальном репозитории Maven.
Добавление зависимости на опубликованную библиотеку
Теперь вы можете добавить вашу библиотеку в другие кроссплатформенные проекты в качестве зависимости.
Добавьте репозиторий mavenLocal() и добавьте зависимость от вашей библиотеки в файл build.gradle(.kts).
repositories {
mavenCentral()
mavenLocal()
}
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.base64:multiplatform-lib:1.0.0")
}
}
}
}
repositories {
mavenCentral()
mavenLocal()
}
kotlin {
sourceSets {
commonMain {
dependencies {
implementation 'org.jetbrains.base64:multiplatform-lib:1.0.0'
}
}
}
}
Зависимость implementation состоит из:
Идентификатора группы и версии — указанных ранее в файле
build.gradle(.kts)Идентификатора артефакта — по умолчанию это имя вашего проекта, указанное в файле
settings.gradle(.kts)
Для получения более подробной информации см. документацию Gradle по плагину maven-publish.
Что дальше?
© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform-library.html