实现语聊房
本文介绍如何集成语聊 UIKit 来实现语聊房间的创建和销毁、用户进房和退房等功能。
示例项目
声网提供 API-Examples-AUIKit/Android/VoiceRoomApp 示例项目供你参考本文提到的集成步骤和代码逻辑。
准备开发环境
前提条件
- Android Studio 3.5 及以上。本文以 Android Studio Giraffe | 2022.3.1 和 JBR 17.0.6 为例。
- Android 手机,版本 Android 5.0(API Level 21)及以上。
- 可以访问互联网的计算机。确保你的网络环境没有部署防火墙,否则无法正常使用声网服务。
- 开通服务。
创建项目
如需创建新项目,在 Android Studio 里,依次选择 Phone and Tablet > Empty Activity,创建 Android 项目。
创建项目后,Android Studio 会自动开始同步 gradle,稍等片刻至同步成功后再进行下一步操作。
集成依赖
本节介绍如何集成语聊项目所需的依赖库:
-
下载声网提供的 AUIVoiceRoom/Android/asceneskit 文件夹,并将该文件夹复制到与你的
app
文件夹所在的同一级目录下。 -
在
<your_app>/setting.gradle.kts
文件中添加如下行:KotlindependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// 添加 jitpack 仓库,拉取 auikit 库
maven { url = java.net.URI.create("https://www.jitpack.io") }
}
}
// 项目名需为你的 Android Studio 项目的真实名称
rootProject.name = "VoiceRoomApp"
include(":app")
// 添加 asceneskit 库到项目里
include(":asceneskit") -
在
<your_app>/app/build.gradle.kts
文件中添加如下行:Kotlindependencies {
...
// 添加 asceneskit 依赖
implementation(project(":asceneskit"))
} -
点击 Sync Now 按钮,等待 gradle 同步完成。
配置权限
在 <your_app>/app/Manifests/AndroidManifest.xml
文件中添加如下行,以完成如下设置:
- 设置允许 App 访问网络、录音等权限。
- (可选)如果你的后端服务 Host URL 不是 https 开头,设置允许 App 使用非加密的网络通信。
- 声明
MainActivity
活动,即 App 的主要活动。 - 声明
RoomActivity
活动,即 App 中语聊房房间的详情界面活动。同时,指定语聊房的窗口保持原始大小和布局,不受到软键盘的影响。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 允许 App 访问互联网 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 允许 App 录音 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 允许 App 修改音频设置 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- 允许 App 访问网络状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 允许 App 访问 Wi-Fi 状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许 App 拨打电话 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- 允许 App 使用非加密的网络通信-->
<!-- 仅在你的后端服务 host url 不是 https 开头时需要设置该权限 -->
<application
android:usesCleartextTraffic="true">
<!-- 声明 MainActivity 活动 -->
<activity
android:name=".MainActivity">
</activity>
<!-- 声明 RoomActivity 活动 -->
<activity
android:name=".RoomActivity"
android:windowSoftInputMode="adjustNothing" />
</application>
</manifest>
配置主题
在 <your_app>/app/src/main/res/values/themes.xml
文件中添加如下行配置语聊房 UI 主题:
<resources>
<!-- 将 VoiceRoomApp 改成你实际的项目名 -->
<style name="Theme.VoiceRoomApp" parent="Theme.VoiceRoom" />
</resources>
(可选)防止代码混淆
在 <your_app>/app/proguard-rules.pro
文件中添加如下行,以防止声网 SDK 的代码被混淆:
-keep class io.agora.**{*;}
-dontwarn javax.**
-dontwarn com.google.devtools.build.android.**
实现语聊房
AUIVoiceRoomUikit
基于声网 RTC、RTM 引擎、AUIKit 等模块封装,帮助你轻松管理语聊房。
你可以使用 AUIVoiceRoomUikit
类中的 API 实现语聊房间的创建和销毁、用户进房和退房等功能。
1. 初始化 AUIVoiceRoomUiKit
在 MainActivity.kt
文件中添加 onCreate
函数。在该函数中调用 AUIVoiceRoomUikit
类的 init
方法并传入 AUICommonConfig
参数,以初始化 AUIVoiceRoomUiKit
。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 初始化 AUIVoiceRoomUikit
AUIVoiceRoomUikit.init(AUICommonConfig().apply {
// 设置应用程序的上下文
context = applicationContext
// 设置 host url
host = "https://service.agora.io/uikit-voiceroom"
// 生成一个随机的用户 ID
userId = (Random().nextInt(1000) + 10000).toString()
// 设置用户名
userName = "User-$userId"
// 设置用户头像
userAvatar = "https://accktvpic.oss-cn-beijing.aliyuncs.com/pic/sample_avatar/sample_avatar_1.png"
})
}
}
2. 房主创建房间
本节展示如何让房主创建语聊房。
2.1 添加按钮:创建房间
Android Studio Giraffe 默认使用 Jeckpack Compose 构建 UI,但是依然兼容 XML 布局。本文以 XML 布局来做演示。
参考如下步骤添加创建房间按钮:
-
新建
<your_app>/app/src/main/res/layout/activity_main.xml
文件并在该文件中添加如下行,以增加一个创建房间按钮,用于让房主点击创建:XML<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<Button
android:id="@+id/btnCreateRoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:text="创建房间"/>
</LinearLayout> -
在
MainActivity.kt
文件中,添加如下高亮的几行,设置当前 Activity 使用 XML 布局,并为创建房间按钮设置点击事件的监听器。Kotlinclass MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 设置使用 XML 布局
setContentView(R.layout.main_activity)
// 初始化 AUIVoiceRoomUikit
AUIVoiceRoomUikit.init(AUICommonConfig().apply {
// 设置应用程序的上下文
context = applicationContext
// 设置 host url
host = "https://service.agora.io/uikit-voiceroom"
// 生成一个随机的用户 ID
userId = (Random().nextInt(1000) + 10000).toString()
// 设置用户名
userName = "User-$userId"
// 设置用户头像
userAvatar = "https://accktvpic.oss-cn-beijing.aliyuncs.com/pic/sample_avatar/sample_avatar_1.png"
})
// 添加点击创建房间按钮的事件
findViewById<Button>(R.id.btnCreateRoom).setOnClickListener {
}
}
}
2.2 创建语聊房
在 setOnClickListener
函数中添加如下高亮行,调用 AUIVoiceRoomUikit
类的 createRoom
方法并传入 createRoomInfo
参数,以创建语聊房。createRoomInfo
里需要传入房间信息。
如果创建房间成功,那么启动 RoomActivity
活动。在后续步骤中会创建 RoomActivity
并添加代码逻辑,用 RoomActivity
来显示房间详情界面。
// 添加点击创建房间按钮的事件
findViewById<Button>(R.id.btnCreateRoom).setOnClickListener {
// 随机生成房间名
val roomName = "Room-${Random().nextInt(100) + 1000}"
// 创建房间
val createRoomInfo = AUICreateRoomInfo()
createRoomInfo.roomName = roomName
AUIVoiceRoomUikit.createRoom(
createRoomInfo,
success = { roomInfo ->
// 跳转到房间详情页
RoomActivity.launch(this@MainActivity, roomInfo)
},
failure = {
// 创建房间失败
Toast.makeText(this@MainActivity, "Create Room failed. reason: ${it.code} - ${it.message}", Toast.LENGTH_SHORT).show()
}
)
}
3. 房主加入房间
本节展示如何让房主加入语聊房。
3.1 创建房间详情页
参考如下步骤创建房间详情页:
-
新建
<your_app>/app/src/main/res/layout/room_main.xml
文件并在该文件中添加如下行,以添加语聊房的详情页面。XML<?xml version="1.0" encoding="utf-8"?>
<io.agora.asceneskit.voice.AUIVoiceRoomView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/roomView"
android:layout_width="match_parent"
android:layout_height="match_parent" /> -
在
MainActivity.kt
文件所位于的目录下,新建RoomActivity.kt
文件,并在该文件中添加如下行,从而实现一个房间详情页的活动类RoomActivity
。RoomActivity
通过接收传递的房间信息,在onCreate
方法中显示房间的详细信息。通过使用静态方法launch
,可以方便地启动RoomActivity
并传递房间信息。Kotlinclass RoomActivity : FragmentActivity() {
companion object {
const val EXTRA_ROOM_INFO = "RoomInfo"
// 启动 RoomActivity
fun launch(context: Context, roomInfo: AUIRoomInfo){
// 创建一个 Intent 对象,指定启动 RoomActivity 的目标上下文和 RoomActivity 类名
val intent = Intent(context, RoomActivity::class.java)
// 将房间信息作为额外的数据添加到 Intent 中,使用 EXTRA_ROOM_INFO 作为键名
intent.putExtra(EXTRA_ROOM_INFO, roomInfo)
// 使用目标上下文启动 RoomActivity
context.startActivity(intent)
}
}
// 房间信息
private val roomInfo by lazy {
// 从 Intent 中获取传递的房间信息
intent.getSerializableExtra(EXTRA_ROOM_INFO) as AUIRoomInfo
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 设置使用 XML 布局
setContentView(R.layout.room_activity)
// 初始化房间详情页布局
val roomView = findViewById<AUIVoiceRoomView>(R.id.roomView)
roomView.setFragmentActivity(this@RoomActivity)
}
}
3.2 启动房间
在 RoomActivity
的 onCreate
函数中增加如下高亮的几行。调用 AUIVoiceRoomUikit
类的 launchRoom
方法并传入以下参数,以启动语聊房:
roomInfo
:房间信息。包含如下:roomId
:房间 ID。owner
:房主信息。memberCount
:房间内的人数。createTime
:房间创建的时间(毫秒)。
roomView
:房间的 UI View。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 设置使用 XML 布局
setContentView(R.layout.room_activity)
// 初始化房间详情页布局
val roomView = findViewById<AUIVoiceRoomView>(R.id.roomView)
roomView.setFragmentActivity(this@RoomActivity)
// 检查并申请运行时权限
PermissionHelp(this).checkMicPerm(
// 获取到权限
granted = {
// 启动房间
AUIVoiceRoomUikit.launchRoom(roomInfo, roomView)
},
unGranted = {
// 没有获取到权限
finish()
}
)
}
4. (可选)听众加入房间
本节展示如何让听众加入已存在的房间。
4.1 添加按钮:加入房间
参考如下步骤添加加入房间按钮:
-
在
main_activity.xml
中添加如下高亮的几行,添加一个加入房间的按钮,以用于让听众点击加入房间。XML<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<Button
android:id="@+id/btnCreateRoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:text="创建房间"/>
<Button
android:id="@+id/btnJoinRoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:text="加入房间"/>
</LinearLayout> -
在
MainActivity
类中findViewById<Button>(R.id.btnCreateRoom).setOnClickListener{}
函数后添加如下几行,为加入房间按钮设置点击事件的监听器。Kotlin// 添加点击加入房间按钮的事件
findViewById<Button>(R.id.btnJoinRoom).setOnClickListener {
// 弹出房间名输入弹窗
val input = EditText(this@MainActivity)
input.hint = "Room Name"
AlertDialog.Builder(this@MainActivity)
.setTitle("Launch Room")
.setView(input)
.setPositiveButton("Confirm"){ dialog: DialogInterface, i: Int ->
}
.setNegativeButton("Cancel"){ dialog: DialogInterface, i: Int ->
dialog.dismiss()
}
.show()
}
4.2 获取房间列表
添加如下高亮的几行,调用 AUIVoiceRoomUikit
类的 getRoomList
方法并传入如下参数,以获取语聊房间列表:
lastCreateTime
:房间列表的起始时间(毫秒)。例如,1681879844085。pageSize
:每一页房间列表所展示的房间数量。
如果在房间列表中找到匹配的房间名,那么执行 launch
函数启动 RoomActivity
,让听众进入到房间详情页。
// 添加点击加入房间按钮的事件
findViewById<Button>(R.id.btnJoinRoom).setOnClickListener {
// 弹出房间名输入弹窗
val input = EditText(this@MainActivity)
input.hint = "Room Name"
AlertDialog.Builder(this@MainActivity)
.setTitle("Create Room")
.setView(input)
.setPositiveButton("Confirm"){ dialog: DialogInterface, i: Int ->
// 确认加入房间
val roomName = input.text.toString()
if(TextUtils.isEmpty(roomName)){
Toast.makeText(this@MainActivity, "Room name is empty", Toast.LENGTH_SHORT).show()
dialog.dismiss()
return@setPositiveButton
}
// 查询房间信息
AUIVoiceRoomUikit.getRoomList(0, 50,
success = { list ->
val roomInfo = list.findLast { it.roomName == roomName }
if(roomInfo == null){
Toast.makeText(this@MainActivity, "The room is unavailable. RoomName=$roomName", Toast.LENGTH_SHORT).show()
dialog.dismiss()
return@getRoomList
}
// 跳转到房间详情页
RoomActivity.launch(this@MainActivity, roomInfo)
},
failure = {
Toast.makeText(this@MainActivity, "Get room list failed. ${it.code} - ${it.message}", Toast.LENGTH_SHORT).show()
dialog.dismiss()
})
}
.setNegativeButton("Cancel"){ dialog: DialogInterface, i: Int ->
dialog.dismiss()
}
.show()
}
5. (可选)退出或销毁房间
本节展示如何退出并销毁房间。
在语聊房中,房主可以主动销毁房间,房间销毁时听众会被动退出房间。房间存在时,听众也可以主动退出房间。
5.1 主动退出或销毁房间
在 RoomActivity
中添加如下高亮的几行代码,即可实现通过点击按钮或使用 Android 系统键盘主动退出房间(听众)或销毁房间(房主)。
class RoomActivity : FragmentActivity() {
companion object {
const val EXTRA_ROOM_INFO = "RoomInfo"
fun launch(context: Context, roomInfo: AUIRoomInfo){
val intent = Intent(context, RoomActivity::class.java)
intent.putExtra(EXTRA_ROOM_INFO, roomInfo)
context.startActivity(intent)
}
}
// 房间信息
private val roomInfo by lazy {
intent.getSerializableExtra(EXTRA_ROOM_INFO) as AUIRoomInfo
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 设置使用 XML 布局
setContentView(R.layout.room_activity)
// 初始化房间详情页布局
val roomView = findViewById<AUIVoiceRoomView>(R.id.roomView)
roomView.setFragmentActivity(this@RoomActivity)
// 点击退出房间按钮时
roomView.setOnShutDownClick {
// 主动退出房间
destroyRoom()
finish()
}
// 检查并申请运行时权限
PermissionHelp(this).checkMicPerm(
// 获取到权限
granted = {
// 启动房间
AUIVoiceRoomUikit.launchRoom(roomInfo, roomView)
},
unGranted = {
// 没有获取到权限
finish()
}
)
}
// 使用 Android 系统键盘返回主页时
override fun onBackPressed() {
// 主动退出房间
destroyRoom()
super.onBackPressed()
}
}
5.2 被动退出房间
在 RoomActivity
中添加如下高亮的几行。通过 AUIVoiceRoomUikit
类的 registerRespObserver
方法注册房间事件观测器。在观测器中添加 onRoomDestroy
回调来监听房间销毁事件。当房间销毁事件发生时,执行 destroyRoom
函数。
在 destroyRoom
函数中,调用 AUIVoiceRoomUikit
类的 unRegisterRespObserver
方法取消注册房间事件观测器。这样,在房间销毁时,观测器将不再接收房间相关事件。
class RoomActivity : FragmentActivity() {
companion object {
const val EXTRA_ROOM_INFO = "RoomInfo"
fun launch(context: Context, roomInfo: AUIRoomInfo){
val intent = Intent(context, RoomActivity::class.java)
intent.putExtra(EXTRA_ROOM_INFO, roomInfo)
context.startActivity(intent)
}
}
// 房间信息
private val roomInfo by lazy {
intent.getSerializableExtra(EXTRA_ROOM_INFO) as AUIRoomInfo
}
// 房间事件观察者
private val roomManagerRespObserver = object: IAUIRoomManager.AUIRoomManagerRespObserver {
override fun onRoomDestroy(roomId: String) {
super.onRoomDestroy(roomId)
// 房间被销毁
destroyRoom()
finish()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 设置使用 XML 布局
setContentView(R.layout.room_activity)
// 初始化房间详情页布局
val roomView = findViewById<AUIVoiceRoomView>(R.id.roomView)
roomView.setFragmentActivity(this@RoomActivity)
roomView.setOnShutDownClick {
// 主动退出房间
destroyRoom()
finish()
}
// 检查并申请运行时权限
PermissionHelp(this).checkMicPerm(
// 获取到权限
granted = {
// 启动房间
AUIVoiceRoomUikit.launchRoom(roomInfo, roomView)
},
unGranted = {
// 没有获取到权限
finish()
}
)
// 注册房间事件观察者
AUIVoiceRoomUikit.registerRespObserver(roomManagerRespObserver)
}
// 系统键盘返回主动退出房间时
override fun onBackPressed() {
destroyRoom()
super.onBackPressed()
}
private fun destroyRoom() {
// 取消注册房间事件观察者
AUIVoiceRoomUikit.unRegisterRespObserver(roomManagerRespObserver)
}
}
5.3 添加销毁逻辑
在 destroyRoom
函数中,添加如下高亮的几行代码。调用 AUIVoiceRoomUikit
类的 destroyRoom
方法并传入房间 ID,以销毁房间。至此,destroyRoom
函数的代码补充完成。
private fun destroyRoom() {
// 退出或销毁房间
AUIVoiceRoomUikit.destroyRoom(roomInfo.roomId)
// 取消注册房间事件观察者
AUIVoiceRoomUikit.unRegisterRespObserver(roomManagerRespObserver)
}
注意事项
后端部署
为方便你快速集成语聊房,声网已经帮你部署好后端,无需你进行操作。
声网在示例项目中提供的后端服务 Host URL(https://service.agora.io/uikit-voiceroom
)仅用于测试体验,请你不要商用。
如需将项目商用,请参考配置示例项目部署后端并在项目中配置你的后端服务 Host URL。如果你的后端服务 Host URL 不是 https 开头,你还需要参考配置权限设置允许 App 进行非加密的网络通信。
下一步
在创建、进入房间后,你可以参考如下业务流程图开发后续的麦位管理、聊天、礼物等功能。