KA0714 — Создание вашей библиотеки KMP

  • Запись изменена:08.12.2022
  • Post category:Публикации
  • Reading time:33 минут чтения

В предыдущих главах вы создали обучение для Android, iOS и настольных компьютеров. Все эти приложения загружают RSS-канал raywenderlich.com и показывают вам последние статьи, написанные об Android, iOS, Flutter и Unity. Вы можете выполнить поиск по определенной теме или сохранить статью локально, чтобы прочитать ее позже. В процессе разработки приложения вы работали с:

  • Сериализация
  • Сеть
  • Базы данных
  • параллелизм

И на этом пути вы также создали дополнительные инструменты, которые можно повторно использовать в других проектах:

  • Регистратор
  • Диспетчеры

В этой главе вы узнаете, как создать и опубликовать библиотеку, чтобы вы могли повторно использовать ее в других приложениях, которые вы разработаете в этой книге, и в следующем, которое вы собираетесь создать. :]

Перенос существующей функции на мультиплатформу

Из этой книги вы узнали, как разработать проект, в котором библиотека уже используется на разных платформах. Однако вы можете перенести существующее приложение на Kotlin Multiplatform.

В этом разделе вы увидите, как такую ​​простую функцию, как открытие ссылки на веб-сайт в браузере, можно легко перенести в KMP.

Учимся открывать ссылку на разных платформах

В Learn при нажатии на статью открывается веб-страница — будь то Android, iOS или настольный компьютер. Поведение одинаково на всех трех платформах, хотя реализация совершенно разная.

В Android отображается подсказка, чтобы вы могли выбрать, какое приложение следует использовать для отправки Intent . Или, если он уже установлен по умолчанию, он автоматически откроет его и загрузит статью, на которую вы нажали. MainActivity.kt в androidApp/ui определяет эту функцию:

private fun openEntry(url: String) { val intent = Intent(Intent.ACTION_VIEW) intent.data = Uri.parse(url) startActivity(intent) }

Поскольку на устройстве может быть установлено несколько приложений, важно определить, какие приложения могут получить это намерение. В этом сценарии вы ищете приложения, которые могут открывать URL-адрес. Чтобы избежать открытия неправильного приложения, Android позволяет вам определить пару параметров, которые система использует для фильтрации между всеми установленными приложениями, и тот, который лучше всего соответствует вашему намерению . Во- первых, он проверяет те, которые имеют в своем AndroidManifest.xml определенный ACTION_VIEWатрибут, а затем те, которые способны анализировать URI .

У iOS другой подход. Чтобы открыть URL-адрес, вам просто нужно использовать OpenURLAction из среды. Откройте LatestView.swift из модуля iosApp и перейдите к Sectionструктуре:

@Environment(\.openURL) var openURL

var openURLПозволяет отправить URL-адрес, который откроет браузер по умолчанию на вашем устройстве :

openURL(URL(string: "\(item.link)")!)

Когда пользователь нажимает на одну из статей, приложение создает объект URLиз этого элемента linkи вызывает openURLего, чтобы открыть ссылку в браузере.

desktopApp использует другой подход. Desktopимеет browserфункцию, которую вы можете использовать для запуска браузера по умолчанию на вашем компьютере. Откройте Main.kt из модуля desktopApp и прокрутите вниз до конца этого файла:

fun openEntry(url: String) { try { val desktop = Desktop.getDesktop() desktop.browse(URI.create(url)) } catch(e: Exception) { Logger.e(TAG, "Unable to open url. Reason: ${e.stackTrace}") } }

Вызов getDestkopвозвращает экземпляр Desktop, который содержит его контекст, а также пару функций, которые позволяют вам получить доступ к некоторым функциям вашего компьютера, таким как открытие и редактирование файлов, браузер, почта, печать и многое другое. Здесь вы используете, browseчтобы открыть браузер по умолчанию с urlэлементом, на который вы нажимаете.

Блок trycatchнеобходим — согласно документации, на некоторых платформах десктопный API может быть недоступен. Это может привести к нежелательному поведению. Такой подход гарантирует, что в худшем случае приложение хотя и не откроет ссылку, но и не рухнет.

Примечание . В качестве альтернативы вы также isDesktopSupportedможете проверить, доступен ли настольный API. В любом случае будьте осторожны, потому что вызов browseможет вызвать ошибку IOException.

Теперь, когда вы знакомы с тем, как три платформы открывают URL-адрес, пришло время перенести эту логику в KMP.

Добавление нового модуля

Первое, что нужно решить, — хотите ли вы переместить эту логику в существующий общий модуль или создать новый. Поскольку добавление новой библиотеки также требует переноса кода, вы выберете это более полное решение.

