Android 通用视频组件开发

背景

  • 背景:目前车机的多媒体App都是各自维护自己的UI视图及基础逻辑,会有不少重复代码。并且大多数媒体App都会和本地多媒体有交互,所有媒体App都会接入到MediaCenter,没有统一的接口会导致接入适配成本和维护成本比较高。所以希望能够抽出公共基础功能到sdk中,供所有媒体App使用,从一致性和开发效率上得到提升。
  • 应用App:QQ音乐、杜比播放器、本地多媒体、迷你播放器

快速上手

为了应对不同的使用场景,接入方式有两种:

  • 打包播放器和UI一键接入
  • 单独视频UI(自行实现播放器)

可根据实际使用场景选择其一即可,如无特殊原因建议选择第一种方式。

1 添加依赖

在app的Gradle中加入以下依赖:

dart 复制代码
implementation 'com.max.media:media-video:$mediaVersion'

2 初始化播放器

ini 复制代码
PlayerInitializer.init(context, isVideo = true, enableMediaCenter = true)
  • Context:上下文对象,必填
  • isVideo:视频还是音频,必填
  • enableMediaCenter :是否接入媒体中心,默认true

3 接入视频UI组件

添加FlexPlayerView布局,用于展示视频内容及播控组件:

ini 复制代码
<com.flex.uniteplayer.ui.FlexPlayerView
    android:id="@+id/player_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

4 配置视频组件

可通过FlexPlayerView对视频组件进行设置:

接口 说明
fun setTitleBarVisible(visible: Boolean) 隐藏视频标题栏,包括标题和左侧关闭
fun enableUpDownGesture(enable: Boolean) 设置是否支持上下手势
bindControlView(listener: ControlViewListener) 绑定视频控件UI,获取组件UI控制器,可直接管理视频组件。如果需要对视频组件做更多操作可使用此接口(后文会详细说明)

5 播放视频

5.1 创建播放器

首先创建一个播放器FlexSimlePlayer:

kotlin 复制代码
class FlexSimplePlayer(context: Context?,
    isVideo: Boolean,
    enableParkDetect: Boolean = true,
    enableParkDialog: Boolean = true)

参数说明:

参数 说明
context 上下文;
enableParkDetect 只针对视频生效,是否启用行车娱乐限制,非驻车档会自动暂停视频播放;
enableParkDialog 只针对视频生效,是否弹出行车娱乐限制框,设置为disable后需要应用可以自己实现提示界面;

5.2 开始播放

php 复制代码
player.startPlay(context: Context,
        mediaData: List<MediaData>,
        view: FlexPlayerView?,
        listener: FlexMediaListener?,
        mediaCenterData: MediaCenterData? = null)

参数说明:

参数 说明
context 上下文,注意视频播放要使用activity的context,因为行车娱乐限制需要弹框
mediaData 媒体列表,每个媒体item包括url、metadata、mimetiype,其中url是媒体地址,可以是本地、在线点播或直播地址,medadata是media3的原始类型,title和artist字段会显示在mini播放器和PSD上,mimeTypes指定媒体类型,url是对应后缀的无需设置,有些比如优酷投屏中有一个直播url是/m3u8结尾 而不是.m3u8结尾 需要设置mimeTypes = MimeTypes.APPLICATION_M3U8;
view 类型为FlexPlayerView,自实现UI的此参数设置为null
listener 媒体播放监听回调,具体回调接口后面详细展开,不需要监听设置为null
mediaCenterData 媒体中心中需要用的数据,比如应用包名、图标等,具体类型后面详细展开,这里需要注意的是sourceType要设置为6,在媒体中心中对应SourceType.SOURCE_TYPE_ONLINE。

5.3 更新播放列表

kotlin 复制代码
fun updateMediaItems(mediaData: List<MediaData>)

5.4 停止播放

scss 复制代码
player.stopPlay()

到这里,视频就可以正常播放了。当然这个是最简单的播放,更多详细的可以参考:统一媒体播放器接入指南

