Как стать автором
Обновить

Play Store теперь принимает прогрессивные веб-приложения (PWA)

Время на прочтение15 мин
Количество просмотров38K
Автор оригинала: Maximiliano Firtman

Дисклеймер: я не связан с Google Play, Chrome или любой упомянутой компанией. Это не официальное заявление. Логотип и названия используются только для иллюстрации.

В Chrome 72 для Android реализована долгожданная функция Trusted Web Activity. Это означает, что теперь мы можем распространять PWA через каталог Google Play и запускать Chrome без UI в автономном режиме для нативных пакетов! Я некоторое время поигрался с этой функцией, копаясь в API, а здесь расскажу, о чём речь, чего ожидать и что доступно уже сегодня.

PWA в каталоге Play Store


Chrome 72 для Android теперь доступен для всех пользователей, и в этой версии реализована система Trusted Web Activity (TWA). Если вкратце, запуск Chrome осуществляется в автономном режиме (без панели инструментов и UI) для нативных Android-пакетов.

Начнём с того, что публикация в каталоге — не такая простая процедура, какой она должна быть (например, ввести URL в Google Play — и приложение запустится). Кроме того, нельзя использовать доступный WebAPK и опубликовать приложение в каталоге. Здесь используется Java API, который через сервисы взаимодействует с Chrome и, кажется, находится на ранней стадии разработки. Поэтому придётся многое сделать вручную.

Я рассматриваю это как первый шаг. Наверняка вскоре появится лучший инструментарий (возможно, от сообщества) с поддержкой всех доступных API и запуском в один щелчок. Но на нынешнем API можно опубликовать в каталоге лаунчер PWA. Я поделюсь своим опытом, как это делается.

По какой-то причине эта функция ещё не появилась в Chrome Platform Status, и документация до сих пор не обновилась (она вообще не обновлялась более 15 месяцев).

Обновление от 5 февраля. Блог Chromium опубликовал короткую заметку о поддержке TWA и некоторые технические детали, упомянутые в этой статье.

Обновление от 1 февраля. Пол Кинлан, ведущий разработчик Chrome в Google, подтвердил выпуск функции TWA и что документация задерживается: причина задержки в том, что разрешение на новую функцию Chrome 72 было принято в последнюю минуту.


Видео от Пита Ле Пейджа годичной давности с объяснением TWA

Зачем публиковать PWA в каталоге?


Это веб-платформа, Карл! Зачем использовать каталог?

Ну, это долгий разговор, но я много лет консультирую большой и малый бизнес, и когда мы рассматриваем разработку PWA, постоянно упоминается каталог приложений: «Наши пользователи будут там искать приложение», «У нас уже есть собственное приложение, и мы не хотим терять пользователей», «Нам нужен доступ к собственному API» или «Я хочу монетизировать PWA».

Отныне стала возможной публикация PWA в каталоге, а также работа из браузера. Конечно, это отдельная операция. Play Store не эмулирует Microsoft Store: ваше PWA не появится в магазине, если вы не скомпилируете APK и не опубликуете его.

Преимущества перед стандартными PWA


Кроме нового механизма распространения и новых пользователей из каталога (и даже из поиска Google в разделе «Приложения»), появляются и другие преимущества:

  • Возможность разместить виджет на главном экране.
  • Ярлыки приложений (при долгом нажатии на значок приложения) и другие глубокие интеграции с ОС.
  • Работа с «компаньоном» на носимых устройствах или расширением Android Auto.
  • Повторная установка после жёсткого сброса или резервного восстановления на новом телефоне.
  • Фоновые службы, которые обращаются к собственным функциям (связь с PWA всё ещё ограничена — подробнее ниже).
  • Монетизация (пока ограничена, подробнее ниже).
  • Некоторые нативные экраны, смешанные с контентом PWA.
  • Распространение более одной иконки PWA в лаунчере и/или на начальном экране, указывающих на разные URL (в пределах одного хоста).
  • Лучшая поддержка интернационализации.

В чём инновация?



