超级白板 New
  • 平台类型
  • 框架 / 引擎
  • iOS
  • Android
  • macOS
  • Windows
  • Linux
  • Web
  • 小程序

创建超级白板

更新时间:2021-09-15 11:29

概念解释

  • ZegoExpress-Video SDK:ZEGO 音视频互动 SDK,能够提供超级白板所需的实时信令传输的能力。超级白板 SDK 必须搭配此 SDK 使用。
  • 超级白板 SDK、ZegoSuperBoard SDK:均指提供 ZEGO 超级白板服务(ZegoSuperBoard) 的 SDK。
  • ZegoSuperBoardView:在代码实现过程中,开发者用于展示的白板视图。
  • ZegoSuperBoardSubView:ZegoSuperBoardView 的子集,开发者实际创建的 View。ZegoSuperBoardView 会自动呈现最新创建或通过 switchSuperBoardSubView 指定的 ZegoSuperBoardSubView。
  • 纯白板:指定宽、高和页数创建的白板,用户在指定的白板画布上进行实时绘制。
  • 文件白板:基于文件创建的白板,白板宽高和页数由文件决定,实现在文件上绘制图元的业务需求。

/Pics/WhiteboardView/sync.gif

前提条件

  • 由于 ZegoSuperBoard SDK 需要与配套的 ZegoExpress-Video SDK 搭配使用,如已集成过 ZegoExpress-Video SDK,需要删除旧包并参考本页面重新集成,避免 SDK 版本不匹配造成初始化失败。
  • ZEGO 控制台 创建项目,并申请有效的 AppID 和 AppSign,详情请参考 控制台 - 项目管理

准备环境

在开始集成 ZegoSuperBoard SDK 前,请确保开发环境满足以下要求:

  • Android Studio 4.0 或以上版本。
  • Android 版本不低于 5.0 且支持音视频的 Android 设备。
  • Android 设备已经连接到 Internet。

集成 SDK

1 (可选)新建项目

此步骤以如何创建新项目为例,如果是集成到已有项目,可忽略此步骤。
  1. 打开 Android Studio,选择菜单 “File > New > New Project”。

  2. 选择项目类型 “Empty Activity”。

  3. 选择项目存储路径。

  4. 单击 “Finish” 完成新工程创建。

2 导入 SDK

ZegoSuperBoard SDK 基于 AndroidX 构建,因此被导入的项目也需要基于 AndroidX 构建。如果开发者的项目不满足该要求,请参考 迁移到 AndroidX 进行迁移。

  1. 请参考 下载 SDK 包,下载最新版本的 SDK,下载完成后进行解压。

  2. 分别将 zegoexpress.jar及对应 arm64-v8a/armeabi-v7a 文件夹、zegowhiteboardview.aar、zegodocsview.aar、zegosuperboard.aar 文件拷贝到开发者的项目目录 “app/libs/” 文件夹下。

  3. 添加 SDK 引用,进入到 “app” 目录,打开 “build.gradle” 文件。

  • 在 “defaultConfig” 节点添加 “ndk” 节点,指定支持的平台类型。
    ndk {
        abiFilters "armeabi-v7a", 'arm64-v8a'
    }
  • 在 “android” 节点添加 “sourceSets” 节点,指定 “libs” 所在目录。
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
  1. 在 “app/build.gradle” 文件中的 dependencies 节点下添加以下代码:

    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
  2. SDK 依赖以下模块,在 “app/build.gradle” 文件中的 dependencies 节点下添加以下代码:

    // 如果需要在纯java项目中集成,需要添加此依赖项
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.30" // 文档编写时最新版本为1.4.30

示例代码中 “libs” 目录仅为举例,开发者可根据实际路径填写。

3 设置权限

添加权限声明,打开 "app/AndroidManifest.xml" 文件,添加如下内容:

    <!-- SDK 必须使用的权限 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

权限说明如下:

权限 必要性 权限说明 需要理由
INTERNET 必要权限 访问网络权限 SDK 基本功能都需在联网的情况下才可以使用。
ACCESS_WIFI_STATE 必要权限 获取当前 WIFI 状态权限 SDK 会根据网络状态的改变执行不同的操作。如当网络重连的时候,SDK 内部会将网络断开时的状态都恢复,用户不需做额外的操作。
ACCESS_NETWORK_STATE 必要权限 获取当前网络状态权限 SDK 会根据网络状态的改变执行不同的操作。如当网络重连的时候,SDK 内部会将网络断开时的状态都恢复,用户不需做额外的操作。
WRITE_EXTERNAL_STORAGE 必要权限 内置 SD 卡写权限 SDK 会将日志和相关配置文件保存在内置 SD 卡内。
READ_EXTERNAL_STORAGE 必要权限 内置 SD 卡读权限 SDK 会将日志和相关配置文件保存在内置 SD 卡内。

4 防止代码混淆

在 proguard-rules.pro 文件中,为 SDK 添加 -keep 类的配置,这样可以防止混淆 SDK 公共类名称。

-keep class im.zego.zegowhiteboard.**{*;}
-keep class im.zego.zegodocs.**{*;}
-keep class im.zego.superboard.**{*;}

实现超级白板

1 初始化 SDK

初始化 ZegoExpress-Video SDK

定义 SDK 引擎对象,调用 createEngine 接口,将申请到的 AppID 和 AppSign 传入参数 “appID” 和 “appSign”,创建引擎单例对象。

如果需要注册回调,可将实现了 IZegoEventHandler 的对象传入参数 “eventHandler”。如果不需要注册回调,可将 “null” 传入参数 “eventHandler”,创建引擎后仍需要注册回调时可通过调用 setEventHandler 接口设置回调。

  • 针对 2021-09-30 及之前注册 ZEGO 控制台 的用户:

    • 从控制台申请的 AppID 和 AppSign 等信息默认是测试环境,需要在初始化 SDK 前设置测试环境,否则 SDK 会初始化失败。应用正式上线前,请向 ZEGO 商务人员申请开启正式环境。
    • createEngine 接口中的 “isTestEnv” 参数设置为 “true” 时表示使用测试环境;为 “false” 时表示使用正式环境。
  • 针对 2021-09-30 之后注册 ZEGO 控制台 的用户:

    • 控制台分配的 AppID 和 AppSign 等信息都为正式环境。
    • createEngine 接口中的 “isTestEnv” 参数取值必须修改为 “false”,表示使用正式环境。
/** 定义 SDK 引擎对象 */
ZegoExpressEngine engine;

/** 填写 appID 和 appSign */
long appID = ;  /** 请通过官网注册获取,格式为 123456789L */
String appSign = ;  /** 64个字符,请通过官网注册获取,格式为"0123456789012345678901234567890123456789012345678901234567890123" */

/** 创建引擎,使用测试环境,通用场景接入 */
engine = ZegoExpressEngine.createEngine(appID, appSign, true, ZegoScenario.GENERAL, getApplication(), null);  

初始化 ZegoSuperBoard SDK

使用 ZegoSuperBoardManagerinit 方法初始化 ZegoSuperBoard SDK。

如果回调 onInit 中的 errorCode 为 ZegoSuperBoardError.ZegoSuperBoardSuccess,代表初始化成功,可进行更多操作。errorCode 可参考 常见错误码

// 配置superBoard初始化所需要的appId和对应的appSign
ZegoSuperBoardInitConfig config = new ZegoSuperBoardInitConfig();
config.appID = KeyCenter.APP_ID;
config.appSign = KeyCenter.APP_SIGN;
// config.isTestEnv(用于切换正式/测试环境)
config.isTestEnv = true;

// 调用SuperBoardManager初始化SuperBoard sdk
// this 为Android的Application上下文,因此此段代码建议放在Application中实现
ZegoSuperBoardManager.getInstance().init(this, config, new IZegoSuperBoardInitCallback() {
    @Override
    public void onInit(int errorCode) {
        Log.d(TAG, "init ZegoSuperBoardManager result: errorCode = [" + errorCode + "]");
        if (errorCode == ZegoSuperBoardError.ZegoSuperBoardSuccess) {
            /** 初始化成功 */
        } else {
            /** 初始化失败 */
        }
    }
});

需要确保 ZegoExpress-Video SDKZegoSuperBoard SDK 均初始化成功,即调用了各自的 init() 方法并在回调中返回的errorCode等于ZegoSuperBoardError.ZegoSuperBoardSuccess,才能够执行后续的接口调用。

