flutter-duit-bdui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Fluttter Duit Backend-driven UI

Flutter Duit 后端驱动UI

Overview

概述

Duit enables backend-driven UI in Flutter applications. The server controls both data and layout via JSON, allowing UI updates without app releases.
Duit可在Flutter应用中实现后端驱动UI。服务器通过JSON控制数据与布局,无需发布应用即可更新UI。

Quick Start

快速开始

  1. Add dependency to pubspec.yaml
  2. Initialize DuitRegistry (optional: with themes/custom widgets)
  3. Create XDriver (HTTP, WebSocket, or static)
  4. Wrap UI in DuitViewHost
  5. Server sends JSON layouts → Duit renders them
  1. 向pubspec.yaml添加依赖
  2. 初始化DuitRegistry(可选:配置主题/自定义组件)
  3. 创建XDriver(HTTP、WebSocket或静态类型)
  4. 用DuitViewHost包裹UI
  5. 服务器发送JSON布局 → Duit渲染界面

Prerequisites

前置要求

SDK Requirements

SDK要求

yaml
- Dart SDK: >=3.4.4 <4.0.0
- Flutter: >=3.24.0
yaml
- Dart SDK: >=3.4.4 <4.0.0
- Flutter: >=3.24.0

Add Dependency

添加依赖

bash
flutter pub add flutter_duit
Install:
bash
flutter pub get
bash
flutter pub add flutter_duit
安装依赖:
bash
flutter pub get

Basic Integration

基础集成

Minimal Setup

最小化配置

dart
import 'package:flutter/material.dart';
import 'package:flutter_duit/flutter_duit.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: DuitViewHost.withDriver(
          driver: XDriver.static({
            "type": "Text",
            "id": "1",
            "attributes": {"data": "Hello, World!"},
          }),
        ),
      ),
    );
  }
}
dart
import 'package:flutter/material.dart';
import 'package:flutter_duit/flutter_duit.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: DuitViewHost.withDriver(
          driver: XDriver.static({
            "type": "Text",
            "id": "1",
            "attributes": {"data": "Hello, World!"},
          }),
        ),
      ),
    );
  }
}

Driver Lifecycle Management

Driver生命周期管理

Always dispose drivers to prevent memory leaks:
dart
class MyWidgetState extends State<MyWidget> {
  late final XDriver driver;

  
  void initState() {
    super.initState();
    driver = XDriver.static(/* ... */);
  }

  
  void dispose() {
    driver.dispose();
    super.dispose();
  }
}
务必销毁Driver以避免内存泄漏:
dart
class MyWidgetState extends State<MyWidget> {
  late final XDriver driver;

  
  void initState() {
    super.initState();
    driver = XDriver.static(/* ... */);
  }

  
  void dispose() {
    driver.dispose();
    super.dispose();
  }
}

Transport Configuration

传输配置

HTTP Transport

HTTP传输

Fetch layouts from REST API endpoints:
dart
final driver = XDriver(
  transportManager: HttpTransportManager(
    options: HttpTransportOptions(
      baseUrl: 'https://api.example.com/view',
      headers: {
        'Authorization': 'Bearer $token',
        'Content-Type': 'application/json',
      },
    ),
  ),
);
从REST API端点获取布局:
dart
final driver = XDriver(
  transportManager: HttpTransportManager(
    options: HttpTransportOptions(
      baseUrl: 'https://api.example.com/view',
      headers: {
        'Authorization': 'Bearer $token',
        'Content-Type': 'application/json',
      },
    ),
  ),
);

WebSocket Transport

WebSocket传输

Real-time bidirectional communication:
dart
final driver = XDriver(
  transportManager: WSTransportManager(
    options: WSTransportOptions(
      url: 'wss://api.example.com/ws',
      headers: {
        'Authorization': 'Bearer $token',
      },
      reconnectInterval: Duration(seconds: 5),
      heartbeatInterval: Duration(seconds: 30),
    ),
  ),
);
实时双向通信:
dart
final driver = XDriver(
  transportManager: WSTransportManager(
    options: WSTransportOptions(
      url: 'wss://api.example.com/ws',
      headers: {
        'Authorization': 'Bearer $token',
      },
      reconnectInterval: Duration(seconds: 5),
      heartbeatInterval: Duration(seconds: 30),
    ),
  ),
);

Static/Stub Transport

静态/桩传输

For testing or local layouts:
dart
final driver = XDriver.static(
  layoutJson,
);
用于测试或本地布局:
dart
final driver = XDriver.static(
  layoutJson,
);

Custom Decoder/Encoder

自定义解码器/编码器

dart
import 'dart:convert';
import 'dart:typed_data';

class CustomDecoder extends Converter<Uint8List, Map<String, dynamic>> {
  
  Map<String, dynamic> convert(Uint8List input) {
    // Custom decode logic
    return jsonDecode(utf8.decode(input));
  }
}