对于已有播放器且对播放器有特定要求的App而言,可以选择单独接入视频UI,保持全局统一。

视频组件设置接口

在快速上手第4步"配置视频组件"中提到一个接口:bindControlView()

接口定义如下:

kotlin 复制代码
 /**
* 提供给APP的接口,用于APP定制视频控制UI
*/
interface ControlViewListener {
    fun onBindView(controlView: IPlayerCallback.ViewController)
}

方法onBindeView返回的是ViewController,视频组件提供的控制器,可以针对视频组件进行更细致的配置。

下面详细讲解ViewController,标红的为常用接口,希望重点关注!

1 设置全屏模式

kotlin 复制代码
 /**
* 设置2/3 屏样式
*/
fun setAppFrameWH()

/**
* 设置全屏样式
*/
fun setFullScreenWH()

全屏App必设接口

针对全屏和2/3屏有不同的UI样式(包括ICON大小、间距等等),所以在切换全屏模式的时候一定要同步设置接口,否则UI布局会异常。默认为2/3屏样式

2 自定义功能Button

为了适配更多的应用场景,我们将播放器下方最多5个Button开放两种定制方法。最左侧固定为播放按钮,不能修改,其余5个均可以自定义,如果不设置则默认不显示。

  • 对于只需要简单设置button的icon和点击事件的场景,可以直接使用方案一

  • 对于需要对Button做更多定制功能的,比如动效、动态替换、长按、双击事件等,需要使用方案二

· 方案一

如前描述,通过此方法可以轻松修改Button的Icon及点击事件

方法名非常直观,如下:

kotlin 复制代码
 /**
* 设置Left Button2样式
*  @param resId
*  @param clickListener 点击事件
*/
fun setLeftButton2(
    @DrawableRes resId: Int = 0,
    clickListener: OnClickListener? = null,
    visible: Boolean = true,
)

/**
* 设置Left Button3样式
*  @param resId
*  @param clickListener 点击事件
*/
fun setLeftButton3(
    @DrawableRes resId: Int = 0,
    clickListener: OnClickListener? = null,
    visible: Boolean = true,
)

/**
* 设置right Button1样式
*  @param resId
*  @param clickListener 点击事件
*/
fun setRightButton1(
    @DrawableRes resId: Int = 0,
    clickListener: OnClickListener? = null,
    visible: Boolean = true,
)

/**
* 设置right Button2样式
*  @param resId
*  @param clickListener 点击事件
*/
fun setRightButton2(
    @DrawableRes resId: Int = 0,
    clickListener: OnClickListener? = null,
    visible: Boolean = true,
)

/**
* 设置right Button3样式
*  @param resId
*  @param clickListener 点击事件
*/
fun setRightButton3(
    @DrawableRes resId: Int = 0,
    clickListener: OnClickListener? = null,
    visible: Boolean = true,
)

顾名思义,找到你需要自定义的Button,按照参数设置即可

· 方案二

如果你需要针对Button做更深入的定制,那么可以通过以下接口直接拿到Button实例,则可以设置你需要的任何属性。

kotlin 复制代码
 /**
* 获取Button
*  @param viewType 根据Type获取对应的Button
*/
fun getButton(viewType: ButtonType): ImageView

3 获取进度条

对于部分App需要自定义进度条,或者拿到进度条实例做一些监听及修改,可以通过以下接口实现:

kotlin 复制代码
 /**
* 获取进度条
*/
fun getProgressBar(): FlexProgressBar

4 设置关闭按钮左边距

kotlin 复制代码
 /**
* 设置关闭按钮距离
*/
fun setCloseMargin(left: Int, top: Int = CLOSE_MARGIN_TOP)

5 设置进度条左右边距

kotlin 复制代码
/**
* 设置进度条距离
*/
fun setProgressMargin(bottom: Int,
                      left: Int = BOTTOM_BAR_MARGIN_LEFT,
                      right: Int = BOTTOM_BAR_MARGIN_RIGHT)

6 设置Loading延迟显示时间

默认1000ms内的loading不进行展示,若需要不控制loading时长则可以该属性设置为0.