В каталоге уже были некоторые PWA, но теперь их гораздо легче подготовить и опубликовать

В Google Play Store уже есть некоторые PWA, такие как Google Maps Go, Instagram Lite и Twitter Lite. Первое приложение использует некую частную версию pre-TWA, а последние два — WebView, это был хоть не идеальный, но единственный способ сделать что-то подобное до появления TWA. В приложениях много машинного кода для некоторых вещей, таких как уведомления. Мы хотим опубликовать PWA как веб-разработчики и не хотим писать много кода Java.

TWA — специальный режим на базе кастомных вкладок Chrome, которые с версии Chrome 45 позволяют запустить встроенный в приложение браузер.

Является ли TWA гибридным фреймворком, похожим на Cordova?


Нет. С Cordova и другими гибридными решениями вы обычно поставляете ресурсы (HTML, JS, CSS и т. д.). в пакете APK. Кроме того, там отличается движок, он изолирован от пользовательского браузера, поэтому не поддерживает сеансы или совместное использование кэша.


Вот как выглядит PWA с Trusted Web Activity. Я пока не вижу реализации цветовых схем

С помощью Trusted Web Activity не нужно упаковывать файлы ресурсов (только нативные компоненты, если они нужны); все ресурсы загружаются и обновляются на лету через сервис-воркера. Ваш PWA всегда рендерится установленной версией Chrome, с её хранилищем, кэшем и сеансами. Таким образом, если пользователь открыл сеанс на веб-сайте, а потом установил приложение из Play Store, он будет уже авторизован в системе.

Требования Play Store


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

  • Передача PWA Criteria (HTTPS, сервис-воркер с обработчиком событий fetch, манифест веб-приложения со значком 512px, background_color и осноным набором других свойств).
  • Рейтинг производительности минимум 80/100 в Lighthouse (доступен в инструментах разработчика Chrome или как NPM CLI).
  • Все текущие правила Play Store.

Согласно сообщению в блоге Chromium, «приложениям, которые не соответствуют требованиям качества TWA или правилам Play Store, может быть отказано в приёме или они могут быть исключены».

Я пока не уверен, что команда Play Store QA проверяет все эти требования при публикации приложения.

Модель безопасности PWA в Play Store


Ваше PWA будет подчиняться модели безопасности браузера, а не нативного приложения, пока вы не добавите нативный код непосредственно в APK. Поскольку всё под контролем браузера, пользователь должен знать, что даже если он только что установил приложение, у него появятся данные сеанса, локальные хранилища и разрешения, уже установленные для этого хоста в браузере. Вот почему при первом запуске ему показывают мини-сообщение «Работает в Chrome»:



Кроме того, когда пользователь удалит приложение, то получит предупреждение, что состояние и данные приложения по-прежнему доступны в Chrome, поэтому при необходимости следует очистить кэш. Среди таких следов, например, разрешение Web Push: даже если пользователь удалит приложение, он всё равно продолжит получать push-уведомления. Сообщение было замечено Генри Лимом:



О необходимости таких уведомлений рассказал Пол Кинлан из команды Chrome.


Способы разработки


Для создания пакета с TWA сначала понадобится Android Studio. Пока что все варианты экспериментальные и описаны только примерами кода в репозитории Chrome на GitHub.

Варианты разработки приложений с TWA:

  • Использование высокоуровневой библиотеки Java Support Library от команды Chrome: в этом случае не нужно писать собственный код Java или Kotlin. Создаёте проект Android Studio (или клонируете пример), настраиваете некоторые метаданные в AndroidManifest.xml из манифеста веб-приложения — и готово.

    Фреймворк обеспечит соединение с TWA и дополнительные возможности для создания записи Settings в Android-устройстве, а также сделает доступными пуш-уведомления. Сейчас библиотека лежит во временном репозитории Jitpack. Думаю, в будущем она переместится в другое место.
  • Работа с Trusted Web Activity вручную. Если у вас есть опыт разработки Android-приложений на Java или Kotlin, вы можете просто вручную подключить PWA. Так вы можете оставить некоторые нативные действия, открывая Trusted Web Activity только в нужный момент. В этом случае я предлагают изучить библиотеку поддержки и понять, как из проекта подключиться к Chrome.

Обновление от 5 февраля: теперь на сайте Android доступна документация по TrustedWebUtils, хелперу TWA.

Распространение манифеста


PWA в App Store не примет манифест веб-приложения; требуется вручную скопировать некоторые значения. Значки берутся из папки “res”, как в любом нативном Android-приложении, блокировку ориентации следует определить в записи активности AndroidManifest и т. д.

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

Валидация URL


TWA будет работать только после цифрового рукопожатия домена с приложением. Механизм известен как Digital Assets Links. Он создаёт доверительные отношения между вашим хостом и APK, доказывая, что вы являетесь владельцем PWA и что вы не будете публиковать в Play Store приложения, которые вам не принадлежат. Он также устанавливает цифровой канал между сайтом и нативным приложением, который теоретически может позволить им обмениваться частными данными (но, похоже, это невозможно с сегодняшним TWA API).

С Digital Assets Links вы должны выложить на своём домене файл <your-domain>/.well-known/assetlinks.json. Этот JSON-файл содержит информацию о пакете Android (например, идентификатор пакета) и хэш сертификата вашего приложения, который вы можете узнать командой в консоли. У Android-пакета будет двойник на URL хоста. Есть онлайн-валидатор для проверки, что всё в порядке.

Если вы не провели рукопожатие, TWA не активируется, и ваше приложение будет просто использовать обычные Chrome Custom Tabs с минимальным интерфейсом Chrome, как если в PWA включить display: minimal-ui. Я не совсем уверен, но наверное Play Store может отклонить приложения, которые просто указывают на обычные вкладки без валидации TWA. Я пока точно не знаю, в какой момент Chrome выполняет проверку Digital Asset Link; если при каждом доступе к приложению, это может стать проблемой производительности. Думаю, возможно кэширование, а также Play Store может делать проверку перед одобрением приложения во время приёма в каталог. Посмотрим, что будет написано в документации.

Существует (не очень простой) механизм обхода процесса сертификации Digital Asset Link для целей разработки, описанный ниже.

Публикация приложения


Чтобы опубликовать ярлык PWA с помощью TWA, нужно следовать всем правилам Play Store. Дополнительную информацию см. в Developer Policy Center. Также понадобится создать аккаунт издателя с одноразовой платой в размере $25, метаданные, скриншоты и маркетинговые материалы для приложения.



Деплой


Когда вы закончите разработку в Android Studio и у вас есть аккаунт к консоли разработчика, нужно создать APK для продакшна и подписать его ключом, созданным в Android Studio. Можете обратиться к сервису App Signing by Google Play, чтобы в будущем упростить процесс.

Консоль Google Play


Для загрузки этих приложений нет никаких особых правил или процессов, но отдел Revision может обнаружить, что вы используете TWA, и проверит, что: 1) Digital Assets Link рабоатет; 2) URL передаёт критерии PWA (в основном, для обработчика событий fetch в сервис-воркере).


Для публикации в Play Store придётся указать много метаданных и графических ресурсов

Обновление приложения


Если вы измените контент, то не нужно заново загружать приложение, если только вы не измените приложение полностью (в соответствии с правилами каталога). Продолжаете обновлять его через сервис-воркеры и обновления на сервере. Новый APK придётся загрузить только если вы захотите изменить метаданные, нативный код или иконки.

Ограничения


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

PWA в подпапках


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

  • Digital Asset Link подключает весь домен, а не только папку.
  • Текущая библиотека поддержки, кажется, обрабатывает как Intent (Link Capturing) весь хост, даже если PWA находится в подпапке.

Нет внутренних приложений


Это ограничение самого Play Store (вы не можете публиковать приложения для локальной сети или приложения, предназначенные только для вас и вашей компании). Вы можете использовать TWA и создавать apk, которые будут развёртываться за пределами магазина.

Digital Asset Link работает только с общедоступными URL, потому что Chrome должен проверить, что мы владеем доменом, а это невозможно с внутренними URL.

