实现效果:
项目github地址:https://github.com/AlexZhuo/AlxYoutubePlayer
因为业务需要,以下代码均以Youtube网站在线视频为例
实现功能:
1、初始化的时候显示标题和视频封面
2、初始化的时候显示一个play按钮
3、不需要依赖任何SDK,或者导入任何第三方库
4、播放过程中可以暂停,可以拖动进度条快进
5、可以全屏播放
6、切换页面的时候会自动暂停
7、页面退出的时候自动销毁WebView
8、不需要申请任何开发者账号或者获取授权
原理:
首先需要一个继承WebView的自定义控件,这里起名叫做YoutubePlayerView,在页面初始化的时候用这个WebView去加载一个事先写好的HTML,当然在加载之前,需要把Youtube的视频id和一些播放参数设置进去。然后一个小的播放窗口就完成了,此时已经完成用户点击play按钮就播放的功能。
但是光能播放还不行,我们还需要捕捉用户的点击事件,比如播放,暂停等等操作,而这些操作本身写在Youtube的JS代码中(Youtube已经把JS调用相关代码的位置预留好,就等着开发者来复写相关的代码了),需要在JS代码中调用java代码,这样就需要有一个JS调用java的接口,这里起名叫QualsonBridge,通过使用WebVIew的addJavascriptInterface()方法将Java代码的接口设置进去,并且需要一个接口实现类,实现的方法名称方法要和JS接口规定的方法一模一样,以便反射调用,一会会把详细的代码贴出来。
完成以上两点,就已经完成了播放,暂停等操作,但是还需要在Activity退出或者被覆盖的时候暂停WebView的播放,所以还需要给这个WebView写一个onDestroy的方法,并在fragment的onDestroy中调用,里面执行的主要就是清楚缓存的操作,还需要WebView写一个onPause的方法,在fragment的onPause中调用,里面主要执行JS代码:javascript:onVideoPause()
关于全屏播放:是通过一个自定义的WebChromeClient来实现将WebView扩大到全屏并修改旋转角度进行播放
代码实现:
首先需要让WebView去加载一块HTML,这段HTML是从Youtube的官方SDK中抽取出来的,本质上是一个HTML编写的小播放窗口,代码如下
<!DOCTYPE html>
<html>
<style type="text/css">
html, body {
height:100%;
width:100%;
margin: 0;
padding: 0;
background:[BG_COLOR];
overflow:hidden;
position:relative;
}
</style>
<script type = "text/javascript" src = "http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type = "text/javascript" src = "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<script src="https://www.youtube.com/iframe_api"></script>
</head>
<body>
<div id="QPlayer"></div>
</body>
<script type="text/javascript">
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('QPlayer', {
height: '100%',
width: '100%',
videoId: '[VIDEO_ID]',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange,
'onPlaybackQualityChange': onPlayerPlaybackQualityChange,
'onPlaybackRateChange': onPlayerPlaybackRateChange,
'onError': onPlayerError,
'onApiChange': onPlayerApiChange
},
playerVars: {
'autoplay': [AUTO_PLAY],
'autohide':[AUTO_HIDE],
'rel': [REL],
'showinfo': [SHOW_INFO],
'enablejsapi': [ENABLE_JS_API],
'disablekb': [DISABLE_KB],
'cc_lang_pref': '[CC_LANG_PREF]',
'controls': [CONTROLS],
'fs' : [FS],
'origin' : 'https://www.youtube.com'
}
});
}
function onPlayerReady(event) {
console.log('player is ready');
onReady('player is ready');
sendDuration();
player.setOption("captions", "track", {"languageCode": "es"});
player.unloadModule("captions");
}
var timerId = 0;
function onPlayerStateChange(event) {
clearTimeout(timerId);
switch (event.data) {
case YT.PlayerState.UNSTARTED:
onStateChange("UNSTARTED");
break;
case YT.PlayerState.ENDED:
onStateChange("ENDED");
break;
case YT.PlayerState.PLAYING:
player.unloadModule("captions");
onStateChange("PLAYING");
timerId = setInterval(function() {
setCurrentSeconds();
}, 100);
break;
case YT.PlayerState.PAUSED:
onStateChange("PAUSED");
break;
case YT.PlayerState.BUFFERING:
onStateChange("BUFFERING");
break;
case YT.PlayerState.CUED:
onStateChange("CUED");
break;
}
}
//底下的这些function就是调用java代码的接口函数
function onPlayerPlaybackQualityChange(playbackQuality) {
console.log('playback quality changed to ' + playbackQuality.data);
onPlaybackQualityChange('playback quality changed to ' + playbackQuality.data);
}
function onPlayerPlaybackRateChange(playbackRate) {
console.log('playback rate changed to ' + playbackRate.data);
onPlaybackRateChange('playback rate changed to ' + playbackRate.data);
}
function onPlayerError(e) {
console.log('An error occurred: ' + e.data);
onError('An error occurred: ' + e.data);
}
function onPlayerApiChange() {
console.log('The player API changed');
onApiChange('The player API changed');
}
function onReady(e){
window.QualsonInterface.onReady(e);
}
//这个函数是最重要的,用于通知Android代码播放状态改变
function onStateChange(e){
window.QualsonInterface.onStateChange(e);
}
function onPlaybackQualityChange(e){
window.QualsonInterface.onPlaybackQualityChange(e);
}
function onPlaybackRateChange(e){
window.QualsonInterface.onPlaybackRateChange(e);
}
function onError(e){
window.QualsonInterface.onError(e);
}
function onApiChange(e){
window.QualsonInterface.onApiChange(e);
}
function setCurrentSeconds(){
window.QualsonInterface.currentSeconds(player.getCurrentTime());
}
function sendDuration(){
window.QualsonInterface.duration(player.getDuration());
}
function setLog(msg){
window.QualsonInterface.logs(msg);