Первым шагом является добавление нового модуля KMM . Перейдите в FileNewNew Module… и выберите шаблон Kotlin Multiplatform Shared Module в нижней части списка. Здесь определите:

  • Название модуля : совместное действие
  • Имя пакета : com.raywenderlich.learn.action
  • Распространение фреймворка iOS : XCFramework

Нажмите « Готово » и дождитесь синхронизации проекта. После этого, если вы посмотрите на вкладку Android Studio Project , вы увидите добавленный новый модуль совместного действия .

Откройте файл settings.gradle.kts в корневой папке проекта. Подтвердите, что совместное действие теперь является частью обучения :

include(":shared-action")

Шаблон Android Studio для Kotlin Multiplatform Mobile создает только цели Android и iOS, поэтому вам потребуется вручную добавить платформу рабочего стола.

В модуле общих действий откройте файл build.gradle.kts . В kotlinразделе после listOfцелей iOS добавьте:

jvm("desktop")

Теперь перейдите к sourceSetsи внизу добавьте desktopMainпеременную:

val desktopMain by getting

Синхронизируйте проект и дождитесь завершения этой операции.

Вам все еще нужно добавить папки desktopMain в модуль общих действий . Простое решение для реализации этого — щелкнуть правой кнопкой мыши src и выбрать NewDirectory . Вы увидите новое окно с несколькими предложениями папок. Найдите «рабочий стол» и выберите desktopMain/kotlin .

Теперь вам просто не хватает структуры пакета. Вы можете легко создать этот каталог, щелкнув правой кнопкой мыши desktopMain/kotlin . На этот раз выберите СоздатьПакет . В этом новом окне введите: com.raywenderlich.learn.action .

Вы также можете удалить файлы Platform.kt и Greeting.kt , созданные Android Studio в папках androidMain , commonMain и iosMain .

Вот и все!

Структура вашего проекта будет выглядеть так:

Рис. 14.1 – Структура проекта

Рис. 14.1 – Структура проекта

В зависимости от типа представления, выбранного на вкладке проекта Android Studio , у вас может быть другая древовидная структура. Чтобы увидеть то же самое, выберите опцию « Проект» вверху.

Рис. 14.2 — Представление проекта Android Studio

Рис. 14.2 — Представление проекта Android Studio

Настройка библиотеки Android для публикации

Чтобы опубликовать библиотеки Android, вам необходимо обновить android()целевое определение в kotlinразделе файла build.gradle.kts с shared-action на:

android { publishLibraryVariants("release", "debug") }

Если вы не укажете Android для публикации своих библиотек, ваш проект по умолчанию будет использовать библиотеку, созданную для рабочего стола. Это возможно, поскольку JVM поддерживает Android. Однако это не сработает, потому что специфичный для платформы код на обеих платформах совершенно разный.

Настройка мультиплатформенного пакета Swift

У вас есть разные возможности для создания библиотеки. Поскольку у Apple есть собственный менеджер пакетов — Swift Package Manager — и многие библиотеки теперь доступны через него, вы будете использовать его в этой главе.

Однако официального плагина для создания пакета Swift из проекта KMM не существует. Итак, вам нужно будет использовать плагин Multiplatform Swift Package . В стартовом проекте у вас есть папка plugins , содержащая обновленную версию этой библиотеки. Откройте файл settings.gradle.kts , чтобы включить его в проект:

includeBuild("plugins/multiplatform-swiftpackage-m1_support")

Примечание . Эта настроенная версия подключаемого модуля поддерживает архитектуру Apple M1 и использует внутренние функции KMM XCFramework для создания фреймворков.

Синхронизируйте проект. Теперь откройте build.gradle.kts из shared-action и добавьте в pluginsраздел:

id("com.chromaticnoise.multiplatform-swiftpackage-m1-support")

Вы можете определить пару параметров для настройки вашего пакета Swift. Для этого добавьте перед kotlinразделом:

//1 multiplatformSwiftPackage { //2 xcframeworkName("SharedAction") //3 swiftToolsVersion("5.3") //4 targetPlatforms { iOS { v("13") } } //5 outputDirectory(File(projectDir, "sharedaction")) }

Вот что происходит:

  1. Это функция, которая позволяет вам настроить сгенерированный пакет Swift.
  2. Вы можете определить конкретное имя для сгенерированного фреймворка, установив расширение xcframeworkName. В противном случае по умолчанию будет использоваться имя модуля.
  3. Как видно из названия, оно соответствует версии инструментов Swift, необходимой для сгенерированного пакета.
  4. targetPlatformsопределяет, какие платформы и версии ОС должна поддерживать платформа. В этом случае он будет работать на всех устройствах iOS и симуляторах с версией 13 или новее.
  5. По умолчанию swiftpackage является выходной папкой пакета Swift. Вы можете определить другое местоположение и имя с помощью outputDirectoryпараметра.

