Skip to content

pili-engineering/QNDroidWhiteBoardSDK

Repository files navigation

WhiteBoard-SDK

  • 实时交互白板的Android版SDK

快速接入

依赖配置

    implementation (name:'qndroid-whiteboard-xxx',ext:"aar") //白板
    implementation("com.squareup.okhttp3:okhttp:x.x.x")//需要依赖okhttp
    implementation ('com.aliyun.dpa:oss-android-sdk:x.x.x')
android {
    defaultConfig{
        // 当前仅支持arm架构
        ndk {
            abiFilters 'armeabi-v7a' , 'arm64-v8a'
        }
    }
}

初始化SDK

  • SDK需要在Application中初始化一次
class MyApplication : Application(){
    override fun onCreate() {
        super.onCreate()

        QNWhiteBoard.init(this)
    }
}

白板的activity的layout文件中引入com.qiniu.droid.whiteboard.QNWhiteBoardView控件, 控件大小最好与用户设定的白板宽高比相同,否则边缘可能会留白。

例如:

<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    ...

   <com.qiniu.droid.whiteboard.QNWhiteBoardView
                android:id="@+id/white_board"
                android:layout_width="0dp"
                android:layout_height="0dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintDimensionRatio="2048:1440"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/horizontalScrollView" />

</androidx.constraintlayout.widget.ConstraintLayout>

实例中通过app:layout_constraintDimensionRatio参数设定宽高比,比例中的数字时白板的虚拟大小,决定了白板中内容的坐标系。

加入房间

首先访问自己的服务器获取要加入的白板房间的token(和rtc使用同一个token)参数(房间的创建和token的生成由服务器对接SDK服务端接口)。

如果您还不知道如何生成 RoomToken,请先阅读 七牛实时音视频云接入指南

首先构建进房参数JoinConfig,然后执行QNWhiteBoard.joinRoom来加入房间。

    val config = JoinConfig(
                    token   //通过后台取到的房间token
            ).apply {
                widthHeightThan=0.5 //白板宽高比 范围[0.5,2.2] 默认0.5
                roleId = 6 // 由用户设定的值,指示本用户在房间中的角色,
                           // 方便用户实现自己的权限管理,默认为0
                sessionId = "xxxx" // 如果用户的业务系统支持单用户多点登录并进入同一个白板房间,
                                   // 那么这个id就是全局唯一的用户标识,此时[userId]可能有相同值,
                                   // 但是[sessionId]必须唯一。可空,留空时sdk会自动生成一个随机id。
                nickname = "xxx" // 本用户在房间中的昵称,可空。
                avatar = "http://xxxx/ssss.jpg" // 本用户在房间中的头像地址,可空。
            }
    QNWhiteBoard.joinRoom(config);

如果加入房间成功,会收到onJoinSuccess回调,如果加入失败会收到onJoinFailed回调。

关闭并离开房间

房间关闭时,比如离开房间的Activity时,必须调用leaveRoom来退出房间并释放资源, 此方法会同时完成离开房间和资源释放,同时可以自动释放QNAutoRemoveWhiteBoardListener类型的事件监听器(推荐),多次执行是安全的。

通常情况会把它放在Activity.onDestroy中执行,比如:

    override fun onDestroy() {
        WhiteBoard.leaveRoom()
        super.onDestroy()
    }

自定义控制面板UI

      <LinearLayout
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:orientation="vertical">

               <androidx.appcompat.widget.AppCompatImageButton
                   android:id="@+id/restore"
                   style="@style/WhiteBoardActionButton"
                   android:tint="?attr/colorOnPrimary"
                   app:backgroundTint="?attr/colorSecondary"
                   app:srcCompat="@drawable/ic_baseline_undo_24"
                   app:visibleGone="@{viewModel.canRecovery}" />

               <androidx.appcompat.widget.AppCompatImageButton
                   android:id="@+id/select"
                   style="@style/WhiteBoardActionButton"
                   app:selected="@{viewModel.currentInputType == InputType.SELECT}"
                   app:srcCompat="@drawable/ic_selection" />

               <androidx.appcompat.widget.AppCompatImageButton
                   android:id="@+id/pen"
                   style="@style/WhiteBoardActionButton"
                   android:tint="@{viewModel.normalPenStyle.Companion.colors[viewModel.normalPenStyle.colorIndex]}"
                   app:selected="@{viewModel.currentInputType == InputType.NORMAL}"
                   app:srcCompat="@drawable/ic_pen_normal" />

               <androidx.appcompat.widget.AppCompatImageButton
                   android:id="@+id/mark"
                   style="@style/WhiteBoardActionButton"
                   android:tint="@{viewModel.markPenStyle.Companion.colors[viewModel.markPenStyle.colorIndex]}"
                   app:selected="@{viewModel.currentInputType == InputType.MARK}"
                   app:srcCompat="@drawable/ic_pen_mark" />

               <androidx.appcompat.widget.AppCompatImageButton
                   android:id="@+id/eraser"
                   style="@style/WhiteBoardActionButton"
                   app:selected="@{viewModel.currentInputType == InputType.ERASE}"
                   app:srcCompat="@drawable/ic_eraser" />

               <androidx.appcompat.widget.AppCompatImageButton
                   android:id="@+id/laser"
                   style="@style/WhiteBoardActionButton"
                   app:selected="@{viewModel.currentInputType == InputType.LASER}"
                   app:srcCompat="@drawable/ic_pen_laser" />

               <androidx.appcompat.widget.AppCompatImageButton
                   android:id="@+id/geometry"
                   style="@style/WhiteBoardActionButton"
                   app:selected="@{viewModel.currentInputType == InputType.GEOMETRY}"
                   app:srcCompat="@drawable/ic_geometry" />

               <androidx.appcompat.widget.AppCompatImageButton
                   android:id="@+id/insert_file"
                   style="@style/WhiteBoardActionButton"
                   app:srcCompat="@drawable/ic_file_upload" />

           </LinearLayout>