Первая загрузка


При первом открытии недавно установленного приложения на устройстве ещё нет файлов приложения (Service Worker ещё не зарегистрирован, если пользователь не открывал PWA раньше), поэтому в автономном режиме пользователь увидит пустой белый экран. Думаю, в будущих версиях полезно бы реализовать некую подкачку через Chrome после установки приложения. Если вы используете TWA API вместо библиотеки поддержки, то обнаружите такую ситуацию и правильно проинформируете пользователя через нативные API.

Вызов нативного кода


Уже есть двунаправленный канал между сервером TWA (Chrome) и клиентом TWA (наш APK). Этот канал в настоящее время используется только для отправки пуш-уведомлений и их отображения в нативном приложении, а не в Chrome.

Здесь есть определённый потенциал в простом соединении нативного кода и JavaScript, предоставив PWA доступ к нативному коду, аналогично механизму APPX/PWA в Microsoft Store.

Возможно, в будущем появится возможность регистрации классов Java/Kotlin в клиенте TWA, чтобы мы могли фактически вызывать их с помощью JavaScript API, когда наш PWA визуализируется в режиме TWA.

Сегодня единственный способ выполнить нативный код — использовать Intents для открытия других нативных действий и затем повторного открытия TWA, отправляя и получая аргументы через параметры URI.

Кроме того, вы можете создать в нативном коде какой-то веб-сервер или сервер WebSocket, и направить на него PWA, но это странно, сложно и, возможно, будет излишне расходовать батарею. Но перед нами целый новый мир возможностей. Посмотрим, что придумает сообщество!

Монетизация с Play Store


Если у вас платное приложение, то нельзя легко проверить, что пользователь действительно за него заплатил (в конце концов, контент — это всего лишь URL-адрес). Кроме того, если вы хотите продать какие-то цифровые ресурсы или подписки с помощью кошелька Play Store, то сложно реализовать такую схему без фактического моста с нативным кодом.

Отладка


Я не уверен, это баг или какая-то проблема моей IDE, но удалённая отладка сервис-воркеров из TWA не работает. Я могу проверить контекст окна, но не сервис-воркера.

Другие движки


Сейчас TWA работает только на Chrome, но в будущем другие браузеры могут клонировать API: например, Samsung Internet, Edge или Firefox.

Обновление от 4 февраля: TWA работает по протоколу Android Custom Tab, который в настоящее время внедряют другие браузеры. Поэтому если в системе установлен другой браузер по умолчанию, он может открыть TWA с содержимым PWA. Впрочем, требуется дополнительное тестирование, чтобы понять, как это работает.

Что произойдёт, если у пользователя более старая версия Chrome и он установит приложение из Play Store? В этом случае PWA отобразится как настраиваемая вкладка Chrome, а не в полностью автономном режиме.


Google Maps Go в Play Store уже использовал что-то похожее на TWA, а Chrome указан как обязательное требование для работы

Что произойдёт, если у пользователя вообще нет Chrome? На сегодняшний день при использовании библиотеки поддержки приложение не будет работать вообще (если нет другого браузера с поддержкой протокола Custom Tabs). Если вы используете TWA API в нативном коде Java/Kotlin, то можете проверить доступность браузера и загрузить альтернативное решение, такое как WebView, или открыть браузер.

Хотя Android-устройства без Chrome редки, но на некоторых он не установлен умолчанию, в том числе на всех новых устройствах в Европе.

Другие платформы


PWA не работает на носимых ОС (часы), но я не совсем уверен, что происходит на других Android-платформах. Вероятно, поддержки ещё нет, но нужно это проверить. Я говорю об Android TV или хромбуках с Play Store. Если вы не протестировали эти платформы, есть смысл отключить их в списке каталога.

Конфликт с WebAPK


