Create a super board
- This document is applicable to the following platforms: iOS, Android.
- The ZEGOCLOUD Super Board SDK for Flutter does not support loading dynamic PPT files on Android 8.0 devices.
Basic concepts
- ZegoExpress-Video SDK: Audio and video interactive SDK of ZEGO, which can provide the real-time signaling transmission capability required by the Super Board. The Super Board SDK must be used together with this SDK.
- Super Board SDK and ZegoSuperBoard SDK: Both refer to the SDKs that provide the ZEGO Super Board service, that is, ZegoSuperBoard.
- ZegoSuperBoardView: Whiteboard view used by developers for presentation during code implementation.
- ZegoSuperBoardSubView: Subset of ZegoSuperBoardView, which is actually created by developers. ZegoSuperBoardView will automatically presents the newly created ZegoSuperBoardSubView or specified ZegoSuperBoardSubView using switchSuperBoardSubView.
- Common whiteboard: Whiteboard created by specifying the width, height, and number of pages, and drawn by a user in real time on the specified whiteboard canvas.

Prerequisites
- Go to ZEGOCLOUD Admin Console to create a new project, and get the AppID and AppSign of your project.
- Contact ZEGOCLOUD Technical Support to enable the file sharing feature.
Prepare the environment
Please ensure that the development environment meets the following technical requirements:
- Flutter version must be between 1.10.0 and 3.13.7 (inclusive).
- Depending on the device running the sample code, the relevant technical requirements are as follows:
Please configure the development environment as follows:
- Android Studio: Go to “Preferences > Plugins”, search for the “Flutter” plugin to download it, and configure the path of the downloaded Flutter SDK in the plugin settings.
- Visual Studio Code: Search for the “Flutter” extension in the app store and download it.
After configuring the Flutter environment in either of the above development environments, run
flutter doctorin the terminal and follow the prompts to install any missing dependencies.
(optional) Create a new project
If you already have a project, you can skip this step.
If you need to know how to create a Flutter project, please refer to the official Flutter documentation Test drive.
Integrate SDK
-
In your Flutter project, open the "pubspec.yaml" file and add "zego_superboard" and "zego_express_engine" dependencies in the form of "pub".
... dependencies: zego_superboard: 2.5.0+7 # This version number is just an example; for other integrable versions, please refer to the version information (https://pub.dev/packages/zego_superboard/versions) of zego_superboard zego_express_engine: 3.10.3-whiteboard ... -
After adding and saving the file, execute
flutter pub getin the terminal. -
Import header files
In your project, import the header files of the zego_superboard SDK and zego_express_engine SDK.
import 'package:zego_superboard/zego_superboard.dart'; import 'package:zego_express_engine/zego_express_engine.dart'; -
Configure the project
Implement the Super Board
Minimal Code
ZEGOCLOUD provides a minimal example code for creating a Super Board, which can be used as a reference for development.
To run this minimal code, you need to:
- Create a "zego_superboard_page.dart" file and copy the following code into the corresponding file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:zego_superboard/zego_superboard.dart';
import 'package:zego_superboard/zego_superboard_defines.dart';
import 'package:zego_express_engine/zego_express_engine.dart';
import 'package:zego_superboard/zego_superboard_event_handler.dart';
class ZegoSuperboardPage extends StatefulWidget {
const ZegoSuperboardPage({super.key});
@override
State<ZegoSuperboardPage> createState() => _ZegoSuperboardPageState();
}
class _ZegoSuperboardPageState extends State<ZegoSuperboardPage> {
Widget? _previewViewWidget;
late int currentViewID = -1;
String userID = DateTime.now().millisecondsSinceEpoch.toString();
String userName = "zego";
String roomID = "567";
int kAppID = ; // Your AppID
String kAppSign = ""; // Your AppSign
ZegoSuperBoardManagerCreateResult? result;
@override
void initState() {
super.initState();
_initExpressSDK();
_registerEventHandler();
}
/// Initialize RTC
void _initExpressSDK() async {
ZegoEngineProfile profile = ZegoEngineProfile(kAppID, ZegoScenario.Default,
enablePlatformView: false, appSign: kAppSign);
await ZegoExpressEngine.createEngineWithProfile(profile);
_initSuperBoardSDK();
}
/// Initialize Super Board
void _initSuperBoardSDK() async {
ZegoSuperBoardInitConfig boardInitConfig =
ZegoSuperBoardInitConfig(kAppID, kAppSign, userID: userID);
// Enable file alpha environment
ZegoSuperBoardManager.instance
.setCustomizedConfig(key: 'set_alpha_env', value: 'true');
ZegoSuperBoardError boardError =
await ZegoSuperBoardManager.instance.initWithConfig(boardInitConfig);
_createCanvasView();
if (boardError.errorCode == 0) {
print('Super Board initialized successfully');
} else {
print('Super Board initialization failed');
}
}
void _createCanvasView() async {
await ZegoSuperBoardManager.instance.createCanvasView((viewID) {
currentViewID = viewID;
}).then((widget) {
setState(() {
_previewViewWidget = widget;
});
});
}
/// Register event listeners
void _registerEventHandler() {
ZegoSuperBoardEventHandler.onError = ((errorCodde) {});
ZegoSuperBoardEventHandler.onRemoteSuperBoardSubViewAdded =
((subViewModel) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardSubViewAdded]:$subViewModel');
}
});
ZegoSuperBoardEventHandler.onRemoteSuperBoardSubViewRemoved =
((subViewModel) async {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardSubViewRemoved]:$subViewModel');
}
});
ZegoSuperBoardEventHandler.onRemoteSuperBoardSubViewSwitched = ((uniqueID) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardSubViewSwitched]:$uniqueID');
}
});
ZegoSuperBoardEventHandler.onRemoteSuperBoardAuthChanged = ((authInfo) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardAuthChanged]:$authInfo');
}
});
ZegoSuperBoardEventHandler.onRemoteSuperBoardGraphicAuthChanged =
((authInfo) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardGraphicAuthChanged]:$authInfo');
}
});
ZegoSuperBoardEventHandler.onSuperBoardSubViewScrollChanged =
((uniqueID, page, pageCount) {
if (kDebugMode) {
print(
'[Flutter][onRemoteSuperBoardGraphicAuthChanged] uniqueID:$uniqueID, uniqueID:$page');
}
});
ZegoSuperBoardEventHandler.onSuperBoardSubViewSizeChanged =
((uniqueID, size) {
if (kDebugMode) {
print(
'[Flutter][onSuperBoardSubViewSizeChanged] uniqueID:$uniqueID, size:$size');
}
});
ZegoSuperBoardEventHandler.onStepChange = (() async {
if (kDebugMode) {
print('[Flutter][onStepChange]');
}
});
ZegoSuperBoardEventHandler.uploadFile = ((info) async {
if (kDebugMode) {
print('[Flutter][uploadFile] info:$info');
}
if (info['state'] == ZegoSuperBoardUploadFileState.upload.value) {
if (kDebugMode) {
print(
'[Flutter][uploadFile] upload_percent:${info['upload_percent']}');
}
} else {
Map? infoMap = info['infoMap'] as Map;
}
});
ZegoSuperBoardEventHandler.uploadH5File = ((info) async {
if (kDebugMode) {
print('[Flutter][uploadH5File] info:$info');
}
if (info['state'] == ZegoSuperBoardUploadFileState.upload.value) {
if (kDebugMode) {
print(
'[Flutter][uploadH5File] upload_percent:${info['upload_percent']}');
}
} else {
Map? infoMap = info['infoMap'] as Map;
}
});
ZegoSuperBoardEventHandler.cacheFile = ((info) {
if (kDebugMode) {
print('[Flutter][cacheFile] info:$info');
}
if (info['state'] == ZegoSuperBoardCacheFileState.caching.value) {}
});
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Container(
color: Colors.white,
child: Column(
children: [
Container(
color: Colors.grey.withOpacity(0.1),
width: double.infinity,
height: 248,
child: _previewViewWidget ?? Container(),
),
const SizedBox(height: 10),
Expanded(
child: Column(
children: [
TextButton(
onPressed: _loginRoom,
child: const Text(
'Login to Room',
style: TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold),
)),
TextButton(
onPressed: _createWhiteboardView,
child: const Text(
'Create Pure Whiteboard',
style: TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold),
)),
TextButton(
onPressed: _destroySuperBoardSubView,
child: const Text(
'Destroy Current Super Board',
style: TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold),
),
),
],
),
)
],
)));
}
/// Login to room
void _loginRoom() async {
ZegoUser user = ZegoUser(userID, userName);
ZegoRoomConfig config = ZegoRoomConfig.defaultConfig();
config.isUserStatusNotify = true;
ZegoRoomLoginResult result = await ZegoExpressEngine.instance
.loginRoom(roomID, user, config: config);
if (kDebugMode) {
print(
'[Flutter][loginRoom] result: $result errorCode: ${result.errorCode}');
}
}
/// Create pure whiteboard
void _createWhiteboardView() async {
ZegoCreateWhiteboardConfig whiteboardConfig = ZegoCreateWhiteboardConfig(
'Create Pure Whiteboard',
perPageWidth: 16,
perPageHeight: 9,
pageCount: 5);
result = await ZegoSuperBoardManager.instance
.createWhiteboardView(config: whiteboardConfig);
if (kDebugMode) {
print(
'[Flutter][createWhiteboardView] result: $result errorCode: ${result!.boardError.errorCode}');
}
}
/// Destroy whiteboard
void _destroySuperBoardSubView() async {
if (result != null) {
ZegoSuperBoardManager.instance
.destroySuperBoardSubView(result!.model.uniqueID);
}
}
}- In the "main.dart" file, import the created route ZegoSuperboardPage.
...
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Superboard view flutter app'),
),
body: const ZegoSuperboardPage(),
),
);
}
...1. Initialize the SDK
Initialize the ZEGO Express Video SDK
Call the createEngineWithProfile interface of Express Video SDK and pass in the applied AppID and AppSign Parameters "appID" and "appSign" create an engine singleton object.
int appID = ; // Your appid
String appSign = ''; // Your appSign
ZegoScenario scenario = ZegoScenario.Default;
ZegoEngineProfile profile = ZegoEngineProfile(appID, scenario, enablePlatformView: false, appSign: appSign);
await ZegoExpressEngine.createEngineWithProfile(profile);Initialize ZegoSuperBoard SDK
Call the initWithConfig method to initialize the ZegoSuperBoard SDK.
If the return value is 0, it means the initialization is successful, and you can perform more operations. For the errorCode, you can refer to Error codes.
/**
* appID: The application ID issued by ZEGOCLOUD for developers. Please apply for it from the ZEGO console at <https://console.zego.im>.
* appSign: The application appSign issued by ZEGOCLOUD for developers. Please apply for it from the ZEGO console at <https://console.zego.im>.
*/
// Create an initialization configuration class
String userID = 'userid';
ZegoSuperBoardInitConfig boardInitConfig = ZegoSuperBoardInitConfig(appID, appSign, userID: userID);
ZegoSuperBoardError boardError = await ZegoSuperBoardManager.instance.initWithConfig(boardInitConfig);Please initialize ZegoExpress-Video SDK and ZegoSuperBoard SDK successfully before calling other methods.
2. Listen for event callbacks
Based on the actual application needs, you can listen for the concerned event callbacks after the ZegoSuperBoard SDK is initialized. The callbacks include error reminders, adding whiteboard files remotely, deleting whiteboard files remotely, and switching whiteboard files remotely.
The SuperBoard automatically realizes the multi-end synchronization capability, and only needs to refresh the local UI logic in the remote notification callback.
- onError: Error codes thrown by the SDK. For errorCode reference, see Error codes.
- onRemoteSuperBoardSubViewAdded: Notification for a new whiteboard added remotely.
- onRemoteSuperBoardSubViewRemoved: Notification for a whiteboard destroyed remotely.
- onRemoteSuperBoardSubViewSwitched: Notification for switching whiteboard files remotely.
ZegoSuperBoardEventHandler.onError = ((errorCodde) {});
ZegoSuperBoardEventHandler.onRemoteSuperBoardSubViewAdded = ((subViewModel) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardSubViewAdded]:$subViewModel');
}
});
ZegoSuperBoardEventHandler.onRemoteSuperBoardSubViewRemoved = ((subViewModel) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardSubViewRemoved]:$subViewModel');
}
});
ZegoSuperBoardEventHandler.onRemoteSuperBoardSubViewSwitched = ((uniqueID) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardSubViewSwitched]:$uniqueID');
}
});
ZegoSuperBoardEventHandler.onRemoteSuperBoardAuthChanged = ((authInfo) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardAuthChanged]:$authInfo');
}
});
ZegoSuperBoardEventHandler.onRemoteSuperBoardGraphicAuthChanged = ((authInfo) {
if (kDebugMode) {
print('[Flutter][onRemoteSuperBoardGraphicAuthChanged]:$authInfo');
}
});
ZegoSuperBoardEventHandler.onSuperBoardSubViewScrollChanged = ((uniqueID, page, pageCount) {
if (kDebugMode) {
print(
'[Flutter][onRemoteSuperBoardGraphicAuthChanged] uniqueID:$uniqueID, uniqueID:$page');
}
});
ZegoSuperBoardEventHandler.onSuperBoardSubViewSizeChanged = ((uniqueID, size) {
if (kDebugMode) {
print(
'[Flutter][onSuperBoardSubViewSizeChanged] uniqueID:$uniqueID, size:$size');
}
});3. Log in to the room
You can call the loginRoom interface of ZegoExpressEngine to log in to the room. If the room does not exist, the room will be created and logged in when this interface is called.
The parameters of roomID and user are generated locally by you, but they need to meet the following conditions::
- Within the same AppID, "roomID" must be globally unique.
- Within the same AppID, "userID" must be globally unique. It is recommended that developers associate "userID" with their own business account system.
- "userID" and "userName" cannot be "nil", otherwise it will cause the room login to fail.
- The constructor of ZegoUser will set the userName to be the same as the parameter userID you passed.
void loginRoom() {
// The "roomID" is generated locally and must be globally unique. Different users need to log in to the same room to communicate.
String roomID = "room1";
// Create a user object. The constructor `userWithUserID` of ZegoUser will set "userName" to be the same as the passed parameter "userID". "userID" and "userName" cannot be "nil", otherwise it will cause the room login to fail.
// The "userID" is generated locally and must be globally unique.
ZegoUser user = ZegoUser('user1', 'userName');
// Only when a ZegoRoomConfig with the "isUserStatusNotify" parameter set to "true" is passed, can the onRoomUserUpdate callback be received.
ZegoRoomConfig config = ZegoRoomConfig.defaultConfig();
config.isUserStatusNotify = true;
// Log in to the room
ZegoExpressEngine.instance
.loginRoom(roomID, user, config: config)
.then((result) => {});
}4. Add a Whiteboard View
Ensure that the ZegoSuperBoard SDK is initialized successfully and that you have logged into a room before calling the createCanvasView interface to obtain the business scenario Widget. This Widget is used to directly add the whiteboard view (ZegoSuperBoardView) to your business scenario view. Example code is as follows:
// Add this Widget to the page's render tree to display the whiteboard view
_containerWidget = await ZegoSuperBoardManager.instance.createCanvasView((viewID){
});5. Create a whiteboard
Before creating a whiteboard, you need to ensure that the login is successful. It is recommended to call the interface for creating a common whiteboard in the callback of a successful login.
// Before creating a whiteboard, you need to ensure that the login is successful, i.e., the room callback status is ZegoRoomState.Connected
ZegoExpressEngine.onRoomStateUpdate = (String roomID, ZegoRoomState state,
int errorCode, Map<String, dynamic> extendedData) {
if (state == ZegoRoomState.Connected && errorCode == 0) {
// This indicates that the login is successful, and you can only create a whiteboard after a successful login
}
};A Super Board can be used to create a common whiteboard.
- Common whiteboard: Whiteboard created by specifying the width, height, and number of pages, and drawn by a user in real time on the specified whiteboard canvas.
At most 50 whiteboards can be created in a room. The whiteboard creation will fail if the room already has 50 whiteboards.
To obtain the current number of whiteboards in a room, call the querySuperBoardSubViewList method.
ZegoCreateWhiteboardConfig whiteboardConfig = ZegoCreateWhiteboardConfig(
'A test whiteboard',
perPageWidth: 16,
perPageHeight: 9,
pageCount: ZogoManager.instance.pageCount);
ZegoSuperBoardManagerCreateResult? result = await ZegoSuperBoardManager.instance.createWhiteboardView(config: whiteboardConfig);6. Destroy a whiteboard
If you need to destroy a specific whiteboard, call the destroySuperBoardSubView interface and pass in the uniqueID of that whiteboard to destroy it.
// After destruction, the SDK will automatically display another whiteboard. The displayed whiteboard will be the one before the destroyed whiteboard.
await ZegoSuperBoardManager.instance.destroySuperBoardSubView('uniqueID');Test Your App
Run the above project on multiple devices and log in with the same room ID. By pressing and moving your finger within the range of the ZegoSuperBoardView on any device, you can see the doodle effect displayed on the ZegoSuperBoardView of each device.
Learn More
So far, you have successfully built a simple Super Board application. Next, you can explore more features of the Super Board through the following documentation:

