背景需求
最近接到一个需求,就是用webview在加载带视频类的网页的时候,使用本地的播放器去替换webview中的播放器,然后使用本地播放器去播放,如果对需求不太清楚可以去使用夸克浏览器,然后找一个视频小站播放个视频就清楚了。
面临的问题有哪些?
1 如何获取webview加载页面中的视频链接
2 如何控制webview原生播放器的(因为你需要暂停原始播放器的播放)
3 本地的播放器如何嵌入webview中原生播放器的位置,并跟随滚动
获取webview页面中的视频url
这个其实就相当于浏览器的资源嗅探功能,实现方式有三种
- js获取,在webview中注入下面这段js
var isPlayOnWeb=false;
var interval = setInterval(function videoTagFinder() {
var videoTags = document.getElementsByTagName("video");
for (var index =0; index < videoTags.length; index++) {
var videoTag = videoTags[index];
if (videoTag.getAttribute("marked") =="1") {
continue;
}
videoTag.addEventListener("webkitbeginfullscreen", onEnterFullScreenEvent,true);
videoTag.addEventListener("webkitendfullscreen", onExitFullScreenEvent,true);
videoTag.addEventListener("play", onVideoPlayEvent,true);
videoTag.addEventListener("pause", onVideoPauseEvent,true);
videoTag.setAttribute("position",index)
videoTag.setAttribute("marked","1");
}
function onEnterFullScreenEvent() {
}
function onExitFullScreenEvent() {
}
function onVideoPlayEvent() {
if(!isPlayOnWeb){
checkIsNeedUsePlayerOfApp(this)
}
}
function onVideoPauseEvent() {
}
function checkIsNeedUsePlayerOfApp(videoTag) {
var i = setInterval(function () {
notifyAppPlayerToPlay(videoTag);
videoTag.pause();
clearInterval(i)
},200)
}
/**
* notify app to play video
* @param videoTag
*/
function notifyAppPlayerToPlay(videoTag) {
var videoSrc = videoTag.currentSrc;
var sourceArr =new Array();
var sources = videoTag.getElementsByTagName("source");
if (sources !=null && sources.length >0) {
for (var index =0; index < sources.length; index++) {
var sourceInfo = {
'url': sources[index].getAttribute("src"),
'media': sources[index].getAttribute("media"),
'type': sources[index].getAttribute("type")
};
sourceArr.push(sourceInfo);
}
}
var videoInfo = {
'videoUrl': videoSrc,
'source': sourceArr,
'title': document.title,
'url': document.URL,
'position':videoTag.getAttribute('position')
};
// 调用native方法
window.JSToNative.webViewPlayVideoAtURL(JSON.stringify(videoInfo));
}
},300)
function setPlayOnWeb(){
isPlayOnWeb=true;
}
单单通过上面这段js仅仅可以获取Video标签的视频url,像一些盗版站点通常会采用IFrame引入其他站点的视频,这样这种方式就失效了,js功底比较弱,暂时没有非常好的js解决方案。
- 拦截所有浏览器的请求,对请求结果进行分析(推荐)
(VBrowser)
这种方法获取的视频url比较准确,但是速度稍微慢一些
这个开源项目就是类似的原理,获取Webview发出的所有请求,然后对响应头进行分析,主要是对mime-type进行分析,其中可以通过Head请求进行探测优化
- 浏览器内核获取(如果你的项目支持的自有内核的话)
控制WebView原生播放器
在已经获取视频地址的情况下,需要对Webview原生播放器进行控制。
这里分为两种情况Video标签和IFrame标签。
针对video标签,可以继续使用上面那段js,它里面已经对Video标签进行了控制,关键是对IFrame标签的控制,我的解决方案也比较粗暴。
!function(){
var iframeTags = document.getElementsByTagName("iframe");
var ifmParent;
var parentHeight = 250;
for (var index = 0; index < iframeTags.length; index++) {
var iframeTag = iframeTags[index];
if(iframeTag.offsetHeight >500){
canPlay = false;
break;
}
if(iframeTag.src != "" && iframeTag.offsetHeight>150){
var url = window.location.href;
ifmParent = iframeTag.parentNode;
if(url.search('http://www.haitum.cn') != -1){
ifmParent = iframeTag.parentNode.parentNode;
}
if(ifmParent.style.paddingTop){
ifmParent.style.paddingTop="0%";
}
parentHeight = iframeTag.offsetHeight
iframeTag.remove();
break;
}
}
ifmParent.innerHTML = "<div id='player_area' style='background:#000; position:relative;width:100%; height:"+parentHeight+"px;'><img id='playimg_sg_webvideo' src='http://xxxx.webvideo.play' height='100px' width='100px' style='height:100px; width:100px; position:absolute;top:50%; left:50%;transform: translate(-50%,-50%); '/> </div>";
var playIcon = document.getElementById("playimg_sg_webvideo");
playIcon.onclick = function () {
window.JSToNative.iFramePlayVideo();
}
}()
原理是直接将Iframe标签移除,然后自己在原IFrame标签位置盖上一个播放按钮,这样就可以自己造一个播放按钮,捕获用户点击播放的时机。
将本地播放器嵌入webview的播放器区域,并跟随滚动
var videoTags
function startVideoScroll(isVideo,position){
videoTag = document.getElementsByTagName("VIDEO")[position];
if(videoTag==null){
videoTag = document.getElementById('player_area');
if(videoTag==null){
return;
}
}
//首先调用一次,作为初始化位置
getVideoPosition(videoTag)
}
// 滑动监听video标签位置
function getVideoPosition(video){
var scrollTop=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;//复杂模式
var pageWidth = document.body.clientWidth || document.body.offsetWidth;
//标签距离顶部-卷去高度=标签距离屏幕顶部高度
var videoPositionStatus = 0;//视频在页面位置的5种标识
var marginPageTopHeight = getPosition(video)-scrollTop//距离顶部高度
if(marginPageTopHeight>=0){
if(marginPageTopHeight<window.innerHeight && (marginPageTopHeight+video.clientHeight)<window.innerHeight){
videoPositionStatus=1
//console.log("视频完全在屏幕中")
}else{
if(window.innerHeight+scrollTop<getPosition(video)){
videoPositionStatus=1
//console.log("视频在底部不可见")
}else{
videoPositionStatus=3
//console.log("视频在底部遮挡一部分")
}
}
}else{
if((getPosition(video)+video.clientHeight)<scrollTop){
videoPositionStatus=4
//console.log("视频在顶部不可见")
}else{
videoPositionStatus=5
//console.log("视频在顶部遮挡一部分")
}
}
window.JSToNative.getVideoPosition(videoPositionStatus+":"+getPosition(video)+":"+video.clientWidth+":"+video.clientHeight+":"+getOffsetLeft(video) + ":" + pageWidth);
}
//元素距离顶部坐标
function getPosition(el) {
var x = 0,
y = 0;
while (el != null && (el.tagName || '').toLowerCase() != 'html') {
x += el.offsetLeft || 0;
y += el.offsetTop || 0;
el = el.offsetParent;
}
return parseInt(y, 10) ;
}
//元素距离左边距离
function getOffsetLeft(ele){
var p=ele.offsetParent;
var left=ele.offsetLeft;
while(p){
if(window.navigator.userAgent.indexOf("MSIE 8")>-1){
left+=p.offsetLeft;
}else{
left+=p.offsetLeft+p.clientLeft;
}
p=p.offsetParent;
//left+=p.offsetLeft;
// p=p.offsetParent;
}
var obj={};
obj.x=left;
return obj.x;
}
上面这段js可以用来获取Video标签或者IFrame标签的初始化位置,然后在配合对Webview的滑动进行监听就可以做到将本地播放器嵌入Webview了。
功能实现了,但是感觉没有夸克做的好,谁有更好的解决方案也可以留言讨论下。
网友评论