Вы когда-нибудь задумывались о том, как приложения в вашем смартфоне не обновляясь меняют свой пользовательский интерфейс за одну ночь? Возьмем для примера любую крупную технологическую платформу, такую как Flipkart от Amazon, Square, AirBnB или Swiggy. Они меняют свой пользовательский интерфейс в зависимости от различных факторов, таких как местоположение. Как они это делают?
Что такое Server-Driven UI?
Управляемый сервером пользовательский интерфейс (Server-driven UI) — это сценарий, в котором клиент получает информацию от API о том, какие компоненты и контент следует показать. В этом могут использоваться все три основные платформы — iOS, Android и веб. Я считаю, что подобная разработка улучшает отзывчивость и управляемость нативных приложений. Сегодня мы поговорим о том, как этого добиться.
Существует множество способов добиться этого в Android, но мы будем использовать самый популярный и простой тип данных — JSON.
Поскольку JSON легко читать и управлять им. Давайте посмотрим на пример JSON-файла.
{ "card": { "log_id": "div2_sample_card", "states": [ { "state_id": 0, "div": { "items": [ { "type": "container", "width": { "type": "match_parent" }, "height": { "type": "match_parent" }, "items": [ { "type": "image", "image_url": "https://upload.wikimedia.org/wikipedia/commons/2/2f/Google_2015_logo.svg", "width": { "type": "fixed", "value": 50 }, "height": { "type": "fixed", "value": 50 }, "preload_required": true, "scale": "fit" }, { "type": "text", "text": "Hello Server Driven UI ", "width": { "type": "match_parent" }, "text_alignment_horizontal": "center" } ], "content_alignment_horizontal": "center", "content_alignment_vertical": "center", "background": [ { "type": "solid", "color": "#ffeeff" } ] } ], "background": [ { "color": "#F1EBDC", "type": "solid" } ], "height": { "type": "match_parent" }, "orientation": "overlap", "type": "container" } } ] } }
В левой части изображения вы можете увидеть схему JSON, которая создает красивый пользовательский интерфейс в правой части с изображением, текстом и цветом фона.
Позвольте мне немного объяснить эти JSON-схемы. Каждый div
используется как контейнер, внутри которого будет список элементов.
Существует несколько основных типов. Давайте рассмотрим некоторые из них подробнее.
- Container — выполняет роль держателя. Воспринимайте его как холст, на котором рисуется пользовательский интерфейс. Простой макет со списком элементов. В примере выше мы используем контейнер для хранения списка изображений и текста с фоном. С точки зрения Android, он использует ширину и высоту как match_parent.
- Image — содержит изображение с такими свойствами, как image_url, ширина, высота и масштаб.
- Text — простой текст для отображения с такими свойствами, как ширина, высота, текст и выравнивание.
Есть и другие типы, но для этой статьи нам понадобится только это, чтобы понять основы серверного пользовательского интерфейса.
Теперь, когда данные UI созданы, посмотрим как их отрисовать в приложениях.
Давайте погрузимся в кодовую часть этого процесса, чтобы его можно было получить на Android, iOS и в вебе.
Есть классная библиотека DivKit, разработанная командой Яндекса, которая прекрасно справляется с этой задачей. Она также используется в продакшене.
Ссылку на Github с примером проекта DivKit можно найти здесь, а ссылку на мой проект с чистым кодом — здесь.
Я объясню, как легко интегрировать Divkit без написания кода в XML.
Шаг 1. Внедрение Divkit в build.gradle:
dependencies { implementation "com.yandex.div:div:29.14.0" implementation "com.yandex.div:div-core:29.14.0" implementation "com.yandex.div:div-json:29.14.0" }
Шаг 2. Внутри файла main.xml вашей Активити:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" />
Шаг 3. Напишите этот код в файле MainActivity.kt:
class MainActivity : AppCompatActivity() { private lateinit var context: Div2Context override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val divConfiguration = DivConfiguration.Builder(CoilDivImageLoader(this)) .actionHandler(object : DivActionHandler() { override fun getUseActionUid(): Boolean { Log.i("TAG", "getUseActionUid: ") return super.getUseActionUid() } override fun handleAction(action: DivAction, view: DivViewFacade): Boolean { Log.i("TAG", "handleAction: " + action.url?.evaluate(view.expressionResolver)) val stringUri = action.url?.evaluate(view.expressionResolver)!! when (stringUri.scheme) { "submit" -> { // Write your code here on button press (actions in JSON) } } return super.handleAction(action, view) } override fun handlePayload(payload: JSONObject) { Log.i("TAG", "handlePayload: $payload") super.handlePayload(payload) } }) .build() this.context = Div2Context( baseContext = this, configuration = divConfiguration, lifecycleOwner = this ) updateUIWithJSON("YOUR JSON FILE NAME GOES HERE!!") } private fun updateUIWithJSON(jsonFileName: String) { runOnUiThread { val linearLayout = findViewById<LinearLayout>(R.id.container) linearLayout.removeAllViews() val divJson = DivAssetReader(context).read("$jsonFileName.json") var templateJson = divJson.optJSONObject("templates") val cardJson = divJson.getJSONObject("card") val div = DivViewFactory(context, templateJson).createView(cardJson) linearLayout.addView(div) div.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT div.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT } } } class DivViewFactory( private val context: Div2Context, private val templatesJson: JSONObject? = null ) { private val environment = DivParsingEnvironment(ParsingErrorLogger.ASSERT).apply { if (templatesJson != null) parseTemplates(templatesJson) } fun createView(cardJson: JSONObject): Div2View { val divData = DivData(environment, cardJson) return Div2View(context).apply { setData(divData, DivDataTag(divData.logId)) } } }
Вот и все. Как только вы запустите код, появится тот же самый пользовательский интерфейс, что и выше. Не нужно писать никакого кода, и самое приятное, что этот JSON можно изменять с сервера, добавляя и удаляя любые дополнения без необходимости менять код приложения.
Это очень простой пример отображения пользовательского интерфейса с сервера. Вы можете прочитать об этом подробнее, а также разобраться и создать любой сложный пользовательский интерфейс с помощью DivKit.
На этом все. Счастливого кодинга 😁.
Еще про Server-Driven UI
- BDUI как стратегия мобильного приложения
- Как разрабатывать Яндекс Маркет, обеспечивать качество и работать с BDUI
- BDUI – удовольствие или боль?
- BDUI на 100%: управляем шиммерами с бэкенда
- Podlodka #318: Backend Driven UI
- Backend Driven… Аналитика!
- DivKit. Server Driven UI. Ольга Ким. Яндекс
- Server Driven UI в Android с Compose
- Server-Driven UI с DivKit
- Глубокое погружение в Server-Driven UI систему Airbnb