@Vee
2017-08-23T12:48:20.000000Z
字数 3316
阅读 2490
港台APP改版中有一个列表播放 YouTube 视频的需求,但 YouTube 的视频链接是不能直接用 Android 系统的 VideoView 来播放的,因为这不是一个真正的视频流,而是一个网页,只能用 WebView 来播放。但是用 WebView 来播放体验总不太好,而且 UI 也无法进行定制。
如果手机里面安装有 YouTube App 的话,可以利用如下方法打开 YouTube 进行播放:
startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("http://www.youtube.com/watch?v=Hxy8BZGQ5Jo")));
这种方法局限性很大,如果手机没有安装 YouTube App 的话,是无法播放的,而且这种方法是打开别人家的 APP 而离开自家的 APP,这估计也是无法接受的。
官方有提供在 Android 系统上播放 YouTube 视频的API(点击此处),这是官方支持的API,可以很好地播放视频,播放体验也不错。
虽然这是官方的 API,但是也有一点不好,就是无法自定义播放 UI,而且全屏时体验不好,经常黑屏。
如上图所示,使用该 API 播放的界面是 YouTube 官方的 UI,会带有 YouTube 自己的 logo。而且含有该播放器组件的 Activity 必须继承于 API 中的YouTubeBaseActivity,这样不便于集成。
总的来说,这不是一种比较好的方法,当然如果运营不介意界面如此,则不失为一种解决措施。详细接入方法请参考官方 API
用工具类(点此)将 YouTube 视频链接解析得到视频的真实地址,然后用 VideoView 播放。
该种方式是根据 YouTube 提供的接口(www.youtube.com/get_video_info?video_id=)来解析的,本质上来说也属于官方支持的。
这种方式可以说比较合适的了,然而这种方式有一个缺点,就是这个解析视频真实地址可能会失败,就是不是所有的视频都可以解析出来;而且这种方式是根据 YouTube 提供的接口(www.youtube.com/get_video_info?video_id=)来解析得到视频流的,不能保证以后 YouTube 是否会更改该接口规则。
如果实在无法接受第二种方案的 YouTube 视频界面,则可采用该种方案,然后把解析工作放在服务端去进行,这样就算以后规则更改,也可以在服务端动态调整,无需客户端修改。而且规则一旦定下来,如果没有特殊情况,一般也不会随便更改。
用法如下:
String youtubeLink = "http://youtube.com/watch?v=xxxx";new YouTubeExtractor(this) {@Overridepublic void onExtractionComplete(SparseArray<YtFile> ytFiles, VideoMeta vMeta) {if (ytFiles != null) {int itag = 22;String downloadUrl = ytFiles.get(itag).getUrl();}}}.extract(youtubeLink, true, true);
downloadUrl就是解析之后的视频流地址。
但是在extract方法中传入视频链接有时会解析失败,这时候最好自己解析出视频 id 之后再把 id 传入 extract中会提高成功率。解析视频 id 的工具方法如下:
public static String extractYoutubeId(String url) throws MalformedURLException {String id = null;try {String query = new URL(url).getQuery();if (query != null) {String[] param = query.split("&");for (String row : param) {String[] param1 = row.split("=");if (param1[0].equals("v")) {id = param1[1];}}} else {if (url.contains("embed")) {id = url.substring(url.lastIndexOf("/") + 1);}}} catch (Exception ex) {Log.e("Exception", ex.toString());}return id;}
根据网上所说,该种方式解析视频真实地址不是所有视频都能解析成功的,不过目前自己公司的视频目前没有遇到过解析失败的例子。
在列表中播放视频,这种时候在 ListView/RecyclerView 的 item 中嵌入 VideoView 就不合适了。因为 VideoView 继承于 SurfaceView ,而 SurfaceView 是独立于 View hierachy 而存在的,这就意味着 SurfaceView 在具有高效的渲染机制的同时,是不受 View 管理的,也就是 SurfaceView 的显示不受 View 属性控制的,不能进行平移、缩放等操作,也难以放在 ListView/RecyclerView、ScrollView 等一些控件中使用。
为了弥补 SurfaceView 的不足,Android 在 4.0 中加入了 TextureView, 它并没有创建一个单独的窗口用来绘制,这使得它可以像一般的 View 一样执行一些变换操作,设置透明度等,也很方便的放在其他 ViewGroup 中去。
所以要在 ListView/RecyclerView 中播放视频,我们就需要实现基于 TextureView 的 VideoView,实现代码参考 VideoView 就可以了。
这里引用了 GitHub 上面一个项目地址:https://github.com/waynell/VideoListPlayer,该项目实现了基于 TextureView + MediaPlayer 的视频播放器,也可以用于在 ListView/RecyclerView 中播放。但是该项目并没有提供控制视频播放的控制器,例如暂停、拖动进度条等操作。
没办法,只能自己去搞下来进行二次封装。地址为http://172.16.5.203/Android_Common/VideoListPlayer。主要为视频播放提供了一个操作面板用于控制视频的播放。
到此依然有一个问题:在列表中如何实现视频全屏小窗切换无痕播放
列表中的视频 view 是嵌入在 ListView/RecyclerView 中去的,如何能改变其中的大小实现全屏而且还是无痕切换呢。目前想到的解决方案是:
在 ListView/RecyclerView 布局同等层级中加入视频 view, 将该 view 依附在 itemView 的显示区域, 然后监听 ListView/RecyclerView 的滚动, 通过滚动的位置来动态移动视频 view 的位置,这样在全屏时只需要将其他 View 隐藏,显示该视频 view 即可。注意,在列表播放的时候也是该视频 view 在播放,由于是同一个视频 view,故可以实现无痕切换。
上述方案确实可以解决全屏播放的问题,但是由于需要监听 ListView/RecyclerView 的滚动,动态移动视频 view,故接入的时候比较麻烦。
经过一番折腾,终于实现了列表播放 YouTube 视频的需求。但是在自己完成全屏播放视频封装的时候,在 GitHub 上面发现了一个更加完美的也是基于 TextureView 封装的视频库,该库也支持列表播放、UI定制,关键是接入简单,完全不用监听 ListView/RecyclerView 的滚动。该库地址为https://github.com/lipangit/JieCaoVideoPlayer,上面有详细的接入文档。