Kotlin Multiplatform
2.62K subscribers
84 photos
3 videos
407 links
Русскоязычный канал новостей о Kotlin Multiplatform
Download Telegram
Немного про подключение kotlin/native фреймворка в ios приложение. Есть несколько путей:
1. Добавить в ios проекте отдельный таргет-фреймворк, который не будет иметь какого либо исходного кода, но будет содержать специальную build phase, в которой будет происходить вызов gradle task компиляции фреймворка, после чего результат компиляции будет копироваться в директорию сборки xcode - туда, куда бы сам xcode скомпилировал фреймворк будь тут исходный код swift'а. Это самый старый вариант интеграции.
2. Добавить в ios проекте фреймворк как embed фреймворк, указывая где он будет находиться - директория должна быть всегда одна, даже для разных архитектур фреймворка. Далее добавить к проекту build phase, которая будет вызывать у gradle специальную таску. Задача таски - собрать фреймворк и положить его по тому пути, который был указан при добавлении фреймворка в проект. Таким образом нет никаких лишних таргетов. Этот подход описан в текущем туториале от JetBrains "Targeting iOS and Android with Kotlin Multiplatform".
3. Интеграция через CocoaPods используя плагин org.jetbrains.kotlin.native.cocoapods. Для айосников он будет самый удобный. В gradle потребуется добавить специальную конфигурацию плагина (по сути описание pod'а нашего) и плагин автоматически сгенерирует нам podspec. После чего в Podfile от iOS приложения мы просто ссылаемся на наш pod локальный и вся интеграция готова. Под капотом все работает примерно так же как первый и второй случай - создается специальный проект для pod'а, там нет исходного кода но есть embed framework который собирается специальной gradle таской, которая и скомпилирует и перенесет фреймворк по нужному пути. Есть у этого решения пара особенностей - во первых на момент pod install фреймворк должен быть уже скомпилирован, то есть в градле мы должны засинхать проект и запустить gradle task :podspec в нашем mpp проекте. Во вторых - из gradle проекта не видны таски, используемые в xcode build phase (syncFramework в особенности). То есть запустить перекомпиляцию с переносом фреймворка куда-надо из вне xcode нельзя. А еще плагин позволяет подключать iOSные pod'ы в kotlin/native (только те у которых есть objc биндинг).
4. Интеграция через CocoaPods но без плагина org.jetbrains.kotlin.native.cocoapods. Разница в том, что podspec файл один раз пишется и кладется рядом с проектом, а градл таски syncFramework добавляются отдельно к проекту (у нас в IceRock это делает наш mobile-multiplatform плагин) и доступны для запуска просто из IDE или gradle. Это дает больше прозрачности при разработке и полный контроль над самой build phase сборки фреймворка (мы например кеширование на проектах через shell скрипт дополнительное делаем, чтобы не запускать gradle лишний раз при сборках ios проекта - он очень долгий).

Туториал Targeting iOS and Android with Kotlin Multiplatform - https://play.kotlinlang.org/hands-on/Targeting%20iOS%20and%20Android%20with%20Kotlin%20Multiplatform/
Плагин CocoaPods - https://kotlinlang.org/docs/reference/native/cocoapods.html
Плагин mobile-multiplatform - https://github.com/icerockdev/mobile-multiplatform-gradle-plugin
Пример интеграции mobile-multiplatform плагина (пока у него нет ридми) - https://github.com/icerockdev/moko-mvvm/tree/master/sample

#tips
Небольшой список библиотек kotlin multiplatform, покрывающий большинство базовых задач мобильной разработки:
* https://github.com/ktorio/ktor - http клиент, API построено coroutines. Заменяет Retrofit и Alamofire;
* https://github.com/Kotlin/kotlinx.coroutines - асинхронный код в синхронном стиле, вместо калбеков просто помечаем функцию suspend и компилятор добавит калбеки за нас. А сам код будет выглядеть как синхронный. Частично заменяет RxJava/RxSwift ну и калбеки разумеется;
* https://github.com/Kotlin/kotlinx.serialization - сериализация из/в json/cbor/protobuf, работает на аннотациях и кодогенерации. Заменяет gson/jackson/TRON/Codable;
* https://github.com/russhwolf/multiplatform-settings - постоянное key-value хранилище. По сути SharedPreferences/UserDefaults доступные в общем коде;
* https://github.com/cashapp/sqldelight - база данных SQLite доступная в общем коде, с генерацией типобезопасных API. Заменяет Room/Realm/CoreData;
* https://github.com/AAkira/Napier - логирование. Замена Timber/CocoaLumberjack;
* https://github.com/Kodein-Framework/Kodein-DI - внедрение зависимостей (решаются зависимости в рантайме, нет кодогенерации и проверки на этапе компиляции). Замена Dagger/Swinject;
* https://github.com/korlibs/klock - работа с датой и временем, с поддержкой таймзон и форматирования;
* https://github.com/icerockdev/moko-mvvm - компоненты для построения Presentation слоя на базе MVVM. ViewModel'и и LiveData для реактивного обновления UI;
* https://github.com/icerockdev/moko-resources - ресурсы локализации и изображения с доступом из общего кода, и генерацией под обе платформы из одного источника;
* https://github.com/icerockdev/moko-permissions - получение рантайм разрешений из общего кода.

#libs
Channel photo removed
Channel photo updated
Сегодня хочется поделиться видео записями выступлений на тему мобильной мультиплатформы с прошедшего Kotlin/Everywhere Minsk.
Интересное:
* Reaktive: реактивное программирование в Kotlin Multiplatform - про перенос Rx в мультиплатформу, с поддержкой смены потоков, разбор от авторов библиотеки (уже было чуть раньше в постах);
* Sliced but whole. A little adventure in multiplatform world - не сильно успешный опыт использования mpp, стоит и такие кейсы знать. Подсвечивает проблемы адаптации людей с градлом, разобран и фронтенд веб с kotlin2js, интероп Firebase ios фреймворка с kotlin/native. Итог от спикера - "не для продакшена". Если рассматривать мобильную разработку - по нашему опыту для продакшена уже полгода как готово :)
* iOS & Kotlin. Путь приложения от начала до публикации в AppStore - взгляд айосника на разработку с kotlin mpp, в кейсе когда айосник единственный разраб на проекте и андроид платформы пока еще нет;
* Kotlin Multiplatform с точки зрения бизнеса - тут понятно из названия. Минимум технической инфы, максимум мнения бизнеса (аутсорс) на технологию и опыт использования.

https://www.youtube.com/playlist?list=PL0SwNXKJbuNmNzTBowoiL7tem0-1gOsmo

#videos
Затронем важную часть разработки, которая совсем не видна пользователям, но очень нужна разрабам - логирование. В мобильной мультиплатформе есть небольшой выбор библиотек:
* https://github.com/JakeWharton/timber - стандарт в Android разработке. Мультиплатформенная версия начата, но так и не закончена. Есть форк от Touchlab где доделана и айос версия (https://github.com/touchlab/timber/tree/native), но в bintray нет сборки с актуального котлина (можно просто скачать себе исходники и собрать самому себе в мавен репозиторий);
* https://github.com/AAkira/Napier - библиотека вдохновленная Timber'ом - поддержка обеих мобильных платформ из коробки, api примерно такое же как и у Timber. Так же возможно добавлять свои логгеры (зовутся Antilog). Поддерживает актуальнную версию kotlin;
* https://github.com/korlibs/klogger - мультиплатформенный логгер, без поддержки множества output'ов (как сделано у Timber и Napier) и пока без апдейта до актуального 1.3.50;
* https://github.com/florent37/Multiplatform-Log - самый простейший логгер, так же без поддержки множества output'ов. До актуальной версии kotlin так и не обновлено.

Если подвести краткий вывод - в MPP для логирования брать нужно Napier. Почти тот же Timber, но для всех платформ и не требуется самим пересобирать на новую версию котлина.

#libs
Обратим внимание на еще один важный для разработки момент - Continuous Integration. Уже нельзя представить современный проект без CI, который как минимум должен автоматизировать деплой билдов, а в идеале - проводить и тестирование и проверку кода на правила разработки.
Что же меняется на CI относительно чисто нативных iOS и Android проектов, если мы начинаем использовать общую библиотеку на Kotlin MultiPlatform?
Ответ - практически ничего. Для android все остается также как было. Для iOS могут потребоваться некоторые изменения. Обратим внимание на них:
1. На раннере собирающем iOS должна быть java для корректного запуска gradle и компиляции kotlin/native;
2. При интеграции общей библиотеки через cocoapods перед вызовом pod install должен быть собран фреймворк (в официальном cocoapods плагине перед pod install нужно вызвать у gradle задачу podspec, а если использовать наш mobile-multiplatform плагин как в moko-template - можно просто вызывать pod install и все сделается само);
3. При интеграции общей библиотеки через билдфазу с отдельным таргетом в самом проекте - билдфаза сама запустит градл и все что нужно сделает, без необходимости делать что-то предварительно;
4. Для запуска тестов на айос пока требуется добавлять отдельную градл таску в конфигурацию общей библиотеки. Таска соберет запускаемый файл тестов и запустит его на симуляторе iOS.

У нас, в IceRock, для CI используется GitLab CI, раннер это mac-mini на котором и xcode и android sdk установлены, сборка android проекта делается полностью средствами градла, а сборка айос полностью средствами Fastlane.

Так же по этой теме есть неплохая статья https://diamantidis.github.io/2019/09/08/continuous-integration-for-kotlin-native-projects-with-gitlab-ci, в которой разобрана вся настройка CI для GitLab под проект с общей библиотекой, включая и запуск тестов и прогон lint. Статья входит в цикл статей про MPP - там есть и про настройку окружения, и про настройку юнит тестов, и про инструменты проверки кода. Есть и проект пример с этим всем https://gitlab.com/diamantidis_io/kmp_template/tree/master

Упомянуто:
https://kotlinlang.org/docs/reference/native/cocoapods.html - официальный gradle плагин cocoapods
https://github.com/icerockdev/mobile-multiplatform-gradle-plugin - gradle плагин для упрощения настройки mobile mpp проектов
https://github.com/icerockdev/moko-template - проект шаблон с использованием mobile-multiplatform плагина (примеры фичей и ридми пока в процессе)

#posts #tips
При разговоре о мультиплатформенной разработке iOS разработчики обычно предполагают что это означает отказ от привычных им библиотек. В контексте Kotlin Multiplatform хочется развеять это заблуждение...
* Первый момент (и самый очевидный) - так как UI делается все так же в Swift, то разработчику доступны все нативные библиотеки как через CocoaPods так и Carthage;
* Второе - внутри самой общей библиотеки на Kotlin в ios-specific части тоже можно использовать зависимости из нативного мира - ограничение только в том что библиотека должна иметь objc биндинг (так как Kotlin/Native взаимодействует именно с objc). Вручную это делается через cinterop;
* Третье - для упрощения подключения iOS библиотек к kotlin ios-specific gradle плагин org.jetbrains.kotlin.native.cocoapods позволяет прям в gradle указать список pod'ов которые будут автоматически проброшены в kotlin. И в ios-specific части можно работать с подключенными библиотеками. У плагина есть пара ограничений (нет поддержки SubSpec и собирать библиотеку нужно будет обязательно через Xcode, так как для линковки все данные о подключенных Pod'ах именно у Xcode).

Документация по плагину - https://github.com/JetBrains/kotlin-native/blob/master/COCOAPODS.md
Ручное подключение библиотеки, без плагина - https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#cinterop-support

#tips
Forwarded from Nikolay
Небольшое дополнение - можно взаимодействовать и с библиотеками написанными на Си, а также возможно работать и в другую сторону, экспортируя Котлин в виде Objective-C или C деклараций.
Наконец-то опубликованы видео с прошедшего DroidCon New York, на котором было очень много внимания уделено именно Kotlin Multiplatform в мобильной разработке. Что есть:
* Native Concurrency and Coroutines - от автора библиотеки CoroutineWorker , которая позволяет выполнять suspend функции на отдельных потоках - как появилась библиотека и как используется в Autodesk;
* Multiplatform Library Development - от автора библиотеки multiplatform-settings - про разработку mpp библиотеки, про проектирование апи под обе платформы, про состояние kotlin mpp на данный момент;
* Lessons Learned from Using Kotlin Multiplatform internally - опыт погружения андроид и айос специалистов в мультиплатформу, какие шишки набивали, какие выводы сделали, фидбек айосников;
* Effective Multiplatform Architecture - очень классная презентация с полезными аргументами как продать мпп бизнесу, так и для технарей с полезными идеями как вводить мультиплатформу в существующий проект;
* Multiplatform Functional Architecture - про архитектуру MVU (Model-View-Update) на мультиплатформе. Библиотека oolong поможет строить такую архитектуру. Для любителей Redux;
* SwiftUI meets Kotlin Multiplatform! - небольшой доклад про то как дружили общую библиотеку и SwiftUI. Для этого предложено и ViewModel'и унести на сторону нативного android, ios кода;
* Using Kotlin/JS and Kotlin/Native on Android - доклад от Jake Wharton о том как на андроиде он дружил обычный котлин, нативный котлин и kotlin js в одном приложении;
* Building apps using Kotlin Native - расказ про разработку общей библиотеки, для новичков в теме. Даже задета тема про Worker'ы для многопоточности на Native.

#videos
Сегодня поделюсь статьей, которую возможно уже видели в сети, но она имеет очень интересную информацию. Статья про разработку библиотеки kissme - не про поцелуи, а про хранение данных в keychain. Помимо просто истории о разработке multiplatform библиотеки и столкновением с некоторыми ограничениями, тут есть то что не часто встретишь - линковка objective-c библиотеки в kotlin код. У ребят как раз был кейс, что не смогли через kotlin ios-specific код сделать нужную функциональность и поэтому решили сделать дополнительно objective-c библиотеку, которую прилинковали к котлину через cinterop и в итоге вызывали из котлина функции своей библиотеки.
Kissme: Kotlin Secure Storage Multiplatform library. The Code Story.

#posts #libs
Сегодня у нас пост новостей от JetBrains.
Kotlin/Native в следующем релизе получит:
* поддержка Xcode 11
* новый LLVM
* новые API iOS, macOS
* поддержка watchOS и tvOS.
Подробнее тут - https://github.com/JetBrains/kotlin-native/pull/3391
Попробовать можно будет уже скоро - EAP планируется в ближайшие недели.

Так же вы можете задать вопросы про новый релиз напрямую авторам в нашем чатике - нажимайте Discuss и обращайтесь - Николай Иготти уже там (новость как раз от него).

#news
Ioannis Diamantidis продолжает свою серию статей о Kotlin/Native. Новая статья From Kotlin to Native: Or how Kotlin concepts are mapped to the Apple framework разбирает некоторые особенности получаемого из Kotlin кода iOS фреймворка - как Kotlin код выглядит из ObjectiveC и Swift.
Это не полный список особенностей на стыке Kotlin и ObjC, но знать их очень полезно. Так же еще особенности можно подсмотреть в нашей летней статье - Опыт работы с Kotlin Multiplatform за 10 месяцев. Краткий список особенностей kotlin на стыке с ios доступен в презентации.
Так же в октябре на AppsConf мы отметим еще несколько новых особенностей по актуальной версии Kotlin.

#posts #slides
Можно ли работать с базой данных из common кода под ios и android? Ответ - конечно можно :) И есть несколько путей:
1. Метод "в лоб" - делаем interface реализация которого будет проброшена с нативной стороны и на android и ios делаем отдельные реализации БД так, как привыкли разработчики;
2. Делаем expect/actual классы, чтобы уже внутри котлина реализовать всю работу с БД, используя нативные средства Android и iOS в actual реализациях;
3. Используем библиотеку SQLiter которая позволяет в common коде работать с sqlite БД напрямую, без каких либо оберток;
4. Используем библиотеку SQLDelight от известных square (которые успели переименоваться в cashapp). Данная библиотека идет в паре с gradle plugin'ом который из специального файла, в котором описана схема базы данных и запросы, которые планируется выполнять, генерирует сущности и методы для выполнения запросов. И все это доступно из common кода для обеих мобильных платформ, а так же уже проверено на Android годами ранее.

Рекомендуемый на данный момент способ это конечно SQLDelight. Для знакомства с ним можно воспользоваться:
* Презентацией SELECT * SQLDelight JOIN Multiplatform в которой разобраны преимущества библиотеки;
* Статьей SQLDelight 1.x Quick Start Guide for Android с пошаговой инструкцией и даже примером юниттестирования;
* Статьей Kotlin Multiplatform. Very beginner’s guide (part 3) Database с пошаговым примером реализации БД, но статья со времен kotlin 1.3.31, так что возможны некоторые нестыковки, особенно по версиям библиотек используемых - с 1.3.50 на айос не сойдутся они, нужно более новые;
* Проектом Droidcon Lisbon - здесь в app есть common source set и используется SQLDelight с версией kotlin 1.3.41;
* Проектом Newsout тоже на версии kotlin 1.3.41.

А еще SQLDelight поддерживает Flow для оповещения о изменениях, но на iOS там есть проблемы, требующие обхода.

#libs #slides #projects
Тем кто интересуется темой тестирования кода будет полезна статья Shared Library in Kotlin Multiplatform в которой разобрано по шагам создание общей библиотеки и добавление к ней простых тестов.
В паре с статьей идет и проект-пример, в котором можно наглядно посмотреть и тесты и демо приложение, работающее с сетью (ktor-client, kotlinx.serialization, coroutines - стандартный mpp набор).
Еще примеры тестов можно посмотреть в проекте-примере от russwolf (автор multiplatform-settings) и в еще одном проекте примере.

#posts #samples #tests
Badoo продолжает радовать контентом по Kotlin Multiplatform. В этот раз подготовили хоршую подробную статью по настройке автосборки для мультиплатформенной библиотеки - Continuous delivery для вашей Kotlin Multiplatform библиотеки. Стоит ознакомиться со статьей даже тем, кто не собирается настраивать CI/CD, так как помимо конфигурации для автоматической сборки и выгрузки в maven репозиторий через Travis CI всех таргетов библиотеки, там описано и строение публикуемых данных - особенно интересно про Gradle Metadata, что так активно используется Kotlin Multiplatform проектами. Всем бы авторам MPP библиотек настроить автоматизацию на github по примеру ребят, чтобы апдейты к библиотекам выходили как можно быстрее, после релиза новой версии котлина.

#posts #libs
А для тех кто уже успел ознакомиться со статьей от Badoo, есть интересная библиотека - реактивщину в kotlin multiplatform оказывается несут не только Badoo, но и Mirego. И их реализация зовется Trikot.streams. Эта библиотека так же позволяет делать реактивные цепочки с переключением потоков на обеих мобильных платформах (на native так же как Reaktive данные замораживаются для передачи между потоками), но от привычного Rx API библиотеки отличается.
Примеры использования trikot.streams выглядят очень похожими на LiveData, как в moko-mvvm, при чем так же есть конвертация stream в LiveData для android, а для iOS сделан дополнительный cocoapod с вспомогательными swift методами привязки stream к элементам на экране (как и в moko-mvvm).

#libs
Те кто ознакомился с проектом-примером от Karumi, который был в посте со статьей о тестировании, могли заметить что в gradle конфигурации общей библиотеки есть специальная gradle таска, которая генерирует на основе содержимого gradle.properties класс KotlinConfig, по аналогии BuildConfig в android. Эта функциональность далее была выделена в отдельный gradle-plugin который назвали Hagu. Благодаря ему можно вынести различную конфигурацию из кода в gradle.properties файл и иметь единое место для конфигурации. Но в отличие от android в mpp пока нет поддержки buildFlavor, поэтому для конфигурирования разных окружений (dev,prod,stage) это не особо подходит. Зато подходит для подключения разных buildSecret из переменных окружения CI в сборку (чтобы не хранить секреты в самом гите, особенно важно для опенсорс проектов).

