
In today’s software industry, apps need to be able to quickly adapt to a variety of factors, such as user experience, new features, bug fixes, and more. Furthermore, these items need to be submitted to the App/Play Store, as far as it is concerned mobile apps, where it is reviewed and then made available for users to install. This takes a little time. However, the main point I want to highlight is the need for the user to update the app, most of the time. This can usually be mitigated by automatic updates in the app stores, but at the development level, it is still necessary to submit to the approval process in the app stores. This disadvantages exists because most applications today have their user interface hard-coded into the client application — and that’s okay. But there is another approach that helps solve many of these problems: Server-Driven UI, and in today’s article I’m going to talk about this way of creating more dynamic and personalized interfaces.
Understanding Server-Driven UI (SDUI)
Grossly simplified, the Server-Driven UI is an architectural approach where the user interface structure, layout and content are determined by the server rather than being hard-coded in client application. In a traditional mobile app, the representation of the UI is created into the app. The SDUI reverses this responsibility, allowing the interface to update dynamically and server-side changes to be instantly reflected in the app, all without updating the app via the App/Play Store.
Imagine that you are developing a mobile application that needs to display a campaign to users. This feature changes the content and layout quite a bit, and this depends on the time and users we want to reach. With the traditional approach, each change in the layout means a new deploy. In this context, SDUI emerges as a solution, as it sends a different screen and content, such as title, subtitle, padding and action dynamically.
Similarly, server-driven UI is a great option for A/B testing, an experimentation technique that aims to compare different versions of an element to determine which performs best based on a metric, such as clicks and time spent on screen. In this way, the server can send different versions of the UI to groups of users to test design hypotheses.
In both scenarios, we can use the execution flow, where the application makes an HTTP request to the server to request a canvas interface. After that, the server responds with a JSON representing a UI, which the application then needs to translate into a native component and render it.
SDUI Implementation Benefits
- Quick updates: Change the UI without having to release a new version of the app.
- Dynamic customization: Different users can see different screens without changing the app code.
- Easier A/B experiments: You can test different layouts just by changing what the server.
SDUI Implementation Challenges
- Parser: The app needs to be able to understand and build the interface from the data. - Such a parser can be quite complex to implement.
- Performance: It may be a bit slower to build the screen (especially if the JSON is large).
- Less control: If the server fails or sends wrong data, the UI may break.
Building dynamic interfaces with SDUI in Flutter
Here I bring a simple example in Flutter using SDUI. I will implement a simple parser for widgets, responsible for converting JSON content into widgets, dynamically. I also show a piece of code that renders the user interface. But before that, it is better to show what a JSON would look like:
{
"type": "screen",
"components": [
{
"type": "text",
"text": "Special Promotion!",
"style": {"fontSize": 24, "fontWeight": "bold"}
},
{
"type": "button",
"text": "Buy now",
"style": {
"backgroundColor": "#6200EE",
"textColor": "#FFFFFF"
},
"action": {"type": "navigate", "url": "/screen/checkout"},
}
]
}
The parser:
import 'package:flutter/material.dart';
class SDUIParser {
SDUIParser();
Widget parse(Map<String, dynamic> json) {
final type = json['type'];
Widget widget;
switch (type) {
case 'text':
widget = Text(
json['text'] ?? '',
style: TextStyle(
fontSize: (json['style']?['fontSize'] ?? 16).toDouble(),
fontWeight: json['style']?['fontWeight'] == 'bold'
? FontWeight.bold
: FontWeight.normal,
),
);
break;
case 'button':
widget = ElevatedButton(
onPressed: () {
print('Navigate to: ${json['action']?['url']}');
// code to implementation
},
child: Text(json['text'] ?? ''),
);
break;
default:
widget = const SizedBox.shrink();
}
return widget;
}
}
The main program:
void main() {
final parser = SDUIParser();
runApp(MaterialApp(
home: Scaffold(
body: Center(
child: parser.parse(json), // this json comes from the server
),
),
));
}
I confess that the first time I saw this approach, it seemed like a hack, but now that I’ve studied it, I’ve realized how much sense it makes and how it helps with customization and deployment. This approach has opened my mind to possibilities that I can’t explore with hard-code, and I believe that SDUI is much more complex than the traditional approach, mainly because of the parser, and this can open up gaps for bad implementations, like any other approach. It’s a big challenge, but given its benefits, it’s worth trying in complex applications.
Did you get a better understanding of Server-Driven UI? Do you have any questions or find any errors? Let me know, comment below. See you later!