七牛云 QLiveKit,直播间 UI 开发轻松搞定
QLiveKit 的能力
UI 组件可分为事件处理型、UI 展示型和功能型三大类。事件处理型关注于对业务事件做出处理,在页面上可无 UI 表现,例如收到「房主离线」事件则关闭房间;UI 展示型则直接表现为页面显示的 UI;功能型负责实现特定行为功能,例如开始录制视频。
针对以上各个分类,七牛云 QLiveUIKit 平台业务,能快速插拔各个组件,并提供运行管理,可以对内置的组件配置化删除、修改、替换,并快速无侵入式地增加组件。

对 UIKit SDK 有哪些要求?
在标准的 UI 开发模式中,通常可以分为命令式和声明式。常见的命令式 UI 例如安卓 xml,常见的声明式 UI 包括 Flutter、Jetpack Compose UI、SwiftUI 等。
//命令式案例:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tvNotice"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tvLikeCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
class TestLiveActivity {
private lateinit var client: QPlayerClient
override fun onCreate(savedInstanceState: Bundle?) {
client.joinRoom("",null)
val room= client.roomInfo
tvNotice.text = room.notice
ivRoomCover.setImage(room.coverURL)
client.addLikeServiceListener {
tvLikeCount.text = it.count.toString()
}
}
}
//声明式案例:
class LiveRoomViewModel : ViewModel() {
lateinit var client: QPlayerClient
val noticeLiveData = MutableLiveData<String>()
val likeLiveData = MutableLiveData<String>()
fun join(){
client.joinRoom("",null)
val room= client.roomInfo
noticeLiveData.value = room.notice
client.getService(QLikeService::class.java).addLikeServiceListener {
likeLiveData.value = it.count.toString()
}
}
}
fun LivePage(model: LiveRoomViewModel) {
val notice by model.noticeLiveData.observeAsState("")
val like by model.likeLiveData.observeAsState("")
//列表视图
Column {
//绑定 UI 和模型
Text(text = notice)
Text(text = like)
}
}
如果作为 Demo 级 UI 产品,这样的标准开发模式是完全没问题的,但是对于 UIKit SDK 级别的产品,就有更高的要求。在 SDK 运行前,
1、需要支持对 UI 布局编排进行调整
2、要对已存在 UI 删除、修改、替换
3、在某个位置插入某个 UI
假设以标准的 UI 模式提供直播间 UI 页面,要实现以上能力基本方案如下:
方案一:
运行前提供配置参数,运行过程解析参数调整 UI。
案例:直播间底部功能栏通常有如下按钮:美颜、静音、礼物、关播、连麦、PK,可提供如下配置参数:
//按钮集合
val buttons = LinkedList<FuncButtonConfig>()
class FuncButtonConfig {
var btnID = 0
var btnName = ""
var width =100 //宽
var height=100 //高
var text="" //显示文本
var isEnable = true //是否启用
var selectIcon = -1 //选中样式
var normalIcon = -1 //正常样式
var onClickListener: OnClickListener? = null //点击事件
}
该方案的缺点:
1、实际开发过程中,UI 描述很多,开发前没法定义尽可能多的配置。
2、单个 UI 可以定义样式,对于其在父容器中的布局无法描述,也不支持把该组件切换到其他布局里。
方案二:
直接提供 UI 源码,接入用户修改源码调整 UI。
该方案的缺点:
1、页面 UI 逻辑越复杂,接入用户修改越困难 。
2、SDK 升级时,假设客户已经修改了很多 UI 源码,这时客户升级代码需要同步 SDK 修改的部分,非常困难且耗时。
QLiveUIKit 方案实例
QLiveUIKit 将页面拆分成尽可能小的 UI 组件,每个组件可在页面上下文中独立运行。对于每个组件定义如下:
interface BaseComponent<T : BaseContext>
//绑定平台上下文,拥有获取 fragmentManager,AndroidContext,currentActivity 等能力
fun attachKitContext(context: T)
// 绑定房间客户端回调
//拿到 client 就能拿到所有访问业务服务的能力 如发消息 设置监听
fun attachLiveClient(client: QLiveClient)
//activity 生命周期回调
fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event)
// 注册 UI 组件之间的通信事件
fun <T : UIEvent?> registerEventAction(clz: Class<T>, call: Function1<T, Unit>)
//发送 UI 通信事件
fun <T : UIEvent?> sendUIEvent(event: T)
// 房间加入成功回调
fun onJoined(roomInfo: QLiveRoomInfo, isResumeUIFromFloating: Boolean)
// 房间正在进入回调
fun onEntering(roomId: String, user: QLiveUser)
// 当前房间已经离开回调
fun onLeft()
// client 销毁回调
fun onDestroyed()
}

在每个 UI 组件中,基于每个阶段回调,每个组件能完成自己的全部工作,并通过事件通信机制,能和其他组件通信。接下来 SDK 把内置的 UI 组件组装出一个页面:
<FrameLayout>
<事件处理组件 1/>
<事件处理组件 2/>
<安卓内置布局组件 1
大小/对齐方式/其他样式
>
<UI 组件 1
背景图:""
宽:""
高:""
其他 UI 描述:""/>
<UI 组件 1
宽:""
高:""
其他 UI 描述:""/>
</安卓内置布局组件 1>
<安卓内置布局组件 1>
<UI 组件 1
宽:""
高:""
其他 UI 描述:""/>
<UI 组件 1
宽:""
高:""
其他 UI 描述:""/>
</安卓内置布局组件 1>
</FrameLayout>
在这个安卓布局 xml 中,首先注册了事件处理组件,其次用安卓内置的布局组件,编排了每个通过 QLiveUIKit 实现的内置 UI 组件。
开发者只需拿到一份原本的页面配置文件,便可在此基础上:
1、调节原有的组件样式
2、删除原有的组件
3、任意位置增加组件
4、修改每个组件的编排布
接下来 QLiveKit 在运行过程中,可根据 UI 配置动态装载 UI 页面。客户在整个接入过程中,只要关注需要调整的页面配置文件即可。通过这样的设计,QLiveKit 甚至可以通过手动拖拽组件,生成页面配置组装出直播页面,大幅提高开发效率。