Если вы установили PWA из Chrome, то у вас уже есть APK для этого URL, подписанный Play Store, но каталог всё равно оставит приложение в списке и позволит пользователю установить его тоже. И наоборот: установка приложения из каталога не помешает Chrome предложить пользователю «добавить» его из браузера. Думаю, этого можно избежать, если WebAPK тоже получит Digital Asset Link или мы сможем как-то сопоставить идентификатор приложения WebAPK, но вряд ли это произойдёт в ближайшее время. Посмотрим.


Два приложения Starbucks, работающие одновременно: WebAPK и наш собственный APK

Вы можете заблокировать предложение Chrome установить WebAPK и вместо него показать своё приложение из каталога, используя атрибут related_applications и атрибуты prefer_related_applications манифеста веб-приложения. Get Installed Related Apps API может в будущем помочь разрешить этот конфликт.

Создание первого PWApk


Знаю, я только что изобрёл слово PWApk, но звучит неплохо, верно?

Несколько лет назад я сделал видеокурс по нативным веб-приложениям Android. Хотя это не совсем относится к PWA, но поможет понять экосистему Android.


Самый простой способ сделать APK на основе TWA — это клонировать образец репозитория SVGOMG из репозитория ChromeLabs на GitHub

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

Создайте новый проект в Android Studio и выберите No Activity: будем использовать только Trusted Web Activity из библиотеки поддержки.


Начнём с пустого проекта

Заполните данные, выберите название проекта (мы его позже изменим) и имя пакета: это будет идентификатор нашего приложения в Android, а также в каталоге. Рекомендую использовать имя хоста в обратном порядке и произвольное название в конце. Например, если у вас хост mypwa.com/calculator, то пакет можно назвать com.mypwa.calculator.

В качестве базы подойдёт API 19 (Android 4.4). Похоже на то, что скоро это будет минимальная версия, необходимая для Chrome. Некоторые функции TWA будут работать только с API 23 (Android 6.0), но об этом позаботится библиотека поддержки.

Обновление от 5 февраля: Chrome официально объявил, что TWA работает только с Android 4.4 KitKat. Таким образом, эта функция недоступна примерно 5% активных пользователей Android: их откатит на версию с кастомной вкладкой и адресной строкой.


Выбор минимального уровня API ограничит список устройств, для которых PWA будет предлагаться в каталоге Play Store

Добавление зависимости


Следующий шаг — добавление библиотеки поддержки TWA в качестве зависимости, поэтому откроем два файла с названием build.gradle:


Два файла конфигурации: для проекта и для Android-приложения

Начнём с файла проекта. Добавим в секции allprojects > repositories следующую строку:

maven { url "https://jitpack.io" }

На следующем шаге мы открываем build.gradle модуля и добавляем в зависимости:

implementation 'com.github.GoogleChrome:custom-tabs-client:e446d08014'

Настройка TWA


Следующий шаг — установить в файле модуля параметры PWA для Trusted Web Activity, добавляем в секцию defaultConfig:

manifestPlaceholders = [
        hostName: "app.starbucks.com",
        defaultUrl: "https://app.starbucks.com",
        launcherName: "Starbucks",
        assetStatements: '[{ "relation": ["delegate_permission/common.handle_all_urls"], ' +
         '"target": {"namespace": "web", "site": "https://app.starbucks.com"}}]'
]

Тут в качестве примера я буду использовать Starbucks PWA. Информация из процесса Digital Asset Link понадобится ключу assetStatements. Мы пока пропустим эту часть. Свойство с названием launcherName должно совпадать с short_name в манифесте веб-приложения.

Настройка манифеста


У приложений Android собственный манифест, они не примут манифест веб-приложения. Нужный файл находится в разделе app > manifests и называется AndroidManifest.xml. Там вы найдёте самозакрывающийся элемент Application XML.


Файл Android-манифеста по умолчанию

Там изменяем значение android:label на ${launcherName}, которое мы установили ранее в метаданных, так что у нас будет единственный источник истины для названия приложения.

Следующий шаг — настройка этого файла, начиная с тега <application>, чтобы добавить в него дочерние элементы, которые будут выглядеть следующим образом:

<meta-data
    android:name="asset_statements"
    android:value="${assetStatements}" />