#plugins
В одном из прошлых постов были разобраны возможные варианты по работе с датой и временем в common коде. Среди всех библиотек особо выделялась библиотека klock, так как имела практически весь нужный в мобильной разработке функционал. Сегодня хочется упомянуть другую библиотеку работы с датой/временем - fluid-time. Она так же поддерживает kotlin 1.3.50 и android (jvm), ios платформы. В ней есть работа с датами, временем, таймзонами, интеграция с kotlinx.serialization из коробки, timestamp. Но чего в ней нет, так это хорошей документации. Поэтому знакомиться с библиотекой и ее API надо через код.

Тем же кто решит заглянуть в gradle конфигурацию библиотеки для упрощения разбора следует сразу ознакомиться с gradle-plugin'ом, который был сделан автором библиотеки специально для поддержки всех своих библиотек.
Так же у автора есть fluid-stdlib - дополнения к kotlin-stdlib в котором есть вынесение в общий код Currency, Country (с использованием на платформах системных инструментов) и множество разных дополнений к типам данных. Опять же документация скудная, смотрите код.

#libs
Для тех кто пользуется REST API и имеет в проектах OpenAPI (Swagger) спецификацию (надеюсь проектов без серверной спецификации уже все таки нет) в проекте OpenAPIGenerator появилась поддержка генерации kotlin-multiplatform API. На днях вышел релиз, в котором данное изменение уже присутствует.
Генерируется api завязанное на ktor-client, coroutines, KotlinxSerializer (фича ktor-client). Наружу результат запроса выдается в виде HttpResponse из ktor, то есть снаружи можно без проблем обрабатывать любой статус-код.
Мы в IceRock пока не проверяли этот генератор, так как уже полгода пользуемся своим, который наконец-то выгрузили в опенсорс - moko-network. Он основан на более старой версии OpenAPIGenerator'а, но проверен уже несколькими боевыми проектами. Поддерживаются и сериализация enum'ов с разными имя-значение (что из коробки kotlinx.serialization не умеет, но в OpenAPIGenerator'е это реализовано аналогично как у нас), а так же сериализация делается не через фичу KotlinxSerializer чтобы напрямую каждому запросу указывать конкретный сериализатор, это избавляет от проблемы "только один list сериализатор на всю api". В ридми пока не заполнен блок использования, но можно посмотреть по проекту-примеру.
Те кто попробует официальную версию из OpenAPIGenerator'а - прошу напишите свой фидбек использования нам в чат (кнопка discuss). А если и с нашим плагином сравнить удастся - такой фидбек будет еще полезнее.

#plugins
Разработка приложений с общим кодом на обе платформы не нова, и среди популярных решений есть сейчас React Native (от которого некоторые большие компании начинают уходить), Flutter (к которому многие идут) и Kotlin Multiplatform (про который наш канал). И периодически слышен вопрос от некоторых разработчиков: вот на kotlin можно написать общую логику, но нельзя писать UI (точнее неудобно), а можно ли совместить общую логику на kotlin и общий UI на Flutter?
Ответ: да, можно. И это даже делали...На эту тему есть пара статей - Fast Prototypes with Flutter + Kotlin/Native (русский перевод) и Приложение для iOS и Android на Kotlin + Flutter UI. При чем у второй статьи есть и открытый код, а сама статья это пошаговая инструкция как сделать так же самому (первая же статья больше про сам принцип и немного про ограничения этого симбиоза).

Если задуматься над вопросом "а зачем?" то мысли есть такие:
1. Для разработки прототипа одним человеком (особенно если сделать автоматическую генерацию каналов для связи kotlin и flutter между собой) - нам нужен человек который и общую логику на kotlin напишет и ui сразу на обе платформы сделает, при чем с hot reload и действительно быстрой разработкой визуала;
2. Для дальнейшего развития этого прототипа в большое замудреное приложение, напичканное разными нативными штуками типа фоновых сервисов, интеграций разных экстеншенов и прочих платформенных штук. С заменой UI на нативный, привычный всем пользователям. То есть достигаем как можно быстрее состояния MVP для проверки гипотезы, а если ее ждет успех - тогда уже вкладываем ресурсы в нативную разработку (не выкидывая общую бизнеслогику написанную на kotlin).

Возможно и у вас есть свое мнение по поводу вопроса "зачем соединять flutter и kotlin mpp?" - заходите в чат и поделитесь.

#posts #cases