Этот плагин позволяет вам генерировать манифест диспетчера пакетов Swift и XCFramework, которые вы можете использовать в iosApp .

Чтобы Framework сгенерировался как «SharedAction», вам необходимо дополнительно установить XCFrameworkимя и его baseName. Перейдите в целевой раздел iOS и обновите:

val xcf = XCFramework("SharedAction") listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { it.binaries.framework { baseName = "SharedAction" xcf.add(this) } }

Синхронизируйте проект. Откройте терминал и в корневой папке проекта запустите:

./gradlew shared-action:createSwiftPackage

Тебе следует увидеть:

ПОСТРОИТЬ УСПЕШНО

Посмотрите на папку с общими действиями . Вы увидите новый каталог sharedaction , который содержит только один файл: Package.swift . Поскольку проект не содержит никакого кода, XCFramework не были сгенерированы.

Создайте файл PlatformAction.kt внутри shared-action/commonMaincreateSwiftPackage и снова выполните команду.

После его выполнения вернитесь в папку sharedaction . Теперь у вас есть XCFramework для симулятора arm64 и arm64_x86_-_64 .

Вот и все! Ваш модуль готов к созданию пакетов Swift.

Вы также можете сделать такое же обновление для общего модуля. Подобно тому, что вы сделали с shared-action , откройте файл shared/build.gradle.kts и добавьте plugin:

id("com.chromaticnoise.multiplatform-swiftpackage-m1-support")

И тогда это конфигурация:

multiplatformSwiftPackage { xcframeworkName("SharedKit") swiftToolsVersion("5.3") targetPlatforms { iOS { v("13") } } }

Приведенная выше команда позволяет вам создать пакет Swift только для модуля совместного действия . Если вы хотите сгенерировать для обоих общих модулей, вы можете легко это сделать, не добавляя имя библиотеки в качестве префикса:

./gradlew createSwiftPackage

Перенос кода на мультиплатформу

Теперь, когда вы все настроили, пришло время перенести код из пользовательского интерфейса приложения в мультиплатформенный. Поскольку модуль совместного действия будет обрабатывать действие пользователя по открытию ссылки, в PlatformAction.kt , который вы создали внутри commonMain , добавьте:

public expect object Action { public fun openLink(url: String) }

Это объект, который будет вызывать пользовательский интерфейс.

Кроме того, вы можете просто определить openLinkфункцию, не добавляя ее в object:

public expect fun openLink(url: String)

Вы можете вызвать эту функцию непосредственно из androidApp и desktopApp , так как вы ссылаетесь на нее напрямую. Однако из iosApp вам нужно будет получить к нему доступ через:

PlatformActionKt.openLink(url: "\(item.link)")

Поскольку класс не определен, компилятор создает его при создании фреймворка и использует в качестве имени имя класса плюс расширение файла.

Хотя вы можете определить другое имя, у вас всегда будет префикс kt — не самое сочувствующее имя, особенно когда вы пытаетесь убедить команду iOS принять общий модуль, написанный на Kotlin. :]

Android Studio предложит автоматически сгенерировать отсутствующие файлы. Игнорируйте это пока. В некоторых версиях IDE эта функция не работает должным образом и приводит к созданию файлов в неправильных каталогах. Чтобы избежать непредвиденных ошибок, вы добавите все эти файлы вручную.

Создайте файл PlatformAction.kt для androidMain , iosMain и desktopMain . Все они должны находиться в одном каталоге для каждой из платформ: com.raywenderlich.learn.action .

Определите пустую actualфункцию:

public actual object Action { public actual fun openLink(url: String) {} }

Реализуйте openLinkфункции для разных целей:

  • androidApp : откройте файл MainActivity.kt и прокручивайте, пока не увидите openEntryфункцию. Скопируйте его содержимое и вставьте в openLinkфункцию, которую вы создали в shared-action/androidMain :

public actual fun openLink(url: String) { val intent = Intent(Intent.ACTION_VIEW) intent.data = Uri.parse(url) startActivity(intent) }

Так как этот блок кода существует вне области видимости Activity , вам нужен его Context для вызова startActivity. Чтобы преодолеть это, вы собираетесь объявить activityContextпеременную вне Actionобъекта:

public lateinit var activityContext: Context

Теперь обновите startActivityвызов:

activityContext.startActivity(intent)

У вас есть доступ к Android SDK, поэтому для вышеуказанной функции вам потребуется импортировать:

import android.content.Context import android.content.Intent import android.net.Uri

  • desktopApp : перейдите к файлу Main.kt и найдите openEntry. Скопируйте его содержимое в openLinkфункцию из shared-action/desktopMain .