.....

绑定事件操作

       //选择笔
       inputPen.setOnClickListener((View.OnClickListener) v -> {
           //todo 选择笔型号 笔颜色 大小
           QNWhiteBoard.setInputMode(InputConfig.pen(17, Color.parseColor("#22ddff")))
       });
       //插入文件
       inputFile.setOnClickListener((View.OnClickListener) v -> {          //选择文件
           String path = selectFile();
           // 插入文件
           QNWhiteBoard.insertFile(new FileConfig(File(path)));
       });
       //使用橡皮
       inputErase.setOnClickListener((View.OnClickListener) v -> {
           //todo 选择橡皮大小
           QNWhiteBoard.setInputMode(InputConfig.erase(12));
       });
       //撤销
       mWhiteBoardViewControllerView.recover.setOnClickListener((View.OnClickListener) v -> { 
           QNWhiteBoard.recover();
       });

设置回调

 QNWhiteBoard.getInstance().addListener(new QNAutoRemoveWhiteBoardListener() {

            @Override
            public void onJoinSuccess(@NonNull Room var1, @NonNull RoomMember var2) {
              //白板房间加入成功
            }

            @Override
            public void onJoinFailed(int var1) {
                //白板加入失败
            }

            @Override
            public void onBoardSizeChanged(@NonNull WhiteBoardViewport viewport) {
                int width = viewport.size.displayWidth;
                int height = viewport.size.displayHeight;
               //todo 根据白板ui尺寸变化跟新显示UI样式
            }

            @Override
            public void onWidgetActive(@Nullable ActiveWidgetInfo activeWidgetInfo) {
                //用户书写或操作白板时会激活被操作的widget,同时触发此事件
                //todo 跟新自定义显示UI
                mWhiteBoardViewControllerView.onWidgetActive(activeWidgetInfo);
            }

            @Override
            public void onFilePageChanged(@NonNull ActiveWidgetInfo activeWidgetInfo) {
               //当文件被翻页时触发,同时会触发onWidgetActive。 当前仅被激活的文件发生翻页时才会收到此事件
               // todo 跟新自定义显示UI
                mWhiteBoardViewControllerView.onFilePageChanged(activeWidgetInfo);
            }

            @Override
            public void onWidgetActionEvent(@NonNull WidgetActionEvent var1) {
                //widget被执行了某些关键动作
                //比如有人插入文件或删除文件会收到此事件。 同时每个远端用户的文件加载情况也会触发此事件,通过此事件可以观察到每个人文件加载成功或失败情况。
                // todo 跟新自定义显示UI
                mWhiteBoardViewControllerView.onFilePageChanged(activeWidgetInfo);
            }
             ....
        });

api

  • 所有用户可以主动调用的方法都是QNWhiteBoard类的静态方法
方法名称 方法描述
init 初始化白板SDK
joinRoom 进入白板房间
leaveRoom 离开白板房间
addListener 添加一个白板事件监听器
removeListener 移除一个白板事件监听器
clearListener 清空所有白板监听器

主动控制的方法

  • 所有用户可以主动调用的方法都是QNWhiteBoard类的静态方法
方法名称 方法描述
setDefaultInputMode 设置白板的默认初始输入模式配置
setRetry 设置白板断线自动重连次数
setInputMode 改变白板的输入模式
setBackgroundColor 设置白板背景色
scroll 垂直滚动白板显示区
newBoardPage 新建白板页
insertBoardPage 插入新白板页
jumpBoardPage 跳转到目标白板页
preBoardPage 后退到上一页
nextBoardPage 前进到下一页
deleteBoardPage 删除白板页
insertFile 向当前白板页中插入文件
jumpFilePage 文件翻页
deleteFile 删除文件
recover 撤销一次擦除的笔迹
screenshots 白板截图
cleanBoardPage 白板清屏

获取白板当前属性的方法

  • 所有用户可以主动调用的方法都是QNWhiteBoard类的静态方法
方法名称 方法描述
getStatus 获取白板当前状态
getRoom 获取当前加入的房间信息
getMe 获取当前房间中的个人信息
getUsers 获取当前房间中的用户列表
getPageList 获取当前白板的全部页信息列表
getCurrentPage 获取当前白板页信息
getBackgroundColor 获取当前显示的白板背景色
getInputConfig 获取当前使用的白板输入模式
getActiveWidget 获取当前被激活操作的widget
canRecovery 是否存在可还原的笔迹
getViewport 获取当前白板的窗口尺寸信息

添加事件监听器

事件名称 事件描述
onJoinSuccess 成功加入白板房间
onJoinFailed 加入房间失败
onReconnecting 白板正在自动重连
onReconnected 自动重连成功
onDisconnected 房间彻底断开连接
onBoardStatusChanged 白板房间状态变化
onUserList 当前已经在房间中的用户列表
onUserJoin 有其它用户加入了房间
onUserLeave 有其它用户离开了房间
onBoardPageList 白板页信息列表
onCurrentBoardPageChanged 白板当前页变化
onBoardPageInfoChanged 某一个白板页信息变化
onBoardSizeChanged 白板的虚拟大小发生变化
onBoardScroll 白板内发生滚动
onBackgroundColorChanged 白板背景色变化
onWidgetActive 有widget被激活
onFilePageChanged 文件被翻页
onWidgetActionEvent widget被执行了某些关键动作
onRecoveryStateChanged 笔迹回收站状态变化

|onPageCleaned|清屏成功回调| |onFileScrolled|文件滑动回调|

QNWhiteBoard

所有白板SDK的主动用户接口,所有接口线程安全

init

public static void init(@NonNull Context context , boolean debug)

初始化白板SDK

应用启动后只需调用一次,最好在Application中调用。

参数 描述
context Android上下文
debug 是否开启debug模式,如果为true则sdk会输出一些日志

joinRoom

public static void joinRoom(@NonNull JoinConfig config)

进入白板房间

只有此方法执行成功才能连通白板,目前sdk仅支持同时进入一个房间,多次调用是安全的,但仅有第一次调用的参数有效,后续调用会被忽略,如需进入其它房间,需要先执行leaveRoom

加入成功后本地会收到onJoinSuccess回调,加入失败则会收到onJoinFailed回调。 同时远端用户会收到onUserJoin回调。

如果已经加入成功但是发生了掉线,则SDK会尝试自动重连,并收到onReconnecting回调。 重连次数可以通过setRetry修改,重连成功后会收到onReconnected,重连失败会收到onDisconnected,此时必须用户手动调用此方法重新加入房间。

参数 描述
config 房间和身份信息

leaveRoom

public static void leaveRoom()

离开白板房间

该方法会断开白板连接并释放资源,同时会清理所有的QNAutoRemoveWhiteBoardListener类型的监听器。 多次调用是安全的。 离开白板后远端用户会收到onUserLeave回调。

addListener

public static void addListener(@NonNull QNWhiteBoardListener listener)

添加一个白板事件监听器

如果添加QNWhiteBoardListener的直接子类则会永久存续,直到使用removeListener移除。 如果添加QNAutoRemoveWhiteBoardListener的子类则可以在leaveRoom时自动移除,无需手动执行removeListener

可以在joinRoom之前或之后添加

参数 描述
listener 事件监听器

removeListener

public static void removeListener(@NonNull QNWhiteBoardListener listener)

移除一个白板事件监听器

可在任何时候调用。

参数 描述
listener 监听器实例

clearListener

public static void clearListener()

清空所有白板监听器

会清空所有的监听器,包括QNWhiteBoardListenerQNAutoRemoveWhiteBoardListener类型的全部监听器。

可在任何时候调用。

screenshots

public static void screenshots(@NonNull ScreenshotsCallback listener)

白板截图

仅在QNWhiteBoardView附加到布局中时有效(即必须有可见的白板),回调ScreenshotsCallback将在非主线程执行。

参数 描述
listener 截图回调,在非主线程回调,截图成功会返回Bitmap,失败返回null

setDefaultInputMode

public static void setDefaultInputMode(@NonNull InputConfig config)

设置白板的默认初始输入模式配置

joinRoom之前调用有效,已经进入房间时调用此方法不会改变当前的输入模式,仅会影响下次进入房间的输入模式。 如需改变当前房间中的输入模式,请调用setInputMode方法。

此方法用于预先设定加入房间后的初始输入配置,反复加入离开房间不会影响此默认设置。 默认设置不会随setInputMode方法改变,即一次设定长期有效。

参数 描述
config 输入模式配置

cleanBoardPage

public static void cleanBoardPage(String pageId)

清空指定页面的画布上的内容

参数 描述
pageId 页面id

setRetry

public static void setRetry(int count)

设置白板断线自动重连次数

默认为10次,设为0表示不自动重连。

参数 描述
count 重连次数

setInputMode

public static void setInputMode(@NonNull InputConfig config)

改变白板的输入模式

此方法用于已经连通白板房间时改变用户对白板的输入模式,包括例如笔迹的粗细和颜色等。

参数 描述
config 输入模式配置

setBackgroundColor

public static void setBackgroundColor(@ColorInt int color)

设置白板背景色

用于在白板房间中改变当前白板页的背景色,未进入房间调用无效。

  • 仅能改变当前页面的背景以及此后新增的页面背景,不会影响已经存在的页面背景。
参数 描述
color 颜色值(支持透明)

scroll

public static void scroll(float offsetY)

垂直滚动白板显示区

  • 目前白板是一个纵向可滚动(高大于宽)的矩形,通常白板的可视区WhiteBoardViewport不能呈现完整白板,需要通过滚动来控制可见区。
  • 白板内部可以通过用户的双指操作来滚动白板,无需外部干涉,此方法的目的是方便用户实现类似top按钮或滚动条功能。

