Русский
Русский
English
Статистика
Реклама

Создание SDK под Android в стиле Single-Activity

Single activity подходом при создании конечного приложения под Android никого не удивишь. Но мы пошли дальше и использовали No-Activity при разработке SDK. Сейчас разберемся для чего это понадобилось, возникшие сложности и как их решали.

Стандартные 3rd party SDK в Android

Как обычно работают внешние SDK в Android? Открывается Activity библиотеки, выполняется некая работа, при необходимости возвращается результат в onActivityResult.

Стандартная схема работы SDK.Стандартная схема работы SDK.

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

Желаемый стек экранов приложения и SDKЖелаемый стек экранов приложения и SDK

Получается, что экраны нашего SDK должны быть частью внешнего приложения. Точно также, как вы можете использовать, например, MapFragment от Google. Итого, при стандартном подходе, мы сталкиваемся с рядом трудностей и ограничений.

Проблемы при стандартном подходе к SDK

  • Если вам нужно несколько взаимодействий между SDK и приложением, то придется открывать-закрывать Activity от SDK и аккуратно обрабатывать передачу данных туда-обратно.

  • Сложно поддержать такой логический порядок экранов, когда элементы приложения чередуются с SDK. (Спойлер: это можно понадобится, но редко).

  • При относительно долгом возможном нахождении в SDK внешнее приложение может уйти в Lock Screen. Такое может случиться, если Lock реализован на колбеках жизненного цикла Activity.

No-Activity подход при разработке SDK

Итак, мы решили, что основная проблема в том, что контекст (Activity) внешнего приложения и SDK разные. Отсюда следует резонное решение - отказаться от контекста SDK и во внешнее приложение поставлять только фрагменты. В таком случае разработчик сможет сам управлять стеком экранов.

No-Activity SDK на ФрагментахNo-Activity SDK на Фрагментах

Данный подход имеет как ряд плюсов, так и значительные минусы. Какие же?

Плюсы No-Acitivty SDK

  • Приложение и SDK имеют общий контекст, т.е. для пользователя это выглядит как абсолютно единое приложение.

  • Основное приложение имеет свой стек фрагментов, а SDK - свой через childFragmentManager.

  • Можно организовать любой порядок экранов и наложений элементов, т.к. навигация доступна и для внешнего приложения.

Минусы No-Acitivty SDK

  • Внешнее приложение должно изначально работать с фрагментами, желательно вообще быть Single-Activity.

  • У SDK нет своего контекста, если хотите использовать dagger - придется исхитриться (но это все же возможно).

  • SDK может влиять на внешнее Acitivty, т.к. requireActivity вернет именно его. Надо полностью доверять SDK.

  • Activity будет получать onActivityResult, и, вероятно, придется его прокидывать во фрагменты.

  • Разработчику внешнего приложения сложнее интегрировать SDK, т.к. простой вызов Activity уже не сработает.

Использование 3rd party библиотек внутри SDK

При любом подходе так или иначе придется использовать библиотеки внутри SDK. Это в свою очередь может привести к коллизии версий с внешним приложением. А части библиотек, например dagger2 нужен будет выделенный контекст.

Dagger2 внутри SDK

Для использования dagger зачастую в приложении используется класс Application. В случае с SDK так сделать не получится, потому что Application, вероятно, будет перетерт со стороны внешнего приложения.

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

internal object ComponentHolder {    lateinit var appComponent: SdkAppComponent        private set    @Synchronized    fun init(ctx: Context) {        if (this::appComponent.isInitialized) return        appComponent = DaggerSdkAppComponent            .builder()            .sdkAppModule(SdkAppModule(ctx))            .build()    }}

Остается только лишь понять, откуда вызвать init, да так, чтобы в процессе жизни SDK быть уверенным, что инициализация выполнилась до любой другой работы. Для этого можно использовать одну точку входа в SDK. Назовем ее EntryPointFragment. Данный фрагмент и будет виден внешнему приложению как единственная точка входа в SDK. Вся дальнейшая навигация внутри SDK будет происходить уже в нем через childFragmentManager.

Как раз при создании EntryPointFragment можно и инициализировать ComponentHolder для Dagger.

override fun onCreate(savedInstanceState: Bundle?) {        ComponentHolder.init(requireActivity())        ComponentHolder.appComponent.inject(this)        super.onCreate(savedInstanceState)    }

Итого, на выходе мы получили ComponentHolder, который можно использовать внутри SDK для инъекции нужных компонент.

Устранение коллизии в версиях

С данной проблемой столкнулись при обновлении версии okhttp3 до новой major версии 4.+. В ней добавили улучшенную поддержку Kotlin, в том числе, например, доступ к коду ошибки через code() теперь стало ошибкой. Клиенты SDK, используя либо 3, либо 4 версию должны получать ту же внутри SDK, иначе все сломается.

Это реально сделать, вынеся код с коллизиями в отдельный модуль. В нем будут 2 flavor:

    flavorDimensions("okhttpVersion")    productFlavors {        v3 {            dimension = "okhttpVersion"        }        v4 {            dimension = "okhttpVersion"        }    }        dependencies {        v3Api okhttp3.core        v3Api okhttp3.logging        v4Api okhttp4.core        v4Api okhttp4.logging}

В двух разных папках, отвечающих за каждый flavor будут одинаковые классы, один из которых будет использовать code() а другой code.

// Code in v3 folderclass ResponseWrapper(private val response: Response) {    val code : Int        get() = response.code()}
// Code in v4 folderclass ResponseWrapper(private val response: Response) {    val code : Int        get() = response.code}

Остается только на уровне приложения выбрать необходимый конфиг и дальше правильная версия приедет в финальный проект.

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

defaultConfig {...missingDimensionStrategy 'okhttpVersion', 'v4'}

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

Заключение

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

Источник: habr.com
К списку статей
Опубликовано: 18.10.2020 04:15:28
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Разработка под android

Android

Sdk

Библиотека

Android development

Android sdk

Android os

Библиотеки

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru