Just DUIT - a first look at the server-driven UI framework for Flutter

Server-Driven UI (or Backend-Driven UI) is a concept in front-end application development in which the backend manages both the application's data and its appearance. Specifically, this pattern attracted my attention due to the fact that by implementing it, you can add interactive interface elements to your application and at the same time not create difficulties for yourself with publishing a new version of the application in the store and persuading users to update. Often, WebView is used to implement such an idea (and for cost savings), but anyone who has ever worked with this technology will never return to using it, provided that the task can be completed in a different way.

There are already packages for Flutter that implement the concept in one way or another. For example server_driven_ui or sdui. But they have a number of significant disadvantages:

Lack of support. Last updates more than six months ago.

Lack of clear documentation. (server_driven_ui)

A large number of third-party dependencies. (sdui)

Lack of a “builder” for the json file from which the UI will be rendered. In fact, the likelihood of an error/typing error at the stage of creating json on the server side increases.

Lack of communication mechanisms with the backend, which “distributed” the ui to us. The Ui cannot receive real-time updates from the server or call any endpoint.

Looking at these shortcomings of both packages, it was decided to write our own framework that would solve the described problems. I also got inspired by some concepts and creatively rethought them in my implementation (registration of custom widgets).

Duit - driven UI toolkit. It’s clear why the words “drived” and “UI” are present here, and “toolkit” is here for the reason that Duit is a whole framework consisting of two main parts: a library for Flutter, which provides UI rendering, as well as adapters for the backend , written in different languages (typescript and go at the moment) and ensuring the correct creation of json structures on the server side.

Core features
Initially establishing a connection to the server and obtaining the layout.

Supports several network protocols for interaction with the server (http, websocket).

"Spot" update of widget state. The concept of "managed" widgets - special components whose state can be updated according to the requirements of the backend (ws push event or response to an http request).

Actions API. A special protocol that allows the server to specify dependencies for an action associated with a widget. In this case, dependencies can be other widgets that can store some data (TextInput, etc).

The ability to create your own widgets that can be embedded in the framework and used in conjunction with other widgets from the basic set.

A set of functions ready for use on the backend that allows you to build hierarchies of widgets. (Similar to composable functions from Jetpack Compose)

I will not go into details of the implementation of each of these points in order to save your time. Below are links to all the libraries mentioned. There are several examples created in the repositories that will give you a closer look at how to use the framework, as well as pages on the GitHub Wiki.

Current status of the project
At the time you are reading this article, version v1.0.0 has already been published for all libraries included in the framework.

The base library uses the following set of widgets that Duit can now draw correctly: Row, Column, Stack, SizedBox, ColoredBox, DecoratedBox, Container, Expanded, Padding, Positioned, Center, Text, TextField, ElevatedButton, Checkbox, Image (network, memory, asset). The library will be replenished.

Backend adapters support the entire list of widgets listed above. The structures/interfaces for all properties that can be useful for rendering on the Flutter side (textStyle, padding etc) are also described.

Basic use case.
We create a driver instance. This entity is responsible for receiving the layout and interacting with the backend.
We form the widget structure on the back side using built-in functions

Let's implement an endpoint through which the driver can get the layout

This setting is enough to render a simple Text widget with the content "Example".
Made on