无论是调用此方法还是用户通过白板手势滚动了白板(包括远程用户滚动白板),都会触发onBoardScroll回调。

参数 描述
offsetY 白板的垂直偏移量,此值为总量而非增量,当前值在WhiteBoardViewport中描述

newBoardPage

public static void newBoardPage()

新增白板页

在房间中调用可以在当前页列表末尾插入一个新的页面并会自动跳转到这个新页面。

页面创建成功后用户会收到onCurrentBoardPageChangedonBoardPageListonBoardPageInfoChanged三个回调。

insertBoardPage

public static void insertBoardPage(@NonNull String pageId)

插入新白板页

在指定的页面之前插入一个新白板页,同时白板会自动跳转到新插入的页面。

页面创建成功后用户会收到onCurrentBoardPageChangedonBoardPageListonBoardPageInfoChanged三个回调。

参数 描述
pageId 目标插入位置的页id,此id来自于页数据,可通过getPageListgetCurrentPage获取页列表或当前显示页数据,也可通过onBoardPageListonCurrentBoardPageChanged回调来收集

jumpBoardPage

public static void jumpBoardPage(@NonNull String pageId)

跳转到指定白板页

直接跳页的实现方式。

跳转成功后用户会收到onCurrentBoardPageChangedonBoardPageInfoChanged回调。

参数 描述
pageId 跳转目标的页id,此id来自于页数据,可通过getPageListgetCurrentPage获取页列表或当前显示页数据,也可通过onBoardPageListonCurrentBoardPageChanged回调来收集

preBoardPage

public static void preBoardPage()

返回到上一页

成功后用户会收到onCurrentBoardPageChangedonBoardPageInfoChanged回调。

nextBoardPage

public static void nextBoardPage()

前进到下一页

成功后用户会收到onCurrentBoardPageChangedonBoardPageInfoChanged回调。

deleteBoardPage

public static void deleteBoardPage(@NonNull String pageId)

删除白板页

删除成功后一定会收到onBoardPageList回调,如果删除的是当前页会同时触发onCurrentBoardPageChanged, 如果删除当前页时仅有的一页,则白板会忽略本次操作。

参数 描述
pageId 要删除的页id,此id来自于页数据,可通过getPageListgetCurrentPage获取页列表或当前显示页数据,也可通过onBoardPageListonCurrentBoardPageChanged回调来收集

insertFile

public static void insertFile(@NonNull FileConfig config)

向当前白板页中插入文件

支持的格式有图片jpg,png 文档pdf,doc,docx,dot,wps,wpt,dotx,docm,dotm,rtf 演示文稿ppt,pptx,pot,potx,pps,ppsx,dps,dpt,pptm,potm,ppsm 表格xls,xlsx,xlt,et,ett,xltx,csv,xlsb,xlsm,xltm 如果试图插入不支持的文件类型则会被忽略。

图片尽量上传2K及以下的尺寸,否则某些老旧设备可能无法加载。 office文件需要在线转换格式,所以画面呈现会相对慢一些。

文件插入后会收到大量onWidgetActionEvent回调(与房间人数有关),此回调仅表达了导致文件状态变化的用户信息和此用户的加载情况, 通常用于在界面上表达房间中各成员对此文件的加载状态。

参数 描述
config 文件配置信息

jumpFilePage

public static void jumpFilePage(@NonNull String widgetId , int pageNo)

文件翻页

对于可翻页的文件,如pdf和office文件,通过调用此方法可以使文件跳到指定序号的页面。

翻页成功后会收到onFilePageChanged回调。

参数 描述
widgetId 文件的widgetId,每个文件都有一个id,可以通过getActiveWidget方法获取当前用户正在操作的Widget,也可以通过onWidgetActive收集当前正在操作的Widget
pageNo 跳转的目标页号,从1开始,如果序号超出文件范围,跳转会失败并忽略

deleteFile

public static void deleteFile(@NonNull String widgetId)

删除文件

删除后会触发onWidgetActionEvent回调,如果删除的文件是当前正在激活的widget,则会收到onWidgetActive回调,并且参数为null。

参数 描述
widgetId 文件的widgetId,每个文件都有一个id,可以通过getActiveWidget方法获取当前用户正在操作的Widget,也可以通过onWidgetActive收集当前正在操作的Widget

recover

public static void recover()

还原最近一次擦除的笔迹

在输入模式为橡皮模式InputConfig.erase时,本用户擦除的笔迹可以通过调用此方法来还原(回滚)。 一次擦除的笔迹指的是用户从落下手指移动擦除线条到抬起手指为止期间擦掉的所有线条。

  • 当切换到其它输入模式或者白板翻页后擦除的笔迹缓存将会清空,将无法再还原擦掉的笔迹,即此方法仅在InputConfig.erase模式下有效。
  • 此方法多次调用是安全的。
  • 判断当前是否有可还原的笔迹可以通过调用canRecovery或监听onRecoveryStateChanged回调获知。

getStatus

@NonNull public static BoardStatus getStatus()

获取白板当前状态

也可以监听onBoardStatusChanged

getRoom

@Nullable public static Room getRoom()

获取当前加入的房间信息

与监听onJoinSuccess获得的信息一致。

  • 返回
    • 房间信息Room,如果未加入房间则会返回null。

getMe

@Nullable public static RoomMember getMe()