ViewController.loadingDelayDurationMillisecond

Q&A

1 可以让播放器和视频组件版本独立吗?

可以,并且这个是推荐的做法。

目前播放器内部集成了视频组件,也就是说只需要依赖视频播放器即可包含视频组件。但是视频组件和播放器版本是分开管理的,可能播放器的版本是滞后的。建议依赖了视频播放器之后,在单独加一个视频组件的依赖,如下:

dart 复制代码
implementation 'com.max.mediaplayer:uniteplayer:$playerVersion'
implementation 'com.max.media:media-video:$mediaVersion'

版本更新记录

内测版

仅SNAPSHOT:

**版本(内测版,仅SNAPSHOT) 更新日志
0.5.0 1. 视频基础控制; 2. 支持配置底部icon的资源id和点击事件
0.6.0 1. 修复手势滑动bug
0.6.2 1. 修复底部icon接口Bug
0.7.0 1. 增加了错误页提示 2. 修复部分rom不能调亮度的问题 3. 自适应平板和车机 4. 修复暂停后拖动进度条持续loading的问题
0.8.6 1. 支持禁用上下滑手势 2. 调整视频View层级
0.9.0 1. 支持监听视频组件的双击、长按事件 2. 去掉toggleControlView接口

正式版

版本 更新日志
1.0.0 1. 修改controlView实例的获取方式,改为异步调用 2. 支持2/3屏和全屏两套UI布局模式一键切换 1) 2/3屏模式:controlView.setAppFrameWH() 2)全屏模式:controlView.setFullScreenWH() 3. 支持自定义LoadingView、进度条边距及icon尺寸 4. 修改UI走查问题
1.1.0 1. 修复视频时长小于1h时格式问题 2. 优化上下手势和Dock栏冲突 3. 调节亮度时取消自动调节亮度勾选 4. 修复持续上下手势,Tips闪烁 5. Loading态支持调起控件 6. 处理加载页和错误页互斥逻辑
1.2.0 1. 上下手势不主动调起播控UI 2. 视频手势层级优化 3. Loading支持播控UI调起 4. UI样式优化
1.2.2 1. 滑动进度条时,显示进度Tips 2. 进度条及底部Bar优化
1.2.3 1. 滑动进度,展示进度Tips
1.2.5 1. 调整进度条样式
1.2.6 优化全屏状态下标题栏位置
1.2.7 1. 优化全屏Toast位置(居中改到顶部)
1.3.5 1. [视频播放器UI]优化在车机屏幕下双击/单击事件的阈值和行为 2. [视频播放器UI]优化在电话场景下播放器依然能够点击的问题 3. [视频播放器UI]支持自定义播放器UI控制效果 4. [视频播放器UI]支持自定义loading延迟时长,默认1s内loading不显示. 5. [视频播放器UI]支持3/2全屏无缝播放效果 6. [音乐播放器]大小播放器设计/动效支持
相关推荐
java小吕布8 分钟前
Java Lambda表达式详解:函数式编程的简洁之道
java·开发语言
程序员劝退师_15 分钟前
优惠券秒杀的背后原理
java·数据库
java小吕布30 分钟前
Java集合框架之Collection集合遍历
java
一二小选手32 分钟前
【Java Web】分页查询
java·开发语言
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ44 分钟前
idea 弹窗 delete remote branch origin/develop-deploy
java·elasticsearch·intellij-idea
Code成立1 小时前
《Java核心技术 卷I》用户图形界面鼠标事件
java·开发语言·计算机外设
Yawesh_best1 小时前
MySQL(5)【数据类型 —— 字符串类型】
android·mysql·adb
鸽鸽程序猿1 小时前
【算法】【优选算法】二分查找算法(下)
java·算法·二分查找算法
遇见你真好。1 小时前
自定义注解进行数据脱敏
java·springboot
NMBG222 小时前
[JAVAEE] 面试题(四) - 多线程下使用ArrayList涉及到的线程安全问题及解决
java·开发语言·面试·java-ee·intellij-idea