Привет, Хабр! Меня зовут Тимофей, я Android-разработчик в Сравни. Давайте поговорим о кросс-обновлении Android-приложений без привязки к конкретному стору – так, чтобы пользователи могли устанавливать из одного источника, а обновлять – из другого, без необходимости удалять и ставить заново.
Поводы задуматься о подобном сценарии у нас были разные: проработка рисков блокировки приложения в сторах, исследование новых возможностей добавить удобства пользователям, активация дополнительных каналов дистрибуции приложений.
Но первые реальные практические шаги в этом направлении мы сделали в формате
“А что, так можно было?”: пошли выкладывать приложение в RuStore и попутно обнаружили возможности использовать аналогичные механизмы для настройки кросс-обновления.

Расскажу, на какие грабли мы наступили на этом пути и что смогли выяснить в процессе – надеюсь, это поможет вам сделать нечто подобное чуть быстрее и безболезненнее, чем у нас.
Спойлер: чтобы всё это завелось, понадобится версия Android API level не ниже версии 28. Но давайте по порядку.
Что не так с подписью приложения
Центральный персонаж моей истории – подпись. Та самая, из криптографии, которая позволяет идентифицировать авторство программного кода. В случае Android-приложений нужна для публикации и верификации сборки (на всякий случай вспомним её адрес по прописке: AndroidStudio → Build → Generate Signed Bundle / APK).
С главным героем познакомились, теперь перейдём к квесту. Исходная постановка задачи звучала так.
Дано:
minSdk = 28;
приложение опубликовано в Google Play и App Gallery с разными подписями, но одинаковыми id (packageName).
Найти:
удобный способ выложить приложение в RuStore.
Таким образом, на тот момент у нас не было цели на настройку кросс-обновления между сторами (чтобы пользователи могли обновить скачанное ранее из Google Play приложение свеже выложенным из RuStore и наоборот). Но мечта была, в процессе решения задачи это сыграло свою роль; запишем для протокола.
Для распространения в App Gallery используется универсальный Android Package Kit (APK); функция подписания приложения не включена. Для распространения в Google Play используется Android App Bundle (AAB) с включенной функцией Play App Signing. То есть Google берёт наш AAB-файл и нарезает его для всех устройств на оптимизированные для них APK; при этом каждый такой APK подписывает неким ключом.
На первый взгляд всё выглядело просто: достаём из Google Play ключ, которым подписываются все итоговые APK; подписывем им релизный AAB; загружаем в RuStore; .…; profit.
Пробуем, не работает.
Оказывается, в RuStore в то время не было возможности загрузить AAB-файл. Позже такая опция появилась.
* на момент написания этого текста фича находится в бете, но для успеха всё равно нужна будет заветная подпись (об этом ниже).
Вчитываемся глубже в документацию: можно загрузить до 10 APK-файлов, чтобы работать с разными подписями и сервисами пушей. Звучит интересно! Пользуясь случаем – спасибо команде RuStore, что всё время были на связи и помогали разбираться!
Продолжаем вчитываться. Для успешного обновления нашего приложения без ошибок, необходимы два условия:
одинаковый id приложения – подтверждение того, что приложение то же самое;
одинаковая подпись – свидетельство того, что приложение создал тот же разработчик.
До этого момента подпись была для нас штукой, которую ты однажды сгенерировал в студии и потом благополучно забывал о её существовании. Что ж, похоже, настал момент познакомиться с ней поближе.
Открываем матчасть: существует четыре схемы подписей, каждая из которых является деревом Меркела (подробнее тут)… Закрываем матчасть, идём в собачьи парикмахеры думать, как всё сделать проще.
Разговор по душам с Google Play Console (мысленный)
В Google Play Console мы загружаем AAB-файл, подписанный нашим ключом. Читаем, что есть ключ подписи и загрузочный ключ. Как бы нам достать этот ключ подписи? На первый взгляд выглядит, что всё устроено так, чтобы его нельзя было вот так просто взять и заполучить.
При создании приложения и далее (например, для запуска тестирования) Google довольно навязчиво подталкивает разработчиков к тому, чтобы использовать сравнительно новую опцию подписания приложения. Оправдывают это возможностью уменьшить размер скачиваемых APK-файлов за счёт того, что APK оптимизированы под каждое устройство.

Ох уж эти ⚠️ – раздражают, ей-богу!
Все обычно соглашаются, ключ генерируется за пару секунд, и никто о нём не вспоминает до момента начала распространения приложения в других магазинах.
Мысленно у меня в голове состоялся примерно следующий разговор с Google Play Console (GPC):
Я: Но ведь ключ – наш! Почему мы не можем его достать?
GPC: Вам самим так будет лучше.
Я: Хотя бы пользоваться можно?
GPC: Да. Загрузите к нам AAB-файл, мы его подпишем вашим ключом и отдадим вам – универсальный APK или пачку нарезанных APK для всех конфигураций устройств, тут выбирайте сами.
Ок, новый план на выкладку в RuStore получается таким:
собрать релизный AAB, подписанный загрузочным ключом;
отправить в Google Play;
скачать универсальный APK;
отправить APK в RuStore.
На всякий случай вспоминаем про риски: а что, если Google забанит наше приложение у себя в сторе (из-за санкций или чего-то такого), они дадут нам возможность пользоваться нашим ключом, сохранённым у них на серверах?
GPC: Нет
