A powerful Flutter package for implementing Server-Driven UI (SDUI) with both JSON and gRPC support.
Server-Driven UI is an architectural pattern where the UI layout and content definitions come from a backend server rather than being hardcoded in the client application. This approach enables:
- Dynamic UI updates without app store releases
- A/B testing and feature flagging at the UI level
- Consistent UI across platforms
- Faster iteration cycles for UI changes
- Render UI dynamically from server-provided definitions
- Support for essential Flutter widgets (Text, Column, Row, Container, etc.)
- JSON parsing for server responses
- gRPC support for efficient, type-safe communication
- Protocol Buffers for structured data exchange
- Easy-to-use client API
- Customizable error handling and loading states
Add the package to your pubspec.yaml:
dependencies:
flutter_glimpse: ^0.0.1# For devs
dependencies:
flutter_glimpse:
path: path/to/flutter_glimpseOr use the Flutter CLI:
flutter pub add flutter_glimpseImport the package in your Dart code:
import 'package:flutter_glimpse/flutter_glimpse.dart';This package provides two approaches for implementing server-driven UI:
For efficient, type-safe server communication:
// Create a gRPC client
final client = GlimpseGrpcClient(
host: 'your-server.com',
port: 50051,
);
// Use the GlimpseGrpcRenderer widget
GlimpseGrpcRenderer(
client: client,
screenId: 'home_screen',
loadingWidget: CircularProgressIndicator(),
errorBuilder: (context, error) => Text('Error: $error'),
)For simpler implementation with standard HTTP requests:
// Parse Glimpse JSON to widget
dynamic json = ...; // Load your JSON
final glimpseWidget = GlimpseParser.parseJSON(json);
final flutterWidget = glimpseWidget.toFlutterWidget();You can also serialize Glimpse widgets back to JSON:
final json = GlimpseParser.toJson(glimpseWidget);And convert Flutter widgets to Glimpse (for supported types):
import 'package:flutter_glimpse/src/flutter_to_glimpse.dart';
final glimpseWidget = flutterToGlimpse(myFlutterWidget);- All core layout and display widgets are supported:
Column,Row,Text,Image,SizedBox,Container,Scaffold,Spacer,Icon. - Adding new widgets is straightforward: implement the Glimpse widget, add proto/JSON parsing, and update the toJson and Flutter conversion logic.
- The codebase is up-to-date, with no remaining TODOs.
Here's a complete example of using the gRPC renderer:
import 'package:flutter/material.dart';
import 'package:flutter_glimpse/flutter_glimpse.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Glimpse Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const GlimpseDemo(),
);
}
}
class GlimpseDemo extends StatefulWidget {
const GlimpseDemo({super.key});
@override
State<GlimpseDemo> createState() => _GlimpseDemoState();
}
class _GlimpseDemoState extends State<GlimpseDemo> {
late GlimpseGrpcClient _grpcClient;
String _screenId = 'home';
@override
void initState() {
super.initState();
_grpcClient = GlimpseGrpcClient(
host: 'localhost', // Replace with your server address
port: 50051, // Replace with your server port
);
}
@override
void dispose() {
_grpcClient.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Server-Driven UI Demo'),
),
body: GlimpseGrpcRenderer(
client: _grpcClient,
screenId: _screenId,
loadingWidget: const Center(
child: CircularProgressIndicator(),
),
errorBuilder: (context, error) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error, color: Colors.red, size: 48),
SizedBox(height: 16),
Text('Error: $error'),
SizedBox(height: 16),
ElevatedButton(
onPressed: () => setState(() {}),
child: Text('Retry'),
),
],
),
);
},
),
);
}
}Here's a basic example of a Dart server that provides UI definitions via gRPC:
import 'package:grpc/grpc.dart';
import 'package:flutter_glimpse/src/generated/glimpse.pb.dart';
import 'package:flutter_glimpse/src/generated/glimpse.pbgrpc.dart';
Future<void> main() async {
final server = Server.create(
services: [
GlimpseServiceImpl(),
],
);
await server.serve(port: 50051);
print('Server listening on port 50051...');
}
class GlimpseServiceImpl extends GlimpseServiceBase {
@override
Future<GlimpseWidgetData> getGlimpseWidget(
ServiceCall call, GlimpseRequest request) async {
// Return different UI based on the screenId
switch (request.screenId) {
case 'home':
return _createHomeScreen();
default:
return _createErrorScreen();
}
}
GlimpseWidgetData _createHomeScreen() {
return GlimpseWidgetData()
..type = WidgetType.SCAFFOLD
..body = (GlimpseWidgetData()
..type = WidgetType.COLUMN
..children.addAll([
GlimpseWidgetData()
..type = WidgetType.CONTAINER
..padding = (EdgeInsetsData()..all = 16)
..child = (GlimpseWidgetData()
..type = WidgetType.TEXT
..stringAttributes['text'] = 'Welcome to Server-Driven UI!'
..textStyle = (TextStyleData()
..fontSize = 22
..fontWeight = 'bold')),
GlimpseWidgetData()
..type = WidgetType.TEXT
..stringAttributes['text'] = 'This UI is rendered from gRPC data'
]));
}
}The package currently supports these Flutter widgets:
ScaffoldContainerColumnRowTextImageSizedBoxSpacerIcon
The package uses Protocol Buffers to define the data structures for gRPC communication. Here's a simplified version of the main message types:
message GlimpseWidgetData {
WidgetType type = 1;
map<string, string> string_attributes = 2;
map<string, double> double_attributes = 3;
map<string, bool> bool_attributes = 4;
// Complex nested attributes
TextStyleData text_style = 6;
EdgeInsetsData padding = 7;
// Children widgets
repeated GlimpseWidgetData children = 12;
GlimpseWidgetData child = 13;
// Scaffold specific parts
GlimpseWidgetData app_bar = 14;
GlimpseWidgetData body = 15;
}
service GlimpseService {
rpc GetGlimpseWidget (GlimpseRequest) returns (GlimpseWidgetData);
}If you need to regenerate the Dart files from the proto definitions:
- Install the Protocol Buffer compiler using the provided scripts:
# Windows
pwsh ./tool/setup_protoc.ps1
# Generate the Protobuf files
pwsh ./tool/generate_protos.ps1- Basic widget support
- gRPC implementation
- JSON implementation
- Interactive widgets (buttons, forms)
- More advanced widget support
See ADDING_WIDGET.md for instructions on how to add a new widget to the Glimpse package.
This project is licensed under the LICENSE file in the repository.
| Jothish Kamal | Rujin Devkota | Adhavan K |
Made with ❤ by GDSC-VIT