public actual fun openLink(url: String) { try { val desktop = Desktop.getDesktop() desktop.browse(URI.create(url)) } catch(e: Exception) { Logger.e(TAG, "Unable to open url. Reason: ${e.stackTrace}") } }

Класс Loggerпринадлежит общему модулю, который вы не используете в share-action . Чтобы решить эту проблему, вы можете сделать одно из следующих действий:

  • Замените вызов на использование printlnвместо этого.
  • Добавьте общую библиотеку в качестве зависимости. Однако это чрезмерно, так как вы в конечном итоге увеличите размер приложения с ненужными функциями.
  • Создайте библиотеку логгеров и добавьте ее в shared-action .

Пока вы будете следовать первому подходу. Тем не менее, третий заманчив, поэтому не забудьте выполнить первое задание этой главы, а затем вернуться к этому шагу и заменить printlnфункцию на Logger. :]

Замените текущий Loggerвызов на:

println("Unable to open url. Reason: ${e.stackTrace}")

И импорт:

import java.awt.Desktop import java.net.URI

  • iosApp : откройте файл HomeView.swift и найдите openURL. Вы найдете два результата: первый объявляет переменную из Environment, а второй — ее вызов.

Переместить эту логику в shared-action/iosMain сложнее, чем предыдущие, потому что вам нужно будет преобразовать этот код в Kotlin и найти соответствующие функции iOS.

Важно помнить, что хотя вы пишете код Swift, KMM использует подписи Objective-C. Вот почему вы используете NSLog в файле PlatformLogger.kt из shared/iosMain .

Иногда может быть трудно найти модуль определенной функции. Нативные библиотеки имеют ту же структуру, что и библиотеки iOS SDK, поэтому первый шаг — перейти на официальный сайт документации и изменить его на Objective-C:

Рис. 14.3 — Документация Apple по функции OpenURL

Рис. 14.3 — Документация Apple по функции OpenURL

На этом изображении вы можете найти openURLдокументацию:

  1. Эти точки показывают вам путь, где находится openURL . Вы можете увидеть, что UIApplication принадлежит UIKit , если вы нажмете на них. Итак, чтобы получить доступ к этой функции из iosMain , вам нужно импортировать:

import platform.UIKit.UIApplication

  1. Откройте страницу UIApplication . Согласно документации, UIApplication — это синглтон, к которому вы можете получить доступ через sharedApplication. Поэтому для доступа к openURL нужно вызвать:

UIApplication.sharedApplication.openURL(url)

  1. Этот раскрывающийся список позволяет переключаться между Swift и Objective-C.

Примечание : вы можете увидеть все классы, которые существуют внутри платформы , если вы перейдете в kotlin-native репозиторий JetBrains .

Теперь, когда вы узнали, как реализовать openURL, вернитесь к PlatformAction.kt из shared-action/iosMain и обновите существующую openLinkфункцию следующим образом:

public actual fun openLink(url: String) { val application = UIApplication.sharedApplication val nsurl = NSURL(string = url) if (!application.canOpenURL(nsurl)) { println("Unable to open url: $url") return } application.openURL(nsurl) }

При появлении запроса импортируйте следующие библиотеки:

import platform.Foundation.NSURL import platform.UIKit.UIApplication

Примечание . В настоящее время в Android Studio для Mac M1 существует проблема, из-за которой platformпакет, похоже, не решен. Другими словами, вы можете увидеть platformимпорт вместе с вызовами UIApplicationи NSURLв красном цвете. Если это так, не беспокойтесь — вы без проблем скомпилируете проект.

Вот и все! Чтобы скомпилировать проект и сгенерировать JVM, библиотеки Android и XCFramework, запустите:

./gradlew assemble

И чтобы сгенерировать пакет Swift (общий и с общим действием), запустите:

./gradlew createSwiftPackage

Теперь у вас есть две библиотеки, которые вы можете опубликовать!

Добавление новой библиотеки в проект

Перед публикацией библиотеки важно отметить, что вы можете включить ее в свои приложения двумя разными способами:

Добавить как новую зависимость

На том же уровне, что и shared , вы включаете его в файлы build.gradle.kts для Android и рабочего стола и добавляете его в проект приложения iOS.

В файле androidApp , а затем в файле build.gradle.kts приложения desktopApp в dependenciesразделе после общей реализации добавьте:

implementation(project(":shared-action"))

Синхронизируйте проект.

Для iOS нужно сначала открыть проект с помощью Xcode . Помните, что вы должны загрузить файл iosApp.xcworkspace .

Чтобы упростить процесс, выполните следующие действия:

  1. Откройте файл проекта и щелкните вкладку « Общие » вверху.
  2. Прокрутите вниз до Frameworks, Libraries и Embedded Content и щелкните значок плюса под SharedKit.xcframework .
  3. Откроется новое окно с просьбой выбрать фреймворк. Нажмите « Добавить другое… », затем «Добавить файлы…».
  4. Перейдите к ./shared-action/sharedaction/ , выберите SharedAction.xcframework и нажмите « Открыть » .

В настоящее время общий доступ добавляется с помощью embedAndSignAppleFrameworkForXcodeкоманды из Run Script . При желании вы можете удалить его и добавить вручную, следуя тому же процессу, что описан выше.

В ваш Xcode будут добавлены оба фреймворка:

Рис. 14.4 — Вид проекта XCode

Рис. 14.4 — Вид проекта XCode

Включить внутрь общего модуля

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

Этот шаг сделать проще — в этом случае нужно просто добавить Shared-Action как реализацию в файл Shared Module build.gradle.kts в разделе commonMain dependencies:

implementation(project(":shared-action"))

Чтобы иметь более строгое разделение проблем, вы будете следовать первому варианту для обучения .

Обновление приложений для использования новой библиотеки

С новой библиотекой, доступной для всех платформ, пришло время заменить существующую логику вызовами openLinkфункции из shared-action .

В androidApp откройте файл MainActivity.kt и обновите openEntryфункцию до:

private fun openEntry(url: String) { activityContext = this openLink(url) }

То activityContext, что вы устанавливаете здесь, будет использоваться для открытия нового действия из shared-action .

Кроме того, не забудьте удалить импорт:

import android.net.Uri

Следующее обновление, которое вам нужно сделать, — это файл Main.kt в проекте desktopApp . При вызове MainScreenComposable обновите onOpenEntryвызов до:

onOpenEntry = { openLink(it) },

При этом вы будете использовать функцию совместного действия , чтобы открыть статью в браузере по умолчанию. Теперь вы можете удалить openEntryв конце этого файла и удалить теперь ненужные импорты:

import java.awt.Desktop import java.net.URI import java.net.URISyntaxException

Чтобы обновить приложение iOS, переключитесь на Xcode и выполните такое же обновление для следующих файлов:

  • RWEntryRow.swift
  • LatestView.swift

Удалить openURLобъявление:

@Environment(\.openURL) var openURL

Замените Buttonдействие при переборе items, from openURLto:

Action().openLink(url: "\(item.link)")

Не забудьте импортировать структуру совместного действия:

import SharedAction

И удалите urlпеременную, которая больше не нужна.

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

В зависимости от вашего браузера по умолчанию вы увидите экраны, похожие на эти:

Рис. 14.5 – Android-приложение: открытие статьи

Рис. 14.5 – Android-приложение: открытие статьи

Рис. 14.6 — Настольное приложение: Открытие статьи

Рис. 14.6 — Настольное приложение: Открытие статьи

Рис. 14.7 — Приложение для iOS: открытие статьи

Рис. 14.7 — Приложение для iOS: открытие статьи

Публикация вашей библиотеки KMP

Во всех проектах, которые вы разработали на протяжении всей этой книги, и общий модуль, и приложения находились в одном репозитории. Это упростило погружение в Kotlin Multiplatform и позволило избежать настройки нескольких репозиториев.

При этом вы можете легко импортировать любой из них, просто включив его в файл settings.gradle.kts , расположенный в корневом каталоге проекта:

include(":androidApp") include(":desktopApp") include(":shared") include(":shared-action") include(":pager") include(":pager-indicators") include(":precompose")

Каждый из этих includes представляет проект, который может находиться в другом репозитории. Если бы они были у вас в виде отдельного репозитория, вам также нужно было бы указать путь к проекту:

include(":your-library") project(":your-library").projectDir = file("../path/to/your-library")

Оба сценария имеют пару недостатков:

  • Конфигурация трудоемкая. Вам нужно добавить проекты как в settings.gradle.kts, так и в build.gradle.kts проекта, который будет их использовать.
  • Более высокое время сборки — особенно при первой сборке проекта. Это происходит потому, что в этот момент нет скомпилированной библиотеки.
  • В этих проектах нет версий. Если вы хотите использовать более старую версию проекта, вам необходимо вручную оформить заказ.

В качестве альтернативы обоим сценариям вместо включения этих модулей вы можете импортировать его библиотеки либо из локального репозитория maven, либо с удаленного сервера.

В этом разделе вы опубликуете ранее созданную библиотеку общих действий .

Настройка библиотеки

Вы можете получить доступ к библиотеке в любом репозитории через ее группу, имя и номер версии со следующей номенклатурой:

  • группа:имя:версия

Имя проекта — это имя папки, в данном случае — shared-action . Вы можете определить группу и версию в файле build.gradle.kts из shared-action .

Чтобы установить версию, добавьте следующий параметр в build.gradle.kts :

version = "1.0"

group, если он не определен, использует родительское имя . В этом случае это будет учиться . Это может ввести в заблуждение, так как нет информации об авторе. Чтобы преодолеть это, выше versionдобавьте:

group = "com.raywenderlich.shared"

Как опубликовать библиотеку локально

Откройте файл build.gradle.kts из shared-action и в конце раздела плагина добавьте:

id("maven-publish")

А теперь, чтобы опубликовать его локально, запустите на терминале:

./gradlew shared-action:publishToMavenLocal

Когда операция завершится, в журналах консоли появится сообщение BUILD SUCCESSFUL .

Если вы хотите опубликовать все свои библиотеки локально, вам следует запустить:

./gradlew publishToMavenLocal

Расположение по умолчанию для вашего локального репозитория maven:

~/.m2/repository

Перейдите в эту папку, и вы увидите каталог com/raywenderlich/shared с библиотекой общих действий для разных платформ внутри.

Вернитесь в Android Studio. Прежде чем продолжить, удалите модуль совместного действияinclude из settings.gradle.kts :

include(":shared-action")

В корне учебного проекта откройте build.gradle.kts . В разделе после добавьте:allprojects``repositories``google()

mavenLocal()

В следующий раз, когда Gradle синхронизируется, он также будет искать зависимости проекта в вашем каталоге .m2/repositories .

Вам просто не хватает обновления зависимостей приложения. Откройте файлы build.gradle.kts из androidApp и desktopApp и замените запись:

implementation(project(":shared-action"))

который ищет project, с:

implementation("com.raywenderlich.shared:shared-action:1.0")

Вместо этого используется библиотека.

Скомпилируйте приложения для Android и ПК и откройте статью из списка.

Рис. 14.8 — Приложение для Android: поиск всех статей для Android

Рис. 14.8 — Приложение для Android: поиск всех статей для Android

Рис. 14.9 — Настольное приложение: Поиск всех статей Android

Рис. 14.9 — Настольное приложение: Поиск всех статей Android

Как опубликовать библиотеку в репозитории GitHub Packages

Существует набор репозиториев, которые вы можете использовать для публикации своих библиотек: JitPack , Maven Central и GitHub Packages . Это самые распространенные. Или вы всегда можете настроить свой собственный репозиторий пакетов.

В зависимости от выбранного репозитория процесс настройки должен быть аналогичен представленному в этом разделе. Как правило, различия заключаются в URL-адресе, который вы используете для подключения, и в требуемой аутентификации.

Здесь вы собираетесь использовать пакеты GitHub — в основном потому, что их просто настроить и есть бесплатный уровень, который вы можете использовать. Вам просто нужно создать учетную запись.

Прежде чем вы сможете опубликовать библиотеку, вам нужно сначала создать токен доступа, который Gradle будет использовать для аутентификации вашей учетной записи.

Создайте свой токен доступа

Войдите в GitHub и перейдите в настройки своего аккаунта . Вы можете увидеть эту опцию, нажав на свой аватар в правом верхнем углу веб-сайта. Затем прокрутите страницу вниз, пока слева не увидите Настройки разработчика, и щелкните там. Вы будете перенаправлены на новый экран. Оттуда перейдите в «Токены личного доступа» и затем «Создать новый токен » .

Или вы можете перейти прямо по этой ссылке .

На этом экране вы можете настроить имя для вашего токена, как долго он будет действовать и какие разрешения у него должны быть. Для имени добавьте: Опубликовать репозиторий Maven и установите флажки write:packages и read:packages .

Он автоматически выберет атрибут репо . Ваш экран будет похож на этот:

Рис. 14.10 — Конфигурация токена GitHub

Рис. 14.10 — Конфигурация токена GitHub

Примечание . Важно выбрать имя, которое впоследствии легко запомнить. Это помогает, когда вы получаете электронное письмо от GitHub, в котором говорится, что срок действия вашего токена истекает, и вам нужно решить, хотите ли вы его продлить или нет.

Щелкните Создать токен . Скопируйте токен аутентификации.

Создать новый репозиторий

Чтобы опубликовать свои библиотеки, вам нужен репозиторий для их отправки. Если у вас его нет, перейдите на главную страницу GitHub и нажмите « Создать » , чтобы создать новый репозиторий.

Кроме того, вы можете перейти прямо по этой ссылке .

Напишите имя репозитория — например, совместное действие — решите, хотите ли вы сделать его общедоступным или частным, и установите флажок « Добавить файл README », чтобы для вас уже была создана ветвь.

Опубликуйте свою библиотеку

Подготовив репозиторий пакетов GitHub, вернитесь в Android Studio и откройте файл gradle.properties , расположенный в корневом каталоге. Здесь добавьте имя пользователя вашей учетной записи и токен, который вы скопировали ранее:

#Repository Credentials mavenUsername=YOUR_USERNAME mavenPassword=YOUR_TOKEN

Это учетные данные, которые Gradle будет использовать для аутентификации.

Откройте файл build.gradle.kts из модуля общих действий и прокрутите вниз.

После multiplatformSwiftPackageдобавь:

publishing { repositories { maven { //1 url = uri("https://maven.pkg.github.com/YOUR_USERNAME/YOUR_REPOSITORY") //2 credentials(PasswordCredentials::class) authentication { create<BasicAuthentication>("basic") } } } }

Эта задача Gradle отвечает за публикацию ваших библиотек по указанному вами URL-адресу. Он использует BasicAuthenticationв качестве механизма аутентификации:

  1. В этом URL вам необходимо определить:
  • YOUR_USERNAME: как следует из названия, это имя пользователя вашей учетной записи GitHub.
  • YOUR_REPOSITORY: имя репозитория, которое вы выбрали ранее. Если вы следовали тому же соглашению об именах, это должно быть совместное действие .
  1. Gradle поддерживает различные типы аутентификации. Вы можете найти все эти методы на их веб-сайте документации . Смотрит PasswordCredentials::classна mavenUsernameи mavenPasswordдля проверки подлинности запроса.

Кроме того, вы можете определить эти переменные прямо здесь, заменив credentialsна:

credentials { name = YOUR_USERNAME password = YOUR_TOKEN }

Рекомендуется хранить их в отдельном файле, который следует добавить в файл .gitignore , чтобы избежать неосознанной передачи учетных данных в репозиторий.

Прежде чем опубликовать свою библиотеку, вам нужно еще раз добавить ее в файл settings.gradle.kts . Откройте его и после общего добавления:

include(":shared-action")

Теперь, когда все готово, подойдите к терминалу и введите:

./gradlew shared-action:publish

Когда эта операция завершится, вы увидите сообщение BUILD SUCCESSFUL в консоли. Откройте страницу репозитория GitHub, и справа вы увидите раздел Packages , в котором должен быть список библиотек, которые вы только что загрузили. Перейдите в раздел «Пакеты», и вы увидите экран, похожий на этот:

Рис. 14.11 — Опубликованные библиотеки GitHub

Рис. 14.11 — Опубликованные библиотеки GitHub

Теперь, когда вы убедились, что ваши библиотеки были успешно загружены, вернитесь в Android Studio и в файле build.gradle.kts , расположенном в корневом каталоге, добавьте следующий код после mavenCentral, который находится внутри allProject/repositoriesраздела:

maven { url = uri("https://maven.pkg.github.com/cmota/shared-action") credentials(PasswordCredentials::class) authentication { create<BasicAuthentication>("basic") } }

Ранее вы определили URL-адрес для публикации ваших библиотек. Теперь вы добавляете в список репозиториев, которые Gradle должен учитывать при загрузке зависимостей проекта.

Примечание . Чтобы использовать учетные данные, которые вы определили в gradle.properties , вам необходимо mavenобъявить этот репозиторий над репозиторием от JetBrains. В противном случае вы получите сообщение об ошибке, связанное с отсутствием учетных данных. Это связано с множественным объявлением репозиториев maven. Gradle автоматически сопоставляет репозитории maven, добавленные с учетными данными в gradle.properties , поэтому первый соответствует mavenUsername/mavenPassword, второй — maven2Username/maven2Passwordи так далее.

Вот и все! Проект готов. Скомпилируйте и запустите оба приложения: Android и рабочий стол.

Рис. 14.12 — Android-приложение: просмотр последних статей

Рис. 14.12 — Android-приложение: просмотр последних статей

Рис. 14.13 — Настольное приложение: просмотр последних статей

Рис. 14.13 — Настольное приложение: просмотр последних статей

Как опубликовать свой пакет Swift

Если ваш репозиторий GitHub уже настроен из раздела выше, вы также можете использовать его для публикации своего пакета Swift.

Откройте терминал и запустите:

./gradlew shared-action:createSwiftPackage

Когда сборка завершится, вы увидите каталог SharedAction внутри модуля Shared-Action , который содержит ваши фреймворки. Скопируйте содержимое этой папки в свой репозиторий GitHub и отправьте эти файлы.

В корне репозитория у вас должны быть следующие файлы:

  • SharedAction.xcframework .
  • Пакет.swift .
  • README.md .
  • SharedAction-1.0.zip

Примечание . Вы не можете хранить их в папке. В противном случае вы не сможете легко добавить их в свой проект.

Откройте Xcode, перейдите в «Проект» и выберите вкладку « Общие ». Прокрутите вниз до Frameworks, Libraries и Embedded Content и, если вы все еще используете локальную платформу SharedAction , удалите ее.

Затем нажмите « + », затем « Добавить зависимость пакета » в нижнем раскрывающемся списке. Откроется новое окно, и вы можете ввести URL-адрес вашего репозитория в правом верхнем углу. В зависимости от видимости Xcode может запросить у вас учетные данные GitHub.

Вы увидите экран, похожий на этот:

Рис. 14.14 — XCode добавляет пакет Swift из пользовательского URL-адреса

Рис. 14.14 — XCode добавляет пакет Swift из пользовательского URL-адреса

В раскрывающемся списке « Добавить в проект » выберите iosApp , а затем « Добавить пакет » . Xcode загрузит вашу библиотеку.

Если все работает должным образом, вы увидите второе приглашение с просьбой подтвердить добавление пакета SharedAction или нет:

Рис. 14.15 — XCode добавляет пакет Swift: Подтвердить

Рис. 14.15 — XCode добавляет пакет Swift: Подтвердить

Щелкните Добавить пакет . Когда эта операция завершится, вы увидите, что в проект добавлена ​​платформа SharedAction .

Скомпилируйте и запустите приложение. Готовы к прочтению новые статьи!

Рис. 14.16 — Приложение для iOS: просмотр последних статей

Рис. 14.16 — Приложение для iOS: просмотр последних статей

Проблемы

Вот несколько задач, которые помогут вам попрактиковаться в том, что вы узнали в этой главе. Если вы застряли на каком-либо этапе, взгляните на решения в материалах к этой главе.

Задача 1: создать регистратор

Все приложения и общий модуль используют класс Logger , определенный в файле shared/PlatformLogger.kt . Это простой регистратор, который вызывает:

  • Android, android.util.Log .
  • Рабочий стол, println .
  • iOS, платформа.Foundation.NSLog .

В этом первом задании создайте и опубликуйте новую библиотеку — shared-logger — которая должна содержать реализацию PlatformLogger.kt для всех трех платформ: Android, настольных компьютеров и iOS.

Задача 2: интегрировать библиотеку регистратора

На протяжении всей этой книги вы создали три разных приложения:

  • Найдите time , помощник часового пояса, в Разделе 1.
  • Organize , многоплатформенное приложение TODO, в разделе 2.
  • Learn , средство чтения RSS-каналов для статей raywenderlich.com, в Разделе 3.

У каждого из них была настроенная версия регистратора. Вторая задача — использовать библиотеку, созданную в ходе первой задачи, во всех трех приложениях. Не забудьте внести изменения как на уровне бизнес-логики, так и на уровне пользовательского интерфейса.

Задача 3: Используйте библиотеку логгеров в модуле общих действий

В начале этой главы вы успешно перенесли функции открытых ссылок на Kotlin Multiplatform и создали модуль совместного действия .

В то время не было класса регистратора, поэтому вы использовали printlnфункцию в качестве регистратора модуля. С недавно созданным shared-logger пришло время обновить shared-action и использовать вашу новую библиотеку.

Ключевые моменты

  • Если функции, которые вы хотите перенести в KMP, имеют какой-либо код для конкретной платформы, вам необходимо написать эту конкретную логику для всех платформ, на которые будет ориентирована ваша библиотека.
  • В вашем проекте может быть несколько библиотек KMP, и даже библиотека KMP может включать еще одну.
  • Чтобы опубликовать библиотеку для Android и рабочего стола, вы можете опубликовать ее локально или в удаленном репозитории пакетов, который поддерживает обе платформы (.jar и .aar). В этой книге вы увидели, как использовать JitPack.
  • Для iOS вы создаете пакет Swift для совместного использования своей библиотеки. Apple требует, чтобы эти платформы были доступны через репозиторий Git, который может быть локальным или удаленным.

Куда пойти отсюда?

Поздравляем! Вы закончили последнюю главу книги. Из этой книги вы узнали, как создать три приложения для Android, iOS и рабочего стола!

Вы начали это путешествие, познакомившись с Jetpack Compose и Swift UI для разработки пользовательского интерфейса, и перешли к совместному использованию бизнес-логики вашего приложения на этих трех платформах с помощью Kotlin Multiplatform. Теперь вы можете создать приложение с нуля и применить все эти новые концепции или перенести уже написанное на KMP.

Теперь, когда вы являетесь мастером Kotlin Multiplatform, вам может быть интересно, что читать дальше. Возможно, вы хотите глубже погрузиться в Jetpack Compose и SwiftUI ?

Или вы предпочитаете вместо этого сидеть сложа руки и смотреть видеокурс? Вы можете увидеть приложения Jetpack Compose и Ваше второе iOS & SwiftUI приложение, которые учат вас тем же концепциям, что и книги.

Кроме того, поскольку вы уже знакомы с Ktor, почему бы не попробовать его на другой платформе? Тот, который не требует от вас разработки пользовательского интерфейса: Server-Side Kotlin с Ktor.