Всем привет, я Дима Авдеев из Туту, наша команда разрабатывает приложения с 20М инсталлов. Расскажу, как можно обновлять приложение без выкатки релиза. Например, когда мы хотим быстро донести до пользователей коронавирусные ограничения. Ниже реализация на SwiftUI и Kotlin (но вы можете использовать UIkit и серверный язык, принятый в вашей команде), а в GitHub-репозитории в конце статьи вы найдёте код сервера и приложений для детального изучения. Пост по мотивам моего доклада. Оглавление Зачем вообще Server driven view Заглянем глубже А что на практике С сервера будет приходить JSON в формате дерева. Там мы опишем нашу вёрстку. Потом на SwiftUI нативно отрендерим JSON. Если пользователь взаимодействует с кнопкой, отправится новый HTTP-вызов: в тело этого вызова мы добавим айдишник кнопки, в результате чего вернётся новый JSON с сервера, а мы его отобразим. Сервер также может послать какие-то дополнительные данные, а мы их обработаем. И даже сможем обеспечить логику наподобие диплинков.  По сути, это однонаправленная архитектура MVI (Model View Intent). Model — это данные JSON, которые к нам приходят от сервера. View — это наш SwiftUI. Intent — тело нового серверного вызова.  Вот хорошее видео, если вы хотите больше знать о MVI Давайте сделаем  экран с важной информацией. Вот вёрстка этого экрана. Наша структура Server driven view — это SwiftUI-структура. Туда, в конструктор, мы передаём  ID пользователя и серверный путь, по которому будем запрашивать JSON для отображения. Давайте посмотрим, как сервер отвечает на этот вызов. Отдаётся дерево. Например в корне может лежать вертикальный контейнер, в нём первый ребёнок — это картинка, второй — текст.  Чтобы не формировать JSON руками, мы сделали специальную DSL-обёртку — причём её можно изменять, перезапускать сервер и сразу видеть изменения на клиенте.     Вы cможете обеспечить привычный пользователю нативный интерфейс iOS, в отличие от WebView и Push. При этом подходы не противоречат Server driven view, их можно использовать вместе.  Вы сможете сами поднять простой сервер, проверить, как отображается вёрстка, отредактировать её и поотлаживать. Можно выделить для этого отдельный микросервис и развернуть в своей инфраструктуре. Логику работы этого сервиса разумнее отдать на реализацию мобильным разработчикам: мы лучше знаем, в каком формате принимать эту вёрстку и сможем заложиться под совместимости и версионирование.  При этом серверный разработчик может поменять UI и поотлаживать логику своей фичи на сервере, не дожидаясь, когда освободится iOS-команда.   А/B-тестами можно будет управлять из серверного кода, добавляя варианты эксперимента на лету без feature toggle на клиенте. Всё это также применимо для Android-приложения — и один микросервис может обслуживать обе платформы.  Правила Apple и Google разрешают использовать такие обновляемые view, но ограниченно: не меняйте основную функциональность приложения.   Время отклика при нажатии на кнопки может возрасти, если у клиента плохой интернет.  Может возрасти нагрузка на серверную инфраструктуру, но мы можем оптимизировать это, добавив слой кеширования, поменяв JSON на бинарные данные или поменяв протокол на вебсокет.   Наконец, версионирование. Нужно сделать несколько серверных URL, и клиент в зависимости от версии будет обращаться к ним. А сервер — разруливать всё так, чтобы старым клиентам не дать лишнюю информацию.  Структура SwiftUI имеет три состояния: состояние загрузки, нормальное состояние и состояние ошибки.  Нормальное состояние вызывает структуру Render Node:она нужна, чтобы рендерить любые элементы нашего JSON. В списке могут быть все возможные JSON-объекты — вертикальный или горизонтальный контейнер, текст, прямоугольник, кнопка и так далее.   Кнопка принимает в себя Intent, он же айдишник кнопки, которая будет нажата.   Контейнер перебирает всех своих детей и для каждого ребёнка заново вызывает функцию Render Node. То есть, по сути, получается рекурсия.  Контейнер также может содержать ещё один контейнер внутри себя. Таким образом мы можем отрендерить всё дерево: у нас есть глобальный Render Node, и каждый узел мы отдельно описываем в SwiftUI. Давайте сделаем экран со статистикой заболевших: у нас будет город, картинка для города, статистика за несколько дней в вертикальных прямоугольниках (зелёный — мало заболевших, красный — много), плюс описание, какие ограничения действуют сейчас в этом городе.  Заведём модельку города — название, картинка, статистика заболевших за несколько дней (далее будет идти код сервера на Kotlin). И модельку для дня, это будет текстовая строка «день недели» и количество заболевших в этот день. Данные сгенерируем случайно  в диапазоне от 100 до 1000.   Теперь подставим данные в нашу карточку и сделаем отображение статистики для одного города. Перебираем в цикле дни из модельки города и отображаем количество заболевших.   Далее перебираем в цикле все города cities и отображаем cityCard(city). Всё, мы сделали экранчик исключительно в серверном коде, можем достаточно быстро вносить изменения и смотреть, как они отображаются на клиенте.  P.S. Подробности можно изучить в этом GitHub-репозитории: там вы найдёте Android- и iOS-приложения, сервер и инструкцию по сборке и запуску.  Спасибо за внимание!