Android自定义WebView实现Youtube网络视频播放控件

本文介绍如何创建一个自定义的YoutubePlayerView,该控件无需依赖任何SDK或第三方库,能实现播放、暂停、进度条拖动、全屏播放等功能。通过继承WebView,加载预设HTML并利用JS接口实现Java与JavaScript的交互,同时在Activity销毁或暂停时自动处理WebView的状态。详细代码和实现步骤也在文中给出。
摘要由CSDN通过智能技术生成


实现效果

项目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);
 
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值