2 监听事件回调

根据实际应用需要,在初始化 SuperBoard 后监听想要关注的事件回调,比如错误提醒、远端新增白板文件、远端删除白板文件、远端切换白板文件等。

SuperBoard 自动实现了多端同步能力,远端通知回调内只需刷新本地UI逻辑即可。

// 常用的 SuperBoard 相关回调
// SuperBoard 自动实现了多端同步能力,远端通知回调内只需刷新本地UI逻辑即可。
ZegoSuperBoardManager.getInstance().setManagerListener(new IZegoSuperBoardManagerListener() {
    @Override
    public void onError(int errorCode) {
        //SDK 抛出的错误码。可以根据错误码提示用户一些异常情况
    }

    @Override
    public void onRemoteSuperBoardSubViewAdded(@NonNull ZegoSuperBoardSubViewModel subViewModel) {
        //远端新增白板。可以根据model里的信息更新展示的UI内容,例如白板名称等
    }

    @Override
    public void onRemoteSuperBoardSubViewRemoved(@NonNull ZegoSuperBoardSubViewModel subViewModel) {
        //远端删除白板通知
        //收到通知后可以根据当前 ZegoSuperBoardManager.getInstance().getSuperBoardView().getCurrentSuperBoardSubView() 的信息更新UI,如更新当前显示白板名称。
    }

    @Override
    public void onRemoteSuperBoardSubViewSwitched(@NonNull String uniqueID) {
        //远端切换白板的通知
        //收到通知后可以根据当前 ZegoSuperBoardManager.getInstance().getSuperBoardView().getCurrentSuperBoardSubView() 的信息更新UI,如更新当前显示白板名称。
    }

});

3 登录房间

需要确保在调用了 ZegoExpress-Video SDK 的 loginRoom() 成功后,才能够执行后续的接口调用。

传入用户 ID 参数 “userID” 创建 ZegoUser 用户对象后,调用 loginRoom 接口,传入房间 ID 参数 “roomID” 和用户参数 “user”,登录房间。

  • 同一个 AppID 内,需保证 “roomID” 全局唯一。
  • 同一个 AppID 内,需保证 “userID” 全局唯一,建议开发者将其设置成一个有意义的值,可将 “userID” 与自己业务账号系统进行关联。
  • ZegoUser 的构造方法 public ZegoUser(String userID) 会将 “userName” 设为与传的参数 “userID” 一样。“userID” 与 “userName” 不能为 “null” 否则会导致登录房间失败。
/** 创建用户 */
ZegoUser user = new ZegoUser("user1");

/** 开始登录房间 */
engine.loginRoom("room1", user);    

登录房间成功的回调需要监听中的 onRoomStateUpdate 。如果 ZegoRoomState 等于 ZegoRoomState.CONNECTED,表示登录房间成功,才能够执行后续的接口调用。

// 创建白板前需要保证登录成功,即房间回调状态为 ZegoRoomState.CONNECTED
engine.setEventHandler(new IZegoEventHandler() {
    /** 以下为常用的房间相关回调 */

    /** 房间状态更新回调 */
    @Override
    public void onRoomStateUpdate(String roomID, ZegoRoomState state, int errorCode, JSONObject extendedData) {
        /** 根据需要实现事件回调 */
        if (state == ZegoRoomState.CONNECTED) {
            // 登录房间成功,需要在登录成功之后才可以创建白板
            // 可以将创建白板的代码放在这里,确保登录房间后创建白板,也可以通过其他方法保证登录成功后再创建白板
        }
    }
});

4 添加白板视图

在登录房间之后,将 ZegoSuperBoardView 直接添加到您的业务场景视图中。示例代码如下:

ZegoSuperBoardView superBoardView = ZegoSuperBoardManager.getInstance().getSuperBoardView();
if (superBoardView != null) {
    // 添加 ZegoSuperBoardView 到指定视图中(以 Demo 中的 boardContainer 视图容器为例)。
    boardContainer.addView(superBoardView, new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.MATCH_PARENT,
            Gravity.CENTER));
}

5 创建白板

