Share This
Связаться со мной
Крути в низ
Categories
//Kotlin Multiplatform Mobile (KMM): пример простого приложения

Kotlin Multiplatform Mobile (KMM): пример простого приложения

Пример простого приложения (счетчика) под обе мобильные платформы, использующего общий код на языке Kotlin.

kotlin multiplatform mobile kmm primer prostogo prilozhenija e74e268 - Kotlin Multiplatform Mobile (KMM): пример простого приложения

Если вы задумываетесь над созданием мобильного приложения одновременно под iOS и Android, знакомы с языком Kotlin и хотите попробовать что-то новенькое, то обратите внимание на Kotlin Multiplatform Mobile (KMM). Это SDK (набор инструментов для разработки программного обеспечения) разработанный компанией JetBrains (создателя языка Kotlin), недавно вышедший в публичную бету, а значит, самое время попробовать его в деле!

В этой статье мы разберем:

  • основные особенности KMM;
  • архитектуру типичного KMM-приложения;
  • приемы организации кода;
  • ресурсы для дальнейшего изучения.

Что особенного в KMM и чем он отличается от других технологий мультиплатформенной разработки?

Ядром KMM является технология Kotlin Native, позволяющая компилировать код, написанный на языке Kotlin, в платформонезависимые, нативные приложения и библиотеки.

Самое важное отличие от популярных решений для мультиплатформенной разработки, таких как React Native или Flutter, это то, что KMM предоставляет набор инструментов, позволяющий использовать общую логику для обоих приложений в виде отдельной библиотеки, написанной на языке Kotlin, которую затем можно импортировать как в Android, так и в iOS приложения (рис. 1).

kotlin multiplatform mobile kmm primer prostogo prilozhenija 0b35c4e - Kotlin Multiplatform Mobile (KMM): пример простого приложения

Рис.1. Архитектура KMM-приложения

Основные плюсы такого подхода:

  • Легко добавить в существующие нативные приложения. Достаточно просто постепенно выделять общий код в отдельную библиотеку.
  • Меньший размер приложения. Компиляция кода Kotlin Native добавляет небольшой оверхед, поэтому размер приложения обычно меньше аналогов на Flutter и React Native.
  • Большая гибкость. Вы можете использовать любые библиотеки и технологии внутри ваших iOS и Android-приложения, без необходимости написания дополнительного кода.
  • Общий код можно использовать не только в мобильных приложениях, но также и в веб-приложениях, и в серверной логике на Kotlin (рис. 2).

kotlin multiplatform mobile kmm primer prostogo prilozhenija 2e8ba18 - Kotlin Multiplatform Mobile (KMM): пример простого приложения

Рис. 2. Использование общего кода между серверной логикой, мобильными платформами и web

Но не стоит забывать и о минусах:

  • Высокий порог входа. Необходимы базовые знания разработки под iOS и Android даже для создания простого приложения.
  • Небольшое комьюнити. Так как KMM все еще находится в бете, его использует не такое большое число пользователей. Для сравнения: на момент написания статьи вопросов с тегом Flutter в Stackoverflow больше 160 тысяч, а по KMM – чуть больше тысячи.
  • Небольшое количество мультиплатформенных библиотек. Несмотря на то что стандартная библиотека языка Kotlin может быть использована в общем коде без ограничений, многие привычные библиотеки языка Kotlin используют платформозависимые вызовы Java-кода и не могут быть использованы напрямую.
  • Сложность организации общего кода. KMM не предоставляет никаких готовых решений, как организовать архитектуру приложения, чтобы увеличить процент общего кода и не усложнить процесс разработки.

Команда JetBrains активно работает над развитием комьюнити, а также улучшает плагин для Android Studio, который заметно упрощает создание и поддержку KMM приложения. А последний минус мы рассмотрим подробнее далее и разберем популярный способ организовать код приложения так, чтобы максимально следовать золотому правилу разработки – DRY (don’t repeat yourself).

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека мобильного разработчика» Интересно, перейти к каналу

Архитектура типичного KMM-приложения

Архитектура типичного мультиплатформенного приложения – это монорепозиторий, состоящий из трех модулей: Android-приложение, iOS-приложение и общая библиотека (рис. 3).

kotlin multiplatform mobile kmm primer prostogo prilozhenija 5ba84f2 - Kotlin Multiplatform Mobile (KMM): пример простого приложения

Рис. 3. Схема модулей базового KMM приложения

Проект с такой структурой можно создать с помощью официального плагина для Android Studio. Шаги по настройке подробно описаны на сайте проекта, поэтому мы не будем углубляться в него подробнее.

Теперь предстоит начать писать общий код. Но как же это сделать? Ведь часто много логики находится непосредственно в UI-компонентах, а что делать с навигацией? Здесь нам на помощь приходит архитектурный паттерн из Flutter, предложенный его создателями компанией Google в 2018. Этот паттерн называется BLoC (business-logic components) и он предлагает вынести всю бизнес-логику из UI-компонента в специальный компонент – BLoC (рис. 4).

kotlin multiplatform mobile kmm primer prostogo prilozhenija 994bc54 - Kotlin Multiplatform Mobile (KMM): пример простого приложения

Рис. 4. Визуализация иерархии BLoC‘ов

Такие bloc’и тесно связаны с определенным UI-компонентом и его жизненным циклом, они создаются и уничтожаются вместе с ним. Но bloc’и не зависят от его реализации и не содержат никакого UI, а значит, они идеальные кандидаты для помещения в общий код. Библиотеки, позволяющие легко внедрить данный подход, уже созданы и активно поддерживаются комьюнити. Самая популярная из них на GitHub – Decompose, на ней мы и остановимся чуть подробнее.

Давайте разберем пример создания BLoC’а в библиотеке Decompose

В качестве примера рассмотрим простейший счетчик, который умеет показывать текущее значение и который можно увеличивать и уменьшать на единицу.

Опишем бизнес-логику нашего компонента:

  1. Он хранит состояние – текущее значение счетчика.
  2. У него есть метод для увеличения значения на один.
  3. У него есть метод уменьшения значения на один.

Создадим Kotlin-интерфейс с этой логикой в общем модуле:

CounterComponent.kt

         data class CounterState(val count: Int)  interface CounterComponent {    val state: Value<CounterState> // (1)    fun onIncrease() // (2)    fun onDecrease() // (3) }     

Это и есть интерфейс нашего bloc’а. Value – это специальный интерфейс, который представляет библиотека Decompose для хранения состояния компонента, который интегрируется со SwiftUI и Jetpack Compose (нативными библиотеками iOS и Android для UI).

Примечание Мы используем CounterState, а не просто Int, так как из-за особенностей Kotlin Native, Value не может хранить значение примитивного типа.

Напишем реализацию для нашего bloc’а:

CounterComponent.kt

         class DefaultCounterComponent: CounterComponent {     override val state = MutableValue(CounterState(0))     override fun onIncrease() {         state.reduce { it.copy(count = it.count + 1) }     }     override fun onDecrease() {         state.reduce { it.copy(count = it.count - 1) }     } }      

MutableValue реализует интерфейс Value и также предоставляется Decompose. reduce – еще один хэлпер, который позволяет обновить текущее значение на основе предыдущего.

Теперь наш bloc готов к использованию в iOS и Android-приложениях.

Для Android-приложения создадим простой компонент на Jetpack Compose (для простоты восприятия, все модификаторы были убраны из кода):

CounterUi.kt

         @Composable fun CounterUi(counterComponent: CounterComponent) {    val state by counterComponent.state.subscribeAsState()    Column {        Text(text = "${state.count}")        Button(onClick = counterComponent::onIncrease) {            Text(text = "+")        }        Button(onClick = counterComponent::onDecrease) {            Text(text = "-")        }    } }      

subsribeAsState() – расширение, которое позволяет трансформировать Value в State, также предоставляется Decompose

Для простоты, наш счетчик – единственный компонент приложения, поэтому мы можем создать наш bloc в MainActivity

MainActivity.kt

         class MainActivity : ComponentActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)         val counterComponent = DefaultCounterComponent()         setContent {            CounterUi(counterComponent)        }    } }      

Перейдем к iOS-приложению на SwiftUI:

CounterView.swift

         import SwiftUI import shared // наша общая библиотека  struct CounterView: View {     private let component: CounterComponent     @ObservedObject    private var state: ObservableValue<CounterState>     init(_ component: CounterComponent) {        self.component = component        state = ObservableValue<CounterState>(component.state)    }     var body: some View {        HStack {            Text("(state.value.count)")            Button(action: { component.onIncrease() }) {                Text("+")            }            Button(action: { component.onDecrease() }) {                Text("-")            }        }    } }      

Код не сильно отличается от того, что был в Android: для отслеживания изменений Value используется специальный адаптер – ObservableValue, код которого можно скопировать из официального репозитория Decompose.

Создаем bloc также при инициализации приложения:

iOSApp.swift

         @main struct iOSApp: App {   var counterComponent = DefaultCounterComponent()    var body: some Scene {      WindowGroup {         CounterView(counterComponent)      }   } }      

Наше KMM приложение-счетчик готово. Вся бизнес-логика находится в общем модуле и используется совместно iOS- и Android-частями.

Код на Гитхабе Код получившегося приложения можно скачать в репозитории.

Что еще предоставляет Decompose?

В статье мы коснулись только самого базового функционала библиотеки. Кроме него, Decompose содержит инструменты для навигации между экранами, сохранения состояния и обработки нажатия кнопки Back для Android

Полезные ресурсы для изучения Kotlin Multiplatform Mobile

  1. Официальный get-started от компании JetBrains
  2. Страница с примерами приложений на KMM
  3. Документация Decompose
  4. Материалы от компании IceRock
  5. Поиск библиотек для KMM

Евгений Хохлов Tech Lead в компании Chatfuel

  • 1 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Связаться со мной
Close