客户端实现
更新时间: 2024/08/02 11:38:27
本文档为您展示智慧云课堂在直播大班课场景下的常见功能,您可以参考智慧云课堂方案实现直播大班课场景,也可以在此基础上实现业务功能的灵活扩展。
技术架构
如果示例项目中默认实现的 UI 不符合您的预期,您可以按需实现自己的用户界面,即只使用我们封装好的组件所提供的音视频能力,自行实现 UI 部分。
教育组件的架构如下图所示。
- EduUI:教育组件的UI配置,包括一对一教学、多人小班课、互动大班课、直播大班课等场景的 ViewController、View 以及 model 部分。
- EduLogic:基于云信 NERTC SDK、IM SDK 以及白板 SDK 定制的,针对教育场景的逻辑实现,包括如下3个服务:
- NEEduRtcService 是音视频服务,提供可供 App 调用的音视频相关方法。
- NEEduIMService 是 IM 服务,提供可供 App 调用的即时通信、聊天室相关方法。
- NEEduBoardService 是互动白板服务,提供可供 App 调用的互动白板相关方法。
业务流程
智慧云课堂的启动流程如下图所示。
当 App 客户端请求加入云课堂时:
- App 客户端向 App 服务端申请 查询房间信息。如果房间不存在,那么加入失败;如果房间已存在,那么加入房间。
- 加入课堂,先检测 IM 是否已经登录。未登录则需要登录,登录失败返回加入失败。向服务端发送加入课堂接口,成功后进入课程页面。
- 请求快照,获取聊天室 ID,加入聊天室。
- 开始初始化。更新本地流,开始拉流。
客户端实现方法
步骤一 集成到项目
-
新建 Android 工程。
- 运行 Android Sudio,在顶部菜单依次选择 File -> New -> New Project... 新建工程。
- 选择 Phone and Tablet -> Empty Activity ,并单击 Next。
- 配置工程相关信息。
Minimum API Level 为 API 21。
- 单击 Finish,完成工程创建。
-
添加依赖模块。
-
复制示例项目中的
Modules
和config.gradle
、config.properties
等相关配置文件至当前目录。 -
settings.gradle
引入Modules
。implementation project(':edu-ui') implementation project(':recordplay-ui') implementation project(':viewbinding')
-
修改工程目录下的
app/build.gradle
文件,添加智慧云课堂 SDK 相关的依赖。allprojects { repositories { google() jcenter() maven{ url 'https://oss.sonatype.org/content/repositories/snapshots/' } } } // 若出现 More than one file was found with OS independent path 'lib/arm64-v8a/libc++_shared.so'. // 可以在主 module 的 build.gradle 文件中 android 闭包内追加如下 packageOptions 配置 android{ //...... packagingOptions { pickFirst 'lib/arm64-v8a/libc++_shared.so' pickFirst 'lib/armeabi-v7a/libc++_shared.so' } } dependencies { //...... // 添加EduUI依赖 implementation project(':edu-ui') }
-
在顶部菜单单击 Build -> Make Project 构建工程,下载依赖。
下载完成后即可在代码中引入云课堂组件中的类和方法。
-
-
权限配置。
智慧云课堂 SDK 正常工作需要应用获取以下权限:
<!-- 网络相关 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 多媒体 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.Manifest.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
以上权限已经在SDK内部进行声明,开发者无需在
AndroidManifest.xml
文件中重新声明这些权限,但需要自己编码实现运行时的权限申请。运行时的权限可在应用首页中统一申请,详细信息请参考 Android 官方开发文档。
步骤二 初始化组件
-
进行全局配置。
首先创建
NEEduOptions
实例对 SDK 进行全局配置,然后调用config
方法传入该实例。NEEduOptions 包含以下参数:
| 配置项 | 说明 | |---|---| | APP_KEY | 应用的 AppKey。可以在网易云信控制台中查看。 | | BASE_URL | 应用服务器地址。私有化配置时需替换为私有化部署地址 | | AUTHORIZATION | 调用服务端接口时,请求头中的校验参数。 | | reuseIM | 配置是否复用底层NIM-SDK的长连接通道,默认关闭。仅当应用中同时还需独立接入和使用NIM-SDK,才需要开启该配置,其他情况下请忽略该配置。 |
NEEduUiKit.config( this, NEEduOptions( BuildConfig.APP_KEY, BuildConfig.AUTHORIZATION, BuildConfig.API_BASE_URL, reuseIM ) )
-
初始化
配置完成后,创建 NEEduUiKit 实例,调用 init 方法进行初始化。包含以下参数:
| 配置项 | 说明 | |---|---| | uuid | 用户鉴权userUuid。匿名登录时请设置为空字符串"" | | token | 用户鉴权userToken。匿名登录时请设置为空字符串"" |
示例代码:
NEEduUiKit.init(uuid, token).observeOnce(viewLifecycleOwner, initObserver)
步骤三 学生加入课堂
学生加入课堂时,会使用 NEEduClassOptions
的实例创建课堂并且加入,如果对应课堂号的课堂已经存在就直接加入。NEEduClassOptions
包含以下参数:
配置项 | 说明 |
---|---|
classId | 课程号,课堂唯一标识 |
className | 课程名称 |
nickName | 用户在课堂中的昵称 |
sceneType | 课堂类型,有4种类型: 一对一教学、多人小班课、互动大班课、直播大班课 |
roleType | 角色类型:host:教育场景中映射为老师,broadcaster: 教育场景中映射为学生 |
示例代码:
eduManager.enterClass(neEduClassOptions).map {
if (it.success()) {
when {
NEEduUiKit.instance?.neEduManager == null -> {
NEEduUiKit.destroy()
ALog.w("eduManager not initialized!")
}
neEduClassOptions.roleType == NEEduRoleType.HOST -> {
when (neEduClassOptions.sceneType) {
NEEduSceneType.ONE_TO_ONE -> {
OneToOneTeacherActivity.start(context)
}
NEEduSceneType.SMALL -> {
SmallClazzTeacherActivity.start(context)
}
NEEduSceneType.BIG -> {
BigClazzTeacherActivity.start(context)
}
}
}
else -> {
when (neEduClassOptions.sceneType) {
NEEduSceneType.ONE_TO_ONE -> {
OneToOneStudentActivity.start(context)
}
NEEduSceneType.SMALL -> {
SmallClazzStudentActivity.start(context)
}
NEEduSceneType.BIG -> {
BigClazzStudentActivity.start(context)
}
// 学生进入直播大班课
NEEduSceneType.LIVE_SIMPLE -> {
LiveClassActivity.start(context)
}
}
}
}
}
it
}
步骤四 在线聊天室
在多人小班课、互动大班课、直播大班课中,可以通过聊天室实现消息收发,学生和学生、学生和老师之间通过聊天室发送文字或图片消息,教师端可以禁言或解禁聊天室。
师生调用 enterChatRoom
加入聊天室,并通过 sendMessage
发送文字和图片消息。
示例代码:
// 发起加入聊天室
// 首先创建EnterChatRoomData实例
val data = EnterChatRoomData(activity.eduRoom?.chatRoomId())
// 接着使用EnterChatRoomData实例进入聊天室
imService.enterChatRoom(data).observe(this, { it ->
// 最后处理结果回调
if (it.success()) roomInfo = it.data!!.roomInfo
it
}
// 发送文本消息
// 首先创建文本消息
val chatMessage = ChatRoomMessageBuilder.createChatRoomTextMessage(it.roomId, text)
// 接着发送消息
imService.sendMessage(chatMessage)
// 发送图片消息
// 首先创建图片消息
val chatMessage =
ChatRoomMessageBuilder.createChatRoomImageMessage(it.roomId, file, file?.name)
// 接着发送消息
imService.sendMessage(chatMessage)
步骤五 录制回放
在线教育场景中,可实现上课过程中老师和学生的音视频、白板、屏幕共享录制,还原真实上课场景,供学生和教师回放复习。目前所有课堂模式都支持录制回放。录制功能包含在云端录制服务中,用户端只需要接入Recordplay
回放组件,回放功能依赖的代码包含在组件里面。
教师开始上课时,服务器会自动开始录制。课程结束时,需要等待服务端 20 分钟左右进行转码。转码完成后,用户可以通过 Recordplay 回放组件观看录制内容。在示例项目中,展示了如何快速接入 Recordplay 组件。接入步骤如下:
-
Recordplay
回放组件包含recordplay-logic
、recordplay-model
、recordplay-ui
3 个依赖模块。复制示例项目中的recordplay-logic
、recordplay-model
、recordplay-ui
这 3 个模块至当前项目目录。 -
添加模块依赖。
示例代码:
implementation project(':recordplay-ui')
-
课程结束后,回放观看端调用
fetchRecord
获取上一次的回放记录,并创建回放播放器实例。示例代码:
RecordPlayRepository.appKey = BuildConfig.APP_KEY RecordPlayRepository.baseUrl = BuildConfig.API_BASE_URL // 根据roomUuid和rtcCid查询回放记录,并创建回放播放器实例 NERecordPlayUiKit.fetchRecord(roomUuid, rtcCid) .observeOnce(viewLifecycleOwner, initRecordObserver) // 回放记录查询结果回调 private val initRecordObserver = { t: NEResult<NERecordPlayer> -> when { t.success() -> { // 调用成功后进入回放观看界面 enterRecordPlay() } // 音视频未完成转码,需要等待服务端20分钟左右进行转码 t.code == NEEduHttpCode.NO_CONTENT.code -> { ALog.i("init record failed, result $t") ToastUtil.showLong(getString(R.string.course_playback_file_is_being_transcoded)) } else -> { // 获取回放记录失败 ALog.i("init record failed, result $t") val tip = context?.let { NEEduErrorCode.tipsWithErrorCode(it, t.code) } if (!TextUtils.isEmpty(tip)) { ToastUtil.showLong(tip!!) } else { ToastUtil.showLong(getString(R.string.open_recordplay_fail_try_again)) } } } }
-
如果成功,那么跳转到
Recordplay
模块中的NERecordActivity
回放界面。示例代码:
NERecordActivity.start(requireActivity()) <!-- 回放播放界面 --> <activity android:name=".NERecordActivity" android:configChanges="keyboardHidden|screenSize|orientation" android:launchMode="singleTop" android:screenOrientation="sensorLandscape" android:theme="@style/Theme.EduApp.Landscape" />
-
初始化播放器。
示例代码:
var recordPlayer = NERecordPlayer.instance recordPlayer.init(application, this)
-
开始播放。
示例代码:
// 判断播放状态 when (recordPlayer.getState()) { // 处于播放就绪状态,开始播放 NERecordPlayState.PREPARED, NERecordPlayState.PAUSED -> recordPlayer.start() ... }
-
暂停播放。
示例代码:
// 判断播放状态 when (recordPlayer.getState()) { // 处于播放暂停状态,暂停播放 NERecordPlayState.PLAYING -> recordPlayer.pause() ... }
-
拖动进度。
示例代码:
// 根据progress改变播放进度,progress介于 0 ~ 100 之间 recordPlayer.seek(recordPlayer.getDuration() * progress / 100)
步骤六 结束课堂
调用 NEEduUiKit.destroy()
结束课程。
示例代码:
releasePlayer() // 释放视频播放器相关资源
NEEduUiKit.destroy() // 结束课程