final driver = XDriver(
  transportManager: HttpTransportManager(
    options: HttpTransportOptions(
      baseUrl: 'https://api.example.com',
      decoder: CustomDecoder(),
    ),
  ),
);
dart
import 'dart:convert';
import 'dart:typed_data';

class CustomDecoder extends Converter<Uint8List, Map<String, dynamic>> {
  
  Map<String, dynamic> convert(Uint8List input) {
    // Custom decode logic
    return jsonDecode(utf8.decode(input));
  }
}

final driver = XDriver(
  transportManager: HttpTransportManager(
    options: HttpTransportOptions(
      baseUrl: 'https://api.example.com',
      decoder: CustomDecoder(),
    ),
  ),
);

Custom Transport

自定义传输

Create your own transport implementation if needed:
dart
class MyCustomTransportManager with TransportCapabilityDelegate {
  
  void linkDriver(UIDriver driver) {
    // Implement linkDriver method
  }

  
  Stream<Map<String, dynamic>> connect({
    Map<String, dynamic>? initialRequestData,
    Map<String, dynamic>? staticContent,
  }) async* {
    // Implement connect method
  }

  
  Future<Map<String, dynamic>?> executeRemoteAction(
    ServerAction action,
    Map<String, dynamic> payload,
  ) async {
    //Implement executeRemoteAction method
  }

  
  Future<Map<String, dynamic>?> request(
    String url,
    Map<String, dynamic> meta,
    Map<String, dynamic> body,
  ) async {
    //Implement request method
  }

  
  void releaseResources() {
    // Implement linkDriver method
  }
}
如有需要,可创建自己的传输实现:
dart
class MyCustomTransportManager with TransportCapabilityDelegate {
  
  void linkDriver(UIDriver driver) {
    // Implement linkDriver method
  }

  
  Stream<Map<String, dynamic>> connect({
    Map<String, dynamic>? initialRequestData,
    Map<String, dynamic>? staticContent,
  }) async* {
    // Implement connect method
  }

  
  Future<Map<String, dynamic>?> executeRemoteAction(
    ServerAction action,
    Map<String, dynamic> payload,
  ) async {
    //Implement executeRemoteAction method
  }

  
  Future<Map<String, dynamic>?> request(
    String url,
    Map<String, dynamic> meta,
    Map<String, dynamic> body,
  ) async {
    //Implement request method
  }

  
  void releaseResources() {
    // Implement linkDriver method
  }
}

Custom Widgets

自定义组件

Create and register Custom Widget

创建并注册自定义组件

dart
import 'package:flutter_duit/flutter_duit.dart';

// 1. Define custom widget
class MyCustomWidget extends StatelessWidget {
  final ViewAttribute attributes;

  const MyCustomWidget({
    required this.attributes,
    super.key,
  });

  
  Widget build(BuildContext context) {
    final attrs = attributes.payload;
    return Container(
      child: Text(attrs.getString(key: "message")),
    );
  }
}

// 2. Create build factory fn for widget
Widget myCustomBuildFactory(ElementPropertyView model) {
    if (model.isControlled) {
        return MyCustomWidget(
            attributes: model.attributes,
        );
    } else {
        return const SizedBox.shrink();
    }
}

// 3. Register build-fn
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  DuitRegistry.register(
    "MyCustomWidget",
    buildFactory: myCustomBuildFactory,
  );

  runApp(const MyApp());
}
dart
import 'package:flutter_duit/flutter_duit.dart';

// 1. 定义自定义组件
class MyCustomWidget extends StatelessWidget {
  final ViewAttribute attributes;

  const MyCustomWidget({
    required this.attributes,
    super.key,
  });

  
  Widget build(BuildContext context) {
    final attrs = attributes.payload;
    return Container(
      child: Text(attrs.getString(key: "message")),
    );
  }
}

// 2. 为组件创建构建工厂函数
Widget myCustomBuildFactory(ElementPropertyView model) {
    if (model.isControlled) {
        return MyCustomWidget(
            attributes: model.attributes,
        );
    } else {
        return const SizedBox.shrink();
    }
}

// 3. 注册构建函数
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  DuitRegistry.register(
    "MyCustomWidget",
    buildFactory: myCustomBuildFactory,
  );

  runApp(const MyApp());
}

Components

组件系统

Components registration

组件注册