获取当前房间中的个人信息

与监听onJoinSuccess获得的信息一致。

  • 返回
    • 自己的成员信息RoomMember,如果未加入房间则会返回null。

getUsers

@NonNull public static List<RoomMember> getUsers()

获取当前房间中的全部用户列表(包括自己)

此列表与监听onUserListonUserJoinonUserLeave收集获得的列表一致。

  • 返回
    • 一个只读的RoomMember成员信息列表,如果未加入房间则会返回空列表。

getPageList

@NonNull public static List<WhiteBoardPage> getPageList()

获取当前白板的全部页信息列表

此列表与监听onBoardPageListonBoardPageInfoChanged处理后获得的列表一致。

  • 返回
    • 一个只读的WhiteBoardPage白板页信息列表,如果未加入房间则会返回空列表。

getCurrentPage

@Nullable public static WhiteBoardPage getCurrentPage()

获取当前显示的白板页信息

此信息与监听onCurrentBoardPageChanged获得的信息一致。

  • 返回
    • 当前白板页信息WhiteBoardPage,如果未加入房间则会返回null。

getBackgroundColor

@ColorInt public static int getBackgroundColor()

获取当前白板页的背景色

此值与监听onBackgroundColorChanged获得的颜色一致。 可通过调用setBackgroundColor改变当前白板页的背景。 默认背景色由服务器创建房间时指定。

  • 返回
    • 当前白板页颜色值,如果未加入房间则会返回一个固定值Color.LTGRAY

getInputConfig

@NonNull public static InputConfig getInputConfig()

获取白板当前的输入模式

getActiveWidget

@Nullable public static ActiveWidgetInfo getActiveWidget()

获取当前被激活操作的widget信息

此信息与监听onWidgetActive获得的数据一致。

  • 返回
    • ActiveWidgetInfo,如果当前用户没有操作过任何widget或者用户未加入房间则会返回null。

canRecovery

public static boolean canRecovery()

是否存在可还原的笔迹(擦除还原,仅对笔迹有效)

此值与监听onRecoveryStateChanged回调获取的值一致。

  • 返回
    • 如果为true表示有可还原的笔迹,此时可通过调用recover来还原一次擦除操作。false时调用recover无效。

getViewport

@NonNull public static WhiteBoardViewport getViewport()

获取当前白板的可视区信息,包括白板的大小和偏移

此数据与监听onBoardSizeChangedonBoardScroll获取的数据一致。 滚动白板可由用户双指手势拖动白板,也可通过程序主动调用scroll完成。

QNWhiteBoardListener

所有的白板事件的监听器,所有事件响应均在主线程回调。 可通过addListener添加。

QNAutoRemoveWhiteBoardListener

public interface QNAutoRemoveWhiteBoardListener extends QNWhiteBoardListener

能自动移除的白板事件监听器(推荐使用) 此监听器同样可以在任何时期添加,但是会伴随leaveRoom的调用而自动移除,无需用户手动执行removeListener

onJoinSuccess

void onJoinSuccess(@NonNull Room room , @NonNull RoomMember me)

成功加入白板房间

joinRoom成功后的第一个关键事件(onBoardStatusChanged返回BoardStatus.SUCCESSFUL会先一步触发)。 在这里可以处理一些加入房间成功时的初始化工作。

  • 在断线重连成功时同样会触发此事件,之后才会触发onReconnected事件。
参数 描述
room 房间信息
me 个人信息,由joinRoom传递的JoinConfig中携带的信息

onJoinFailed

void onJoinFailed(int errorCode)

加入房间失败

joinRoom执行失败后触发,因为并没有成功加入房间,所以不会执行自动重连。 失败后需要用户重新调用joinRoom来加入房间。 如果已经成功加入了房间但是发生了断线则会触发onReconnecting尝试自动重连,重连失败则会触发onDisconnected,而不会触发本事件。

参数 描述
errorCode 失败错误码

onReconnecting

void onReconnecting(int times)

白板正在自动重连

当白板连接意外断开比如网络波动等,白板会自动尝试重连,在每次尝试开始时会触发此事件。 重连成功后会先触发onJoinSuccess后触发onReconnected, 重连次数达到上限后会触发失败事件onDisconnected。 首次调用joinRoom失败不会自动重连,而是触发onJoinFailed

重连次数默认10次,可通过setRetry修改。

参数 描述
times 当前为第几次重试

onReconnected

void onReconnected()

自动重连成功

参考onReconnecting

onDisconnected

void onDisconnected()

自动重连失败,白板彻底断开连接

即在onReconnecting重试次数达到上限后触发, 此时需要用户重新执行joinRoom加入房间。

onBoardStatusChanged

void onBoardStatusChanged(@NonNull BoardStatus status)

白板房间状态变化

joinRoomleaveRoom之间,只要白板房间的状态发生变化就会触发此事件。 同时此事件触发早于onJoinSuccessonJoinFailedonReconnecting等独立事件。 比如调用joinRoom后会立即触发BoardStatus.LOADING的变化,onJoinSuccess触发之前会先触发BoardStatus.SUCCESSFUL的变化。

参数 描述
status 新的白板状态

onUserList

void onUserList(@NonNull List<RoomMember> users)

当前已经在房间中的用户列表(包括自己)

