Кроссплатформенная разработка
Использование Kotlin Multiplatform Mobile в iOS-проекте
Добавление в проект Kotlin Multiplatform Mobile (KMM) вручную может быть утомительным. В этой статье мы добавляем в наш Xcode-проект под названием medium новую платформу KMM.
Настройка и использование Kotlin Multiplatform Mobile в iOS-проекте может быть довольно сложным. В этой статье мы добавляем в наш Xcode-проект под названием medium новую платформу KMM.
Kotlin Multiplatform Mobile в iOS-проекте: начинаем
В этом примере мы будем использовать пустой проект KMM с изюминкой. Если вы не знаете, как создать проект KMM, сначала прочтите мою предыдущую статью. Изюминка: в процессе создания на этот раз мы назовем приложение iOS точно так же, как наш проект Xcode. Это устраняет необходимость изменять путь и переменные проекта кода в Gradle и в файлах свойств.
Наш созданный проект KMM теперь состоит из трех компонентов:
- Приложение для Android
- Общий код (на Kotlin)
- Приложение для iOS
На следующем этапе мы хотим заменить стандартное приложение KMM iOS на наше существующее. Наше существующее приложение, которое используется, называется средним и может быть новым, пустым проектом или вашим последним шедевром. В этой демонстрации среда — это недавно созданный проект.
Замена iOS-приложения
Сначала мы заходим в каталог нашего приложения KMM в Finder. Вы можете увидеть три основные папки: androidApp, shared и medium. Заглянув внутрь папки носителя, мы видим типичный макет проекта Xcode, содержащий файл .xcodeproj и все исходные и тестовые файлы.
Действие: удалите все, что находится в средней папке, и поместите все существующие папки приложения внутрь. С этого момента мы будем открывать приложение для iOS отсюда.
Линкинг нашего приложения для iOS с общими компонентами KMM
Чтобы наше приложение iOS могло работать с общими компонентами KMM, должны произойти две вещи:
- Проект KMM необходимо создать для нашего приложения для iOS.
- Приложению iOS необходимо найти и ссылаться на созданные общие файлы.
1. Создайте проект KMM для Xcode
В своем проекте кода перейдите в корневой проект и откройте Build Phases. Щелкнув +, создайте новую Run Script Phase.
Сценарий выполнения позволяет запускать любой сценарий оболочки при сборке проекта. Этот скрипт позволяет нам создавать приложение KMM для iOS без Android Studio или без запуска Gradle в терминале.
В поле Shell script вставьте:
#!/bin/shPARENTDIR="$(dirname "$SRCROOT/")"cd "${PARENTDIR}"./gradlew :shared:packForXCode - PXCODE_CONFIGURATION=${CONFIGURATION}UNIVERSAL_OUTPUTFOLDER="${APPNAME}/framework/${CONFIGURATION}-universal"FRAMEWORK_NAME="shared"BASEPATH="${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework"ARM64PATH="${PARENTDIR}/${FRAMEWORK_NAME}/build/bin/iosArm64/debugFramework/${FRAMEWORK_NAME}.framework"X64PATH="${PARENTDIR}/${FRAMEWORK_NAME}/build/bin/iosX64/debugFramework/${FRAMEWORK_NAME}.framework" mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" #copy headers, modules & info.plist of ARM64/X64 build into our framework cp -R "${ARM64PATH}" "${UNIVERSAL_OUTPUTFOLDER}/"if [ ! -d "$ARM64PATH" ]; then echo "error: Please on an iOS Device to create ARM64 build files" fiif [ ! -d "$X64PATH" ]; then echo "error: Please run on a Simulator to create X64 build files" fiARM64PATHAPPEND="${ARM64PATH}/${FRAMEWORK_NAME}" X64PATHAPPEND="${X64PATH}/${FRAMEWORK_NAME}"FULLPATH="${PARENTDIR}/${BASEPATH}"lipo -create "${ARM64PATHAPPEND}" "${X64PATHAPPEND}" -output "${FULLPATH}/shared"
Позже я расскажу о функциях этого скрипта. Основное исполнение — это строка ./gradlew: shared: packForXcode. Эта строка кода запускает упаковочный агент, расположенный в build.gradle.kts, который находится в общей папке. Код выглядит так:
val packForXcode by tasks.creating(Sync::class) { group = "build" val mode = System.getenv("CONFIGURATION") ?: "DEBUG" val sdkName = System.getenv("SDK_NAME") ?: "iphonesimulator" val targetName = "ios" + if (sdkName.startsWith("iphoneos")) "Arm64" else "X64" val framework = kotlin.targets.getByName<KotlinNativeTarget>(targetName).binaries.getFramework(mode) inputs.property("mode", mode) dependsOn(framework.linkTask) val targetDir = File(buildDir, "xcode-frameworks") from({ framework.outputDirectory }) into(targetDir) } tasks.getByName("build").dependsOn(packForXcode)
Я не буду углубляться в этот (стандартный) скрипт, за исключением того, что упомяну, что он различает сборки iOS Arm64 и x64. Это различие позволяет нам использовать компоненты KMM на реальном iPhone (с использованием процессора ARM) и в симуляторе. Вы можете узнать больше об архитектуре процессора здесь.
Важно: переместите сценарий выполнения в верхнюю часть этапов сборки!
У Run Script два процесса. Во-первых: он создает структуру сборки для данного процессора (ARM или x64). Во-вторых: он объединяет две платформы сборки в единую структуру, которая может обрабатывать как процессоры ARM, так и x64; назовем это нашим универсальным фреймворком.
Следующий шаг немного непонятен, но он создает правильную настройку и его нужно выполнить только один раз. Так что читайте внимательно!
- Запустите проект на любом симуляторе. Сборка завершится неудачно, и будет сказано: Команда PhraseScriptExecution завершилась неудачно с ненулевым кодом выхода. И это прекрасно! Теперь у нас есть структура симулятора (в shared> build> bin> iosX64> debugFramework).
- Запустите проект на своем iPhone. Сборка будет успешной, но ваше приложение упадет во время выполнения с ошибкой: Library not loaded: shared.framework.. И это опять прекрасно. Теперь у нас есть как фреймворк для iPhone (в shared> build> bin> iosArm64> debugFramework), так и созданный универсальный фреймворк (в framework> Debug-universal). Ошибка возникает из-за того, что универсальный фреймворк еще не привязан к нашему проекту.
Итак, приступим к импорту фреймворка!
2. Импорт нашего универсального ‘shared.framework’
Вы можете прочитать несколько руководств по KMM, в которых предполагается импортировать общий фреймворк из папки сборки. Но мы создали нашу универсальную платформу как для симулятора, так и для iPhone, так что забудьте об этом! Наш фреймворк, совместимый с симуляторами и iPhone, вы найдете в разделе framework> Debug-universal> shared.framework. Теперь этот каталог должен быть связан с нашим проектом Xcode.
В Xcode вернитесь на вкладку General. Здесь вы видите раздел «Frameworks, Libraries, and Embedded Content».
Действие: Здесь мы добавляем shared.framework из каталога framework:
Теперь у вашего проекта есть доступ к объединенному shared.framework. Но в каталоге сборки есть еще один файл фреймворка, который нам тоже нужен.
3. И еще одно!
Перед запуском нашего проекта сейчас мы должны добавить конкретный путь в Framework Search Paths. Этот путь поиска необходим для того, чтобы проект нашел в Xcode фреймворк shared.framework. Перейдите в настройки сборки и найдите раздел «Search Paths».
Там вы найдете раскрывающийся список для Framework Search Paths.
Действие: Вставьте $(SCROOT)/../.shared/build/xcode-frameworks как в Debug, так и в Release, дважды нажав соответствующее поле справа, щелкнув значок плюса во всплывающем окне и вставив эту строку.
Как только это будет сделано, мы готовы запустить проект где угодно, будь то на вашем iPhone или в симуляторе.
Примечание. Если мы работаем на iPhone или симуляторе, будет повторно запущена только соответствующая общая папка сборки. Это сокращает процесс сборки вместо того, чтобы всегда запускать оба типа сборки.
Поздравляю!
Kotlin Multiplatform Mobile в iOS-проекте: отладка
Building for iOS Simulator, but the linked and embedded framework 'shared.framework' was built for iOS.
Это иногда случается, когда мы возимся с файлами сборки. Чтобы исправить это, просто удалите shared.framework со вкладки General (Frameworks, Libraries и Embedded Content), снова выполните сборку на симуляторе iOS, а затем проделайте все манипуляции с shared.framework, как на шаге 2.
Если у вас возникнут какие-либо другие ошибки или ошибки, напишите мне или оставьте комментарий, чтобы мы могли поделиться решениями.