
Вступление
Всем привет. Какое-то время назад, я решил делать свой проект для Android и iOS одновременно. Естественно, встал вопрос о выборе технологий. Пару недель присматривался к популярным стекам и выбрал Kotlin/Native. Поскольку я являюсь Android-разработчиком, то с Kotlin знаком давно, а со Swift особого опыта не было и хотелось получить большую часть кода общего для обеих платформ. Следовательно, сразу встал вопрос, а как писать UI для iOS. Быстрый взгляд на рынок подсказал, что есть Flutter, который позволяет писать UI для двух платформ одновременно. Собственно, так и началась эта история.
В статье описан опыт сборки Flutter в качестве UI и Kotlin для основной логики. Важно: под катом много картинок и инструкция, как собрать проект
Оглавление
- Создание общей библиотеки на Kotlin
- Создание Android-приложения
- Создаём iOS-проект
- Добавление Flutter �� Android-приложение
- Добавление Flutter в iOS-проект
- Заключение
Часть 1
Создание общей библиотеки на Kotlin
- Выбираем Kotlin Mobile Shared library

- Далее

- Указываем нашу рабочую папку, здесь я сделал отдельную папку под проект. Поскольку у меня будет 4 разных проекта и их удобнее держать в одном месте

- Осталось указать в
local.propertiesпуть кsdk.dirи проект начинает собираться, у меня это путь/Users/vlad/Library/Android/sdk

- Структура проекта, изменяем имена пакетов с
sample наhabr.example

- Пора приступать к публикации, вызываем
wrapper. После этого у нас в проекте появится файлик.gradlewи можно будет с ним работать из терминала

- Запускаем из терминала
./gradlew publishToMavenLocal

- После этого в локальном maven-репозитории у нас появится 4 папки, в которых будут лежать наши библиотеки

Часть 2
Создание Android-приложения
Создаём android проект
Тут всё стандартно








- На момент написания статьи проект генерируется с «битой» зависимостью, поэтому убираем в конце
jre7, получитсяkoltin-stdlib, после этого проект начинает собираться

- Открываем
build.gradleи в секциюrepositoriesдобавляемmavenLocal. Важно! Секцияrepositoriesдолжна быть та, что внутриallprojects, а не вbuildScript

- Теперь мы можем добавить нашу библиотеку как зависимость
implementation 'habr.example:commonLibrary-jvm:0.0.1'

- Открываем
activity_main.xmlи указываем вTextViewidmain_activity_text

- В
MainActivity.ktпросто устанавливаем текст в этомTextView

- Отлично, к этому моменту у нас есть Android приложение, которое умеет использовать функцию
hello()из нашей библиотекиhello() на эмуляторе
Часть 3
Создаём iOS-проект
- Выбираем Single View App

- Заполняем основную информацию и выбираем папку. Здесь важно выбирать папку, корневую для наших остальных проектов, поскольку в ней Xcode создаст подпапку с название проекта


- Первым делом добавляем
CocoaPods. Для этого выполняемpod initв папке проекта, закрываем проект вXcodeи выполняемpod install. Видим, что установка завершилась успешно

- Важно! На сайте
CocoaPodsне рекомендуется добавлять папку/Podsв.gitignore, но я всё равно это сделал. Так как после добавленияflutter, мы каждыйbuildбудем реконфигурировать зависимости. Пока что, мне это решение нравится больше, чем засорять.git - Открываем проект через файлик
Awesome App.xcworkspace

- Открываем терминал, в нём переходим в папку нашей
commonLibraryи запускаем./gradlew linkDebugFrameworkIos. После этого в нашей папкеbuildпоявляетсяiOSFramework

- Выбираем Target

- И для этой Target добавляем бинарник

- Выбираем Add Other

- Указываем путь к
framework, который получили на шаге 6 (commonLibrary.framework)


- Теперь в проекте у нас должен отображаться этот
framework

- Идём в
Build Settingsи отключаемEnable Bitcode

- Теперь нужно указать где именно искать наш
framework, открываемFramework Search Path

- Указываем путь
"${PODS_ROOT}/../../commonLibrary". Обязательно выбираемrecursive. Конечно, можно обойтись и без этого, если более точно сконфигурировать путь. Но, поскольку это только начало проекта, сейчас нам важно убедиться в том, что вся эта связка заработает. А поменять пути мы можем и потом

- Нужно сделать так, чтобы при каждом
buildвXcodeсобирался нашframeworkпри помощиgradle. ОткрываемBuild Phases

- Добавляем новую
Script Phase

- Добавляем код скрипта.
cd "${PODS_ROOT}/../../commonLibrary" echo $(pwd) ./gradlew linkIos
Здесь мы просто переходим в папку проекта нашей библиотеки и запускаем./gradlew linkIos. Вызовecho $(pwd)нужен только для того, чтобы показать в консоли, в какую конкретно папку мы попали

- Сдвигаем нашу
build phaseв самый верх, сразу послеtarget dependencies

- Теперь открываем
ViewControllerи добавляем вызов нашей функции из библиотеки

- Запускаем наш проект и видим

Отлично, это значит, что мы правильно подключили Kotlin Library к iOS-проекту
Осталось всего ничего — добавить flutter, как framework для написания UI, в наши приложения и можно начинать разрабатывать продукт
Часть 4
Добавление Flutter в Android-приложение
Тут мне очень помогла статья на github
- Переходим в root-папку, где лежат все наши проекты и делаем
flutter create -t module flutter_ui

- Открываем
settings.gradleи включаем наш flutter-модуль, как подпроект

- Открываем файл build.gradle и добавляем в зависимости наш проект

- Изменяем
MainActivity.ktнаFlutterActivity

- Добавляем
App.kt, в котором будем инициализироватьFlutterпри старте приложения

- Изменяем манифест и говорим, что теперь у нас есть класс для
Application

- Обязательно добавляем
java8, без этого flutter не запустится

- Видим UI и в логах Hello from JVM, а это значит, что мы собрали вместе UI на Flutter и основную библиотеку на Kotlin/Native


- Добавим в
MainActivity.ktметод, который мы будем вызывать из Flutter. Здесь по событию из Flutter мы возвращаем нашhello()из kotlin-library

- И добавляем в
main.dartкод, который будет вызывать метод вiOS/Android-частиприложения

- Получаем

Часть 5
Добавление Flutter в iOS-приложение
- Обновляем наш
Podfile
flutter_application_path = File.expand_path("../flutter_ui", File.dirname(path)) eval(File.read( File.join( flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')), binding)


- Важно. Добавьте
$(inherited)в первую строчкуframework search paths. Обязательно проверьте что у васframework search pathsне пустые

Когда вы меняете зависимости вsome/path/my_flutter/pubspec.yaml, вам нужно запуститьflutter packages getизsome/path/my_flutter, чтобы обновить зависимос��и вpodhelper.rb. После этого нужно запуститьpod installизsome/path/MyApp - Добавим ещё 1
Build Phase, только уже для Flutter. Выше того, что мы добавляли в части 3Script phase
"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed

- Заменим наш
AppDelegateнаFlutterAppDelegate

- Обновим
ViewController

- Обернем наш
ViewControllerвNavigatorController


- Теперь приложение запускается. Но, пока что, у нас нет связи между библиотекой и flutter

- Добавим эту связь с помощью
FlutterMethodChannel

- Отлично, теперь и iOS приложение использует
flutterдляUIиkotlinдля основной логики

Заключение
Что важно здесь сказать: я не претендую на то, что вы узнали что-то новое или уникальное. Я просто поделился свои опытом, поскольку для того, чтобы заставить это всё работать вместе, потратил около 4х рабочих дней. И не смог найти примеров кода проекта, который использует одновременно и Kotlin/Native и Flutter
Итоговые проекты
Список ссылок, которые мне помогли, но не сразу
- Сам flutter
- Связь между нативным кодом и UI flutter platform-channels
- Добавить flutter в существующее приложение github
- Kotlin Native native-overview
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Стоит ли развивать тему и писать про архитектуру этого проекта?
97.35%да, мне интересно будет прочитать147
1.99%нет, мне и так хватает материала по теме3
0.66%я сам напишу статью про flutter + kotlin1
Проголосовал 151 пользователь. Воздержался 31 пользователь.