<activity android:name="android.support.customtabs.trusted.LauncherActivity"
    android:label="${launcherName}">
    <meta-data android:name="android.support.customtabs.trusted.DEFAULT_URL"
        android:value="${defaultUrl}" />

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="https"
            android:host="${hostName}"/>
    </intent-filter>
</activity>

Приведённый ниже код настроит TWA с помощью библиотеки поддержки и Intent Filter, чтобы приложение получило ссылки на PWA и Digital Asset Link. Я пропущу подробности, что происходит с точки зрения Android-приложения.


Пришло время для синхронизации

На этом этапе нужно скомандовать Android Studio принять все ваши изменения, нажав Sync Now. Если всё сделано правильно, то не выскочит никаких ошибок.

Замена иконок


В данный момент приложение использует только иконку Android по умолчанию, поэтому нужно заменить все файлы в app>res>mipmap в разных подпапках для разной плотности пикселей. Есть две версии: квадратные и закруглённые иконки. Закруглённые появились в Android 7.1, и если хотите их игнорировать, то удалите ссылку android:roundIcon ссылку в AndroidManifest.xml.


Нужно взять значки из манифеста и скопировать их во вложенные папки mipmap с соответствующими именами

Настройка темы


Наконец, нужно открыть app/res/values/styles.xml и внести некоторые изменения в тему, чтобы она выглядела как PWA:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>

Вы можете изменить цвета из app/res/values/colors.xml, но я пока не видел, чтобы это работало в TWA.

Если вы ограничиваете ориентацию в манифесте, то можете добавить это ограничение в элемент <activity> в AndroidManifest.xml.

Готовы к тестированию?


Мы готовы протестировать наш PWApk, но перед этим нужно настроить режим разработки TWA для Chrome на тестовом устройстве Android или в эмуляторе (с Chrome 72+).

Настройка Chrome


Убедитесь, что у вас Chrome стабильной версии 72 и откройте chrome://flags. Найдите опцию Enable command line on non-rooted devices и поставьте флаг. Перезапустите браузер.

Затем нужно настроить Chrome для обхода Digital Asset Link для хоста, который мы хотим протестировать, в нашем примере это app.starbucks.com.

Чтобы изменить параметры командной строки для Chrome под Android нужно записать текстовый файл в файловую систему Android. Самый простой способ сделать это — через adb (android debug bridge), который должен быть прописан в path (погуглите, если что), и запустить команду:

adb shell cat /data/local/tmp/chrome-command-line _ - disable-digital-asset-link-verification-for-url="https://app.starbucks.com"

Можно использовать простой bash-скрипт от Google.


Нужно остановить Chrome, чтобы он при запуске принял новые настройки

И перезапустить Chrome. Но не просто убрать приложение из списка задач, а из настроек принудительно завершить весь процесс (Force Stop). Мне пришлось сделать это пару раз, прежде чем всё сработало.


Предупреждение о том, что флаг включен и всё прошло удачно

Если всё сделано, то каждый раз при открытии Chrome вы увидите предупреждение о неподдерживаемом флаге. Если запустить приложение из Android Studio, ваше PWA наконец-то запустится и заработает в автономном режиме под значком и названием вашего APK.

Заключение


Возможность публикации PWA в каталоге Google Play реально меняет правила игры. Кажется, сейчас у нас очень ранняя версия API и определённо требуется доработка. Я действительно хочу, чтобы можно было ввести URL нашего PWA и получить с него файл APK. Это не очень просто из-за системы верификации Digital Asset Link. Только Play Store может это сделать, используя тот же WebAPK, который они генерируют.

Я раньше задавался вопросом, одобряет Google приложения PWA или ведёт с ними войну. Но теперь они сняли с себя подозрения, по крайней мере, в части TWA.

Будем надеяться, что TWA в Chrome 72 — это первый шаг в долгом путешествии!
Теги:
Хабы:
Всего голосов 30: ↑30 и ↓0+30
Комментарии10

Публикации

Истории

Работа

iOS разработчик
16 вакансий
Swift разработчик
16 вакансий

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань