Если вы задумываетесь над созданием мобильного приложения одновременно под 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 Native добавляет небольшой оверхед, поэтому размер приложения обычно меньше аналогов на Flutter и React Native.
- Большая гибкость. Вы можете использовать любые библиотеки и технологии внутри ваших iOS и Android-приложения, без необходимости написания дополнительного кода.
- Общий код можно использовать не только в мобильных приложениях, но также и в веб-приложениях, и в серверной логике на Kotlin (рис. 2).
Но не стоит забывать и о минусах:
- Высокий порог входа. Необходимы базовые знания разработки под iOS и Android даже для создания простого приложения.
- Небольшое комьюнити. Так как KMM все еще находится в бете, его использует не такое большое число пользователей. Для сравнения: на момент написания статьи вопросов с тегом Flutter в Stackoverflow больше 160 тысяч, а по KMM – чуть больше тысячи.
- Небольшое количество мультиплатформенных библиотек. Несмотря на то что стандартная библиотека языка Kotlin может быть использована в общем коде без ограничений, многие привычные библиотеки языка Kotlin используют платформозависимые вызовы Java-кода и не могут быть использованы напрямую.
- Сложность организации общего кода. KMM не предоставляет никаких готовых решений, как организовать архитектуру приложения, чтобы увеличить процент общего кода и не усложнить процесс разработки.
Команда JetBrains активно работает над развитием комьюнити, а также улучшает плагин для Android Studio, который заметно упрощает создание и поддержку KMM приложения. А последний минус мы рассмотрим подробнее далее и разберем популярный способ организовать код приложения так, чтобы максимально следовать золотому правилу разработки – DRY (don’t repeat yourself).
Архитектура типичного KMM-приложения
Архитектура типичного мультиплатформенного приложения – это монорепозиторий, состоящий из трех модулей: Android-приложение, iOS-приложение и общая библиотека (рис. 3).
Проект с такой структурой можно создать с помощью официального плагина для Android Studio. Шаги по настройке подробно описаны на сайте проекта, поэтому мы не будем углубляться в него подробнее.
Теперь предстоит начать писать общий код. Но как же это сделать? Ведь часто много логики находится непосредственно в UI-компонентах, а что делать с навигацией? Здесь нам на помощь приходит архитектурный паттерн из Flutter, предложенный его создателями компанией Google в 2018. Этот паттерн называется BLoC (business-logic components) и он предлагает вынести всю бизнес-логику из UI-компонента в специальный компонент – BLoC (рис. 4).
Такие bloc’и тесно связаны с определенным UI-компонентом и его жизненным циклом, они создаются и уничтожаются вместе с ним. Но bloc’и не зависят от его реализации и не содержат никакого UI, а значит, они идеальные кандидаты для помещения в общий код. Библиотеки, позволяющие легко внедрить данный подход, уже созданы и активно поддерживаются комьюнити. Самая популярная из них на GitHub – Decompose, на ней мы и остановимся чуть подробнее.
Давайте разберем пример создания BLoC’а в библиотеке Decompose
В качестве примера рассмотрим простейший счетчик, который умеет показывать текущее значение и который можно увеличивать и уменьшать на единицу.
Опишем бизнес-логику нашего компонента:
- Он хранит состояние – текущее значение счетчика.
- У него есть метод для увеличения значения на один.
- У него есть метод уменьшения значения на один.
Создадим Kotlin-интерфейс с этой логикой в общем модуле:
Это и есть интерфейс нашего bloc’а. Value
– это специальный интерфейс, который представляет библиотека Decompose для хранения состояния компонента, который интегрируется со SwiftUI и Jetpack Compose (нативными библиотеками iOS и Android для UI).
CounterState
, а не просто Int
, так как из-за особенностей Kotlin Native, Value
не может хранить значение примитивного типа.Напишем реализацию для нашего bloc’а:
MutableValue
реализует интерфейс Value
и также предоставляется Decompose. reduce
– еще один хэлпер, который позволяет обновить текущее значение на основе предыдущего.
Теперь наш bloc готов к использованию в iOS и Android-приложениях.
Для Android-приложения создадим простой компонент на Jetpack Compose (для простоты восприятия, все модификаторы были убраны из кода):
subsribeAsState()
– расширение, которое позволяет трансформировать Value
в State
, также предоставляется Decompose
Для простоты, наш счетчик – единственный компонент приложения, поэтому мы можем создать наш bloc в MainActivity
Перейдем к iOS-приложению на SwiftUI:
Код не сильно отличается от того, что был в Android: для отслеживания изменений Value используется специальный адаптер – ObservableValue
, код которого можно скопировать из официального репозитория Decompose.
Создаем bloc также при инициализации приложения:
Наше KMM приложение-счетчик готово. Вся бизнес-логика находится в общем модуле и используется совместно iOS- и Android-частями.
Что еще предоставляет Decompose?
В статье мы коснулись только самого базового функционала библиотеки. Кроме него, Decompose содержит инструменты для навигации между экранами, сохранения состояния и обработки нажатия кнопки Back для Android
Полезные ресурсы для изучения Kotlin Multiplatform Mobile
- Официальный get-started от компании JetBrains
- Страница с примерами приложений на KMM
- Документация Decompose
- Материалы от компании IceRock
- Поиск библиотек для KMM
Евгений Хохлов Tech Lead в компании Chatfuel
Комментарии