超级白板支持创建纯白板和文件白板。

  • 纯白板:指定宽、高和页数创建的白板,用户在指定的白板画布上进行实时绘制。
  • 文件白板:基于文件创建的白板,白板宽高和页数由文件决定,实现在文件上绘制图元的业务需求。

创建白板前需要保证登录成功,建议可在登录成功的回调中调用创建纯白板或文件白板的接口。

// 创建白板前需要保证登录成功,即房间回调状态为 ZegoRoomState.CONNECTED
engine.setEventHandler(new IZegoEventHandler() {
    /** 以下为常用的房间相关回调 */

    /** 房间状态更新回调 */
    @Override
    public void onRoomStateUpdate(String roomID, ZegoRoomState state, int errorCode, JSONObject extendedData) {
        /** 根据需要实现事件回调 */
        if (state == ZegoRoomState.CONNECTED) {
            // 登录房间成功,需要在登录成功之后才可以创建白板
            // 可以将创建纯白板或文件白板的代码放在这里,确保登录房间后创建白板,也可以通过其他方法保证登录成功后再创建白板
        }
    }
});
  • 创建纯白板
// 创建白板需要构造 ZegoCreateWhiteboardConfig 配置类,具体字段解释如下
ZegoCreateWhiteboardConfig config = new ZegoCreateWhiteboardConfig();
// 白板名称
config.name = "一个测试白板";
// 白板页数
config.pageCount = 5;
// 一页白板的宽度
config.perPageWidth = 960;
// 一页白板的高度
config.perPageHeight = 540;

ZegoSuperBoardManager.getInstance().createWhiteboardView(config, new IZegoSuperBoardCreateCallback() {
    @Override
    public void onViewCreated(int errorCode, @Nullable ZegoSuperBoardSubViewModel subViewModel) {
        Log.d(TAG, "createWhiteboardView() called with: errorCode = [" + errorCode + "], subViewModel = [" + subViewModel + "]");
        if (errorCode == ZegoSuperBoardError.ZegoSuperBoardSuccess) {
            /** 创建成功 */
        } else {
            /** 创建失败 */
        }
    }
});
  • 创建文件白板

创建文件白板前需要先获取文件的 fileID,可参考 共享文件管理 进行上传。

// 创建文件需要构造 ZegoCreateFileConfig 配置类
ZegoCreateFileConfig config = new ZegoCreateFileConfig();
// 文件的fileID,在上传文件成功后可以拿到
config.fileID = fileID;
ZegoSuperBoardManager.getInstance().createFileView(config, new IZegoSuperBoardCreateCallback() {
    @Override
    public void onViewCreated(int errorCode, @Nullable ZegoSuperBoardSubViewModel subViewModel) {
        Log.d(TAG, "createFileView() called with: errorCode = [" + errorCode + "], subViewModel = [" + subViewModel + "]");
        if (errorCode == ZegoSuperBoardError.ZegoSuperBoardSuccess) {
            /** 创建成功 */
        } else {
            /** 创建失败 */
        }
    }
});
  • 一个房间内最多可创建 50 个白板,房间内已存在 50 个白板时再创建白板会失败。
  • 请通过 querySuperBoardSubViewList 获取房间内当前的白板数量。

6 验证白板创建

使用多台设备运行上述项目,登录同一房间ID。用手指在任一设备的 ZegoSuperBoardView 的范围内按下移动,即可看到涂鸦效果展示在各个设备 ZegoSuperBoardView 上。

7 销毁白板

//销毁后SDK内部会自动切换到另外一个白板。展示的白板为销毁白板的上一个

//subViewModel 是白板共享列表 ZegoSuperBoardManager.getInstance().getSuperBoardSubViewModelList() 中的一个model
ZegoSuperBoardManager.getInstance().destroySuperBoardSubView(uniqueId, new IZegoSuperBoardDestroyCallback() {
    @Override
    public void onViewDestroyed(int errorCode) {
        Log.d(TAG, "onViewDestroyed() called with: errorCode = [" + errorCode + "]");
        if (errorCode == ZegoSuperBoardError.ZegoSuperBoardSuccess) {
            /** 销毁成功 */
        } else {
            /** 销毁失败 */
        }
    }
});