[Разработка под Android] Создание SDK под Android в стиле Single-Activity

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
18-Окт-2020 05:30

Single activity подходом при создании конечного приложения под Android никого не удивишь. Но мы пошли дальше и использовали No-Activity при разработке SDK. Сейчас разберемся для чего это понадобилось, возникшие сложности и как их решали.Стандартные 3rd party SDK в AndroidКак обычно работают внешние SDK в Android? Открывается Activity библиотеки, выполняется некая работа, при необходимости возвращается результат в onActivityResult.
Стандартная схема работы 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-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 folder
class ResponseWrapper(private val response: Response) {
    val code : Int
        get() = response.code()
}
// Code in v4 folder
class ResponseWrapper(private val response: Response) {
    val code : Int
        get() = response.code
}
Остается только на уровне приложения выбрать необходимый конфиг и дальше правильная версия приедет в финальный проект.Подсказка: если вы сами используете свой же модуль в проекте и подключаете как исходники, не забудьте следующее:
defaultConfig {
  ...
  missingDimensionStrategy 'okhttpVersion', 'v4'
}
В таком случае вы избавитесь от конфликта при сборке. Иначе просто версия не найдется.ЗаключениеРазработка SDK, если сравнивать с просто Android приложением, намного сложнее, но порой интереснее. Также требования к качеству конечного продукта выше - если что-то упадет, то упадет не у вас, а у вашего клиента, что прямо очень плохо.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_razrabotka_pod_android (Разработка под Android), #_android, #_sdk, #_biblioteka (библиотека), #_android_development, #_android_sdk, #_android_os, #_biblioteki (библиотеки), #_razrabotka_pod_android (
Разработка под Android
)
Профиль  ЛС 
Показать сообщения:     

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

Текущее время: 23-Ноя 00:37
Часовой пояс: UTC + 5