加入房间后会触发一次返回已经在房间中的用户,自动重连成功后也会触发。

  • 如果自己管理用户列表,需要以此回调的作为列表初始数据,并且在重连成功后重置初始列表。
  • 后续的远端用户进出事件由onUserJoinonUserLeave反馈。
  • getUsers总是获取当前的完整用户列表。
参数 描述
users 已经在房间中的用户信息RoomMember列表,此列表为只读列表

onUserJoin

void onUserJoin(@NonNull RoomMember user)

有远端用户加入了房间

  • 如果自己维护用户列表,注意更新列表数据
参数 描述
user 用户信息

onUserLeave

void onUserLeave(@NonNull RoomMember user)

有远端用户离开了房间

  • 如果自己维护用户列表,注意更新列表数据
参数 描述
user 用户信息

onBoardPageList

void onBoardPageList(@NonNull List<WhiteBoardPage> list)

白板页信息列表

在首次进入房间和白板页列表结构变化时触发,比如新增页,删除页等等。 仅翻页不会触发此事件。

参数 描述
list 白板页信息WhiteBoardPage的只读列表,也可以通过getPageList获得

onCurrentBoardPageChanged

void onCurrentBoardPageChanged(@NonNull WhiteBoardPage page)

白板当前页改变

在首次加入房间后和翻页时触发,新增页由于会自动切换到新页面,所以也会触发。

参数 描述
page 当前显示的白板页信息,也可以通过getCurrentPage获得

onBoardPageInfoChanged

void onBoardPageInfoChanged(@NonNull WhiteBoardPage page)

某一个白板页信息变化

目前仅白板页的缩略图地址发生变化时才会触发此事件,每当白板发生翻页时都会自动更新上一个页面的缩略图, 所以通常情况下此事件触发的白板页信息不是当前正在显示的页面。

  • 由于页号WhiteBoardPage.pageNumber的变化是新增和删除页导致,可能同时影响大量的页信息,所以页号变化没有单独的事件,只能监听onBoardPageList观察整个列表的变化。
参数 描述
page 有参数变化的新的页信息,当前仅有缩略图地址变化WhiteBoardPage.thumbnails

onBoardSizeChanged

void onBoardSizeChanged(@NonNull WhiteBoardViewport viewport)

白板大小变化(虚拟大小)

在白板设定的虚拟大小变化时触发,首次进入白板一定会触发一次。

参数 描述
viewport 白板的可视区数据

onBoardScroll

void onBoardScroll(@NonNull WhiteBoardViewport viewport)

白板滚动

白板内发生滚动时触发,主动调用scroll也会触发,首次进入白板也会触发。

参数 描述
viewport 白板的可视区数据

onBackgroundColorChanged

void onBackgroundColorChanged(@ColorInt int backgroundColor)

白板背景色改变

当前的白板背景色变化时触发,首次进入白板也会触发。 可通过setBackgroundColor随时改变背景色。

参数 描述
backgroundColor 新的颜色值

onWidgetActive

void onWidgetActive(@Nullable ActiveWidgetInfo info)

有新的widget被激活

用户书写或操作白板时会激活被操作的widget,同时触发此事件,比如移动文件时会收到被移动的文件信息,在白板上写字时会收到白板的信息。 当此widget是文件且此文件发生翻页后会再次触发此事件,同时也会触发onFilePageChanged

参数 描述
info 当前激活的widget信息,null表示用户还没有操作,比如刚刚翻页后

onPageCleaned

void onPageCleaned(@NonNull String pageId)

清空白板完成回调

使用cleanBoardPage后回调。

参数 描述
pageId 被清空的页面ID

onPageCleaned

void onPageCleaned(@NonNull String pageId)

清空白板完成回调

使用cleanBoardPage后回调。

参数 描述
pageId 被清空的页面ID

onFileScrolled

void onFileScrolled(@NonNull WidgetScrollInfo info)

文件滑动到上下顶部边缘监听

参数 描述
info 滑动信息

onWidgetActionEvent

void onWidgetActionEvent(@NonNull WidgetActionEvent event)

widget被执行了某些关键动作

比如有人插入文件或删除文件会收到此事件。 同时每个远端用户的文件加载情况也会触发此事件,通过此事件可以观察到每个人文件加载成功或失败情况。

  • 当前仅文件和图片widget会触发此事件。
参数 描述
event widget事件信息

onRecoveryStateChanged

void onRecoveryStateChanged(boolean isEmpty)

笔迹回收站空与非空的状态变化

当在擦除模式InputConfig.erase擦除笔迹时被擦除的笔迹会移动到回收站导致回收站不为空,会触发此事件。 当反复调用还原笔迹recover导致回收站为空时会触发此事件。 当从擦除模式切换到其他模式或白板翻页后会自动清空回收站,同样有可能触发此事件。

参数 描述
isEmpty true表示回收站为空,false表示不为空,此时可以通过recover来还原一次擦除操作

ScreenshotsCallback

截图完成回调

screenshots中使用。

ScreenshotsCallback.done

void done(@Nullable Bitmap bitmap)

截图完成

参数 描述
bitmap 截图得到的位图,如果为null表示截图失败,位图大小等于QNWhiteBoardView的像素大小

QNWhiteBoardView

白板的显示控件,用于显示白板内容,当前仅支持同时显示一个白板,如果同时放置了多个白板控件,仅最后一个控件会刷新内容。 布局时此控件的大小最好设定为与白板的虚拟大小WhiteBoardSize的宽高比保持一致,否则多余的边缘会留白。

JoinConfig

加入房间时的参数配置

构造函数

  • public JoinConfig( @NonNull String token)
参数 类型 可空 描述

|token|String|否|每次加入房间时生成的标识符,与appId,roomId,userId关联,通常由服务器生成| |roleId|int|否|角色id,默认为0,通常用来标识此用户身份,方便定制用户权限系统| |sessionId|String|是|用户会话id,用于唯一标识用户,如果用户业务系统中有与userId对应的临时用户标识符,比如session或token等,此临时id可以在此传递,如果userId相同但是sessionId不同的两个用户加入了白板,可以视为相同用户的多设备加入白板实现,如果留空则白板会自动生成一个| |nickname|String|是|用户名或昵称,在白板中使用的用户名称| |avatar|String|是|用户头像地址,在白板中显示的用户头像| |widthHeightThan|double|是|白板宽高比 范围[0.5,2.2] 默认0.5| |limitNumber|int|是|人数限制,0代表不限制:如果 >0,代表白板内最多limitNumber个人,只要白板内人数超过limitNumber数量时,就会进不去,默认0| |boardSizeId|int|是|创建的白板(meeting)的大小。有三个可选值:1,2,3 1代表白板是2x2, 2代表白板是3x3, 3代表白板是1x3 默认3| |bgColor|int|是| 表示白板(meeting)的颜色。也有三个值可选: 1,2,3 1 代表白色,2 代表黑色,3 代表绿色。 默认1| |zoomScale|int|是| zoomScale 扩展比 1~5之间 非必填 默认1| |title|String|是| 白板标题(长度 1 ~ 20 支持数字、字符、下划线_),相同的RTC房间,如果title相同,则进相同的房间,一个RTC房间可以有多个白板房间,标题不同就会生成新的, 该字段非必填|

InputConfig

输入模式配置 此类仅提供静态工厂方法。

InputConfig.pen

public static InputConfig pen(@ColorInt int color , float thickness)

创建一个笔书写输入模式配置

参数 描述
color 笔颜色,支持透明度,适当的透明度可以看作是马克笔实现
thickness 笔粗细,必须大于0

InputConfig.laserPen

public static InputConfig laserPen(@NonNull LaserType laserType)

创建一个激光笔输入模式配置

激光笔是一种瞬时的位置指示型输入模式,指示手指位置的内容。

参数 描述
laserType 激光笔类型

InputConfig.erase

public static InputConfig erase(float size)

创建一个橡皮(擦除)输入模式配置

参数 描述
size 橡皮面积

InputConfig.geometry

public static InputConfig geometry(@NonNull GeometryType geometryType , @ColorInt int color , float thickness)

创建一个几何图形输入模式配置

参数 描述
geometryType 图形类型
color 图形边框的颜色
thickness 图形边框粗细

InputConfig.select

public static InputConfig select()

创建一个选择输入模式配置

此模式可以在白板中框选内容。

FileConfig

向白板插入文件时描述文件信息的配置

构造函数

  • public FileConfig(@NonNull File file)
  • public FileConfig(@NonNull File file , @Nullable String name)
  • public FileConfig(@NonNull File file , @Nullable String name , float left , float top)
  • public FileConfig(@NonNull File file , @Nullable String name , float left , float top , int boxWidth , int boxHeight)
参数 类型 可空 描述
file File 要插入的文件,此文件必须有支持的类型后缀,否则会被系统忽略,支持的类型参考insertFile
name String 指定文件的实际名称,留空会使用file的名称,此名称不会影响系统对file类型的校验,仅做标识用途,比如file本身是随机串文件名,此处可以赋予它有意义的文件名,此名称会在ActiveWidgetInfo中拿到
left float 插入文件时的初始位置的左上角横坐标,默认为0
top float 插入文件时的初始位置的左上角纵坐标,默认为0
boxWidth int 文件外框的宽度,0表示使用文件自身的宽度
boxHeight int 文件外框的高度,0表示使用文件自身的高度

ActiveWidgetInfo

被激活的widget信息

白板中的一切都是widget,包括白板,文件,图片,选择框等等,具体参考WidgetType。 当用户操作了一个widget或者在它上面书写时,这个widget会被激活,会触发onWidgetActive事件。

参数 类型 可空 描述
id String widgetId,此widget的唯一标识符,后续对widget的操作都会用到此id,比如jumpFilePagedeleteFile
type WidgetType 指示了此widget的类型
userId String 此widget创建者的userId,通常白板页是没有创建者的,由服务器创建
name String widget名称,如果此widget是文件或图片时
resourceId String 资源id,sdk内部用于标识实际文件的索引,用户通常无需关心
path String 文件路径,如果widget是文件或图片,此为它的本地路径(如果插入的原文件是office文件,则此路径是它转换后的pdf路径,并非原始文件)
currentPageNumber int 如果widget是文件时,此为当前文件的页码,从1开始
pageCount int 如果widget是文件时,此为文件的总页数(如果原文件是office文件,则此页数是转换成pdf后的实际页数)

Room

房间信息

加入白板房间成功后会收到此数据。

参数 类型 可空 描述
roomId String 房间的id,与joinRoom时的roomId一致
fileGroupId String 白板中的文件在服务器存储的文件组id,用户无需关心
chatRoomId int 房间中的聊天室id,暂不支持

RoomMember

房间中的成员信息

参数 类型 可空 描述
userId String 用户业务系统中的稳定用户id
sessionId String 用户会话id,用于唯一标识用户,如果成员在joinRoom时未传递此参数,则此参数会由白板自动生成
roleId int 角色id,默认为0,通常用来标识此用户身份,方便定制用户权限系统
nickname String 用户名或昵称
avatar String 用户头像地址

WhiteBoardPage

白板页信息

参数 类型 可空 描述
pageId String 白板页id,每个页面的唯一标识符,后续对白板页的操作会用到,比如jumpBoardPagedeleteBoardPage
pageNumber int 页面序号,从1开始,标识了此页是白板中的第几页
thumbnails String 白板页缩略图url,没有时为空字符串

WhiteBoardSize

白板尺寸信息

此信息的数值基于白板内部的虚拟大小和坐标系,并非实际渲染窗口的纹理大小(实际的纹理大小由WhiteBoardView的像素大小决定)。 以下参数由服务器创建白板房间时指定,通常在一个房间中此信息是固定不变的。

参数 类型 描述
maxWidth int 白板最大宽度
maxHeight int 白板最大高度
displayWidth int 白板显示宽度(可视区的宽度,当前仅支持与maxWidth保持一致,即只能垂直延展)
displayHeight int 白板显示高度(可视区的高度,当此参数小于maxHeight时白板可上下滚动)

WhiteBoardSize.ZERO

public static final WhiteBoardSize ZERO = new WhiteBoardSize(0 , 0 , 0 , 0);

一个空尺寸,在未加入白板时获取到的值。

WhiteBoardViewport

白板当前可视区信息

所有数值基于白板内部的虚拟大小和坐标系,并非实际渲染窗口的纹理大小。 当白板页滚动时会刷新此数据。

参数 类型 描述
size WhiteBoardSize 白板尺寸
offsetX float 当前白板水平偏移(当前仅支持垂直滚动,所以此值总是0)
offsetY float 当前白板垂直偏移

WhiteBoardViewport.IDLE

public static final WhiteBoardViewport IDLE = new WhiteBoardViewport(WhiteBoardSize.ZERO , 0 , 0);

一个空闲值,在未加入白板时获取到的值。

WidgetActionEvent

widget动作事件

描述了对文件或图片的关键操作信息,包括加载情况,由谁插入或删除等。 由onWidgetActionEvent提供。

参数 类型 可空 描述
sessionId String 动作发出者的sessionId
type WidgetType widget类型
action WidgetAction 动作类型
name String widget名称

BoardStatus

白板房间状态枚举

BoardStatus.IDLE

空闲状态,表示没有进入白板

BoardStatus.LOADING

正在进入白板,即调用joinRoom之后到成功或失败之前的状态。

BoardStatus.SUCCESSFUL

加入白板成功

BoardStatus.FAILED

加入白板失败

BoardStatus.RECONNECTING

白板正在重连

GeometryType

几何图形类型

InputConfig.geometry中指定要绘制的几何图形。

名称 图形
RECTANGLE 矩形
CIRCLE 圆形
LINE 直线
ARROW 箭头

LaserType

激光笔类型

InputConfig.laserPen中指定激光指示点的样式。

名称 样式
LASER_DOT 圆点
LASER_HAND 手形图标
LASER_ARROWS_WHITE 白色箭头
LASER_ARROWS_BLACK 黑色箭头

WidgetType

widget类型,白板中的一切都是widget

名称 类型
BOARD 白板
FILE 文件,包括pdf和office
IMAGE 图片,jpg和png
GEOMETRY 几何图形,由InputConfig.geometry模式绘制
SELECTION 选择框,由InputConfig.select模式选中的内容

WidgetType

widget类型,白板中的一切都是widget

名称 类型
BOARD 白板
FILE 文件,包括pdf和office
IMAGE 图片,jpg和png
GEOMETRY 几何图形,由InputConfig.geometry模式绘制
SELECTION 选择框,由InputConfig.select模式选中的内容

WidgetScrollInfo

文件滑动信息

onFileScrolled中回调。

参数 类型 描述
widgetId String 文件widgetId
scrollToTop int 1代表到顶
scrollToBottom int 1代表到底

混淆配置

-keep class com.qiniu.droid.whiteboard.** {*;}

WhiteBoardErrorCode

错误码

名称 错误含义
NETWORK_ERROR 100 网络不可用
SERVER_ERROR 101 服务器错误或繁忙
APP_ID_NOT_EXIST 200 appId不存在
ROOM_ID_NOT_EXIST 201 roomId不存在
USER_ID_EMPTY 202 userId为空
TOKEN_ERROR 203 token错误
CONNECT_ROOM_FAILED 300 连接房间失败
PAGE_INFO_TIMEOUT 301 等待页数据下发超时
ROOM_DISCONNECT 302 房间连接中断,可能是网络波动,也可能是房间中传输了错误数据导致被服务器切断
INVALID_ARGS 303 加入房间参数错误