Как мы делали суперприложение на основе Почты

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Совсем скоро, 3 и 4 сентября в VK пройдёт новый Weekend Offer. В нём будет участвовать и наша команда — мы создаём суперприложение на основе почтового клиента Mail.ru. Хотим подробнее рассказать об этом проекте и о задачах, которые нужно будет решать нашим будущим коллегам :)

Год назад бизнес поставил нам задачу: интегрировать в приложение несколько других сервисов компании, чтобы пользователи могли одним нажатием переходить из сервиса в сервис. Ну, вы и сами знаете, для чего нужны суперы — для развития экосистемы и конкретных продуктов. И спустя два месяца мы запустили в эксплуатацию суперприложение на основе почтового клиента Mail.Ru.

Архитектура

Интегрировать в суперприложение нужно было Облако, Марусю, Новости, Календарь и Задачи, а заодно требовалось создать техническую основу, позволяющую легко и быстро добавлять новые сервисы, как вставить вилку в розетку. Архитектурно мы отказались от конкретного приложения-ядра, и решили сделать так, чтобы хостом суперприложения мог стать любой из мобильных клиентов сервисов.

С точки зрения разработчиков мы хотели сделать универсальный механизм интеграции, чтобы авторам хоста и подключаемых сервисов не нужно было разбираться в устройстве продуктов друг друга, достаточно соответствовать общему набору правил. Задача осложнялась тем, что подключаемые к суперприложению сервисы имели разную реализацию. Кто-то предоставлял готовое SDK (Маруся и Пульс) и достаточно было просто встроить его; какие-то сервисы пришлось подключать через WebView (Календарь и Задачи); а кому-то пришлось писать код с нуля, чтобы интегрироваться в суперприложение (Облако).

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

Модули

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

White label

Также мы подумали о том, что не всем брендам компании могут быть нужны все сервисы, и придумали механизм выборочного исключения из приложения кода определённых вкладок. Для брендов по-отдельности регистрируем поддерживаемые его сервисом функции, и каждый модуль сервиса ссылается только на API-модули и запрашивает доступность определённых функций. Если какая-то функция недоступна, то приложение не показывает соответствующие элементы интерфейса — кнопки, формы и т.д. Например, если в суперприложении не будет вкладки Облака, то не получится приложить облачный файл в форме написания письма в Почте. 

Вкладки и фоновые сервисы

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

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

Приоритизация

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

Навигация

Выше мы упомянули, что вкладки взаимодействуют друг с другом с помощью API. Но есть и второй механизм — переход по ссылкам, deep link-ам. Он предназначен для навигации пользователей между сервисами. Мы придумали формат ссылок, который должны поддерживать все вкладки, и каждая из них может запросить переход по такой ссылке. Тогда суперприложение открывает экран целевого сервиса и, при необходимости, запускает запрошенную функцию. Например, если вы выберете в Облаке файл и нажмёте кнопку «Отправить в письме», то через deep link Облако обратится к Почте, программа откроет форму написания и прикрепит выбранный файл.

Ещё на основе deep link-ов работают кнопки в push-уведомлениях, чтобы можно было прямо из сообщения одним нажатием перейти в соответствующий сервис и запустить фичу.

Работа с зависимостями

В работе мы столкнулись с тем, что все вкладки так или иначе используют общие библиотеки, у которых могут быть разные версии. Иногда возникали несовместимости: какая-нибудь вкладка обновляла внутри себя некую библиотеку, и в результате приложение могло не собраться, либо в runtime могли возникнуть ошибки. Мы решили это с помощью самописного Gradle-плагина, который валидирует версии зависимостей при сборке проекта (включая транзитивные зависимости). У нас имеется эталонный каталог с заданными версиями зависимостей, с которыми приложение работает стабильно. При сборке приложения плагин проверяет, что в итоговую сборку не попали зависимости с версией выше указанной в каталоге. Если такие зависимости будут обнаружены, то сборка завершится с ошибкой. Внедрение плагина позволило нам контролировать обновления библиотек и избежать неявного поднятия их версии.

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

class DependenciesPlugin: Plugin<Project> {
    override fun apply(project: Project) {
        project.configurations.all { action ->
            action.resolutionStrategy.eachDependency { rule ->
                MailResolveStrategy.verifyDependency(rule)
            }
        }
    }
}

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

@JvmStatic
fun verifyDependency(details: DependencyResolveDetails) {
    val group = details.requested.group
    val name = details.requested.name

    val currentVersion: String? = details.requested.version
    val catalogVersion: VersionNumber? = findInCatalog(group, name)?.version

    if (currentVersion != null && catalogVersion != null) {
        val moreRecent = maxOf(VersionNumber.parse(currentVersion), catalogVersion)
        if (moreRecent != catalogVersion) {
            val msg = "$group:$name with version $currentVersion is not allowed " +
                "because its version is greater than version $catalogVersion from the catalog."
            throw RuntimeException(msg)
        }   
    }
}

Аналитика

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

Что мы уже выяснили по результатам анализа метрик? Самое главное — пользователи, активировавшие новую версию, остаются на ней, и частота их взаимодействия с продуктом растёт. Судя по опросам, новинка людям понравилась. Опросы подтвердили удовлетворенность обновлением. После запуска супераппа использование не-почтовых сервисов в приложении выросло более чем в 10 раз.

* * *

Друзья, мы приглашаем Android-разработчиков в нашу команду, работы много — нужно развивать и расширять наше суперприложение. Записывайтесь на Weekend Offer, который пройдёт 3 и 4 сентября, и до скорой встречи!

Источник: https://habr.com/ru/company/vk/blog/684108/


Интересные статьи

Интересные статьи

Некоторое время назад мы искали оптимальное аппаратное и программное обеспечение для исполнения нейронных сетей в ЦОД и "на краю" (edge computing). В рамках нашего исслед...
Решения для больших компаний обычно должны выдерживать высокие нагрузки. Когда в штате много десятков тысяч человек, и значительная доля из них ежедневно пользуются ...
Я давно знаком с Битрикс24, ещё дольше с 1С-Битрикс и, конечно же, неоднократно имел дела с интернет-магазинами которые работают на нём. Да, конечно это дорого, долго, местами неуклюже...
Этот пост будет из серии, об инструментах безопасности, которые доступны в Битриксе сразу «из коробки». Перечислю их все, скажу какой инструмент в какой редакции Битрикса доступен, кратко и не очень р...
Сейчас многие и очень многие люди (обычно их называют аналитиками, но в целом это может быть какая угодно специальность) готовят различные красивые таблицы и графики, на основании которых в иде...