Components allow you to create reusable UI templates that can be referenced by a tag and populated with dynamic data.
dart
import 'package:flutter_duit/flutter_duit.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Define component template
  final cardComponent = {
    "tag": "CardComponent",
    "layoutRoot": {
      "type": "Container",
      "id": "cardContainer",
      "controlled": false,
      "attributes": {
        "padding": {"all": 16},
        "margin": {"all": 8},
        "decoration": {
          "borderRadius": 12,
          "color": "#FFFFFF",
          "boxShadow": [
            {
              "color": "#00000033",
              "blurRadius": 6,
              "offset": {"dx": 0, "dy": 2},
            },
          ],
        },
      },
      "children": [
        {
          "type": "Text",
          "id": "cardTitle",
          "controlled": false,
          "attributes": {
            "data": {
              "style": {
                "fontSize": 18,
                "fontWeight": "w600",
                "color": "#333333",
              },
            },
            "refs": [
              {
                "objectKey": "title",
                "attributeKey": "data",
              },
            ],
          },
        },
        {
          "type": "Text",
          "id": "cardDescription",
          "controlled": false,
          "attributes": {
            "data": {
              "style": {
                "fontSize": 14,
                "color": "#666666",
              },
            },
            "refs": [
              {
                "objectKey": "description",
                "attributeKey": "data",
              },
            ],
          },
        },
      ],
    },
  };

  // Register the component
  await DuitRegistry.registerComponents([cardComponent]);

  runApp(const MyApp());
}

// Usage in JSON layout from server:
// {
//   "type": "Component",
//   "id": "card1",
//   "tag": "CardComponent",
//   "data": {
//     "title": "Hello World",
//     "description": "This is a card component"
//   }
// }
Key concepts:
  • tag: Unique identifier for the component
  • layoutRoot: Root element of the component template
  • refs: References to dynamic data passed via the
    data
    field
  • objectKey: Key in the
    data
    object
  • attributeKey: Attribute in the widget to bind to
  • defaultValue: Optional default value if data key is missing
You can register multiple components at once:
dart
await DuitRegistry.registerComponents([
  cardComponent,
  buttonComponent,
  listItemComponent,
]);
组件允许您创建可复用的UI模板,通过标签引用并填充动态数据。
dart
import 'package:flutter_duit/flutter_duit.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 定义组件模板
  final cardComponent = {
    "tag": "CardComponent",
    "layoutRoot": {
      "type": "Container",
      "id": "cardContainer",
      "controlled": false,
      "attributes": {
        "padding": {"all": 16},
        "margin": {"all": 8},
        "decoration": {
          "borderRadius": 12,
          "color": "#FFFFFF",
          "boxShadow": [
            {
              "color": "#00000033",
              "blurRadius": 6,
              "offset": {"dx": 0, "dy": 2},
            },
          ],
        },
      },
      "children": [
        {
          "type": "Text",
          "id": "cardTitle",
          "controlled": false,
          "attributes": {
            "data": {
              "style": {
                "fontSize": 18,
                "fontWeight": "w600",
                "color": "#333333",
              },
            },
            "refs": [
              {
                "objectKey": "title",
                "attributeKey": "data",
              },
            ],
          },
        },
        {
          "type": "Text",
          "id": "cardDescription",
          "controlled": false,
          "attributes": {
            "data": {
              "style": {
                "fontSize": 14,
                "color": "#666666",
              },
            },
            "refs": [
              {
                "objectKey": "description",
                "attributeKey": "data",
              },
            ],
          },
        },
      ],
    },
  };

  // 注册组件
  await DuitRegistry.registerComponents([cardComponent]);

  runApp(const MyApp());
}

// 在服务器返回的JSON布局中使用:
// {
//   "type": "Component",
//   "id": "card1",
//   "tag": "CardComponent",
//   "data": {
//     "title": "Hello World",
//     "description": "This is a card component"
//   }
// }
核心概念:
  • tag: 组件的唯一标识符
  • layoutRoot: 组件模板的根元素
  • refs: 对通过
    data
    字段传递的动态数据的引用
  • objectKey:
    data
    对象中的键
  • attributeKey: 要绑定的组件属性
  • defaultValue: 可选,当数据键缺失时的默认值
您可以一次性注册多个组件:
dart
await DuitRegistry.registerComponents([
  cardComponent,
  buttonComponent,
  listItemComponent,
]);

When to Use This Skill

适用场景

Use this skill when:
  • Integration flutter_duit library into project
  • Custom widet creation
  • Components registration
  • Basic framework behavior overriding via capabilities implementation
  • Need help with the framework API
在以下场景中使用本技能:
  • 将flutter_duit库集成到项目中
  • 创建自定义组件
  • 注册组件
  • 通过能力实现重写基础框架行为
  • 需要框架API相关帮助

Resources

资源

Reference Documentation

参考文档

  • capabilities.md — Notes about capability-based design and core framework parts overriding
  • troubleshooting.md - Notes about common issues in framework integration
  • environvent_vars.md — Notes about avalilable env variables and its usage
  • public_api.md — Notes about driver public API
  • https://duit.pro/docs/en — official documentation site
  • capabilities.md — 基于能力的设计及核心框架部分重写说明
  • troubleshooting.md - 框架集成中的常见问题说明
  • environvent_vars.md — 可用环境变量及其使用说明
  • public_api.md — Driver公开API说明
  • https://duit.pro/docs/en — 官方文档网站