uniapp video网页端可以播放视频,手机端却无法播放
介绍:本文主要介绍uniapp中video标签在手机端无法播放视频的问题并且如何解决。
1.问题场景
- 通过后端接口获取到视频mp4 的地址,然后使用video标签放入src中直接渲染,uniapp在web浏览器打开可以正常播放视频,在app真机调试却无法播放。
- 后端的接口是一个文件下载 接口,直接在web浏览器上访问视频的地址,浏览器上能够正常播放
- 后端在本地服务器的时候,通过video标签访问视频地址,web浏览器打开可以正常播放视频,在app真机调试也可以播放视频。
- 后端在部署上线 后,通过video标签访问视频地址,uniapp web浏览器打开可以正常播放视频,在app真机调试却不可以播放视频。
- 后端在部署上线 后,直接 在web浏览器上访问视频的地址,可以正常播放。在微信 打开地址也可以正常播放,但是在手机浏览器上却无法播放。
- 疑惑:是不是后端部署上线 后,通过http传输 的过程中,发生了未知的问题,导致在手机浏览器 和uniapp上也无法正常访问视频
2.解决方案1
后端直接把mp4的文件格式,转换成flv视频格式,再返回给前端,前端可以正常访问。
这样会有问题:
- flv格式在web浏览器上是无法播放的。(因为flv格式已经被浏览器抛弃了)
- flv格式在手机浏览器和通过uniapp的video标签都可以正常播放。
3.解决方案2
通过webview在uniapp上嵌套一个H5页面,通过H5页面来进行访问。H5页面是通过浏览器来读取视频文件的,只要在web浏览器上可以播放这个视频,那么我们通过webview就一定可以播放视频。因为浏览器的内核比较强大。 下面来介绍如何使用webview,以及可能遇到的坑。
1.下载webview.js包
webview包地址: hybrid/html/uni.webview.1.5.5.js · alpha · DCloud / hello uni-app x · GitCode
如果没有以上网站过期了,就去uniapp官网找: web-view | uni-app官网 (dcloud.io)
下载这个webview包的时候,建议直接复制代码 ,自己再创建一个js文件,把代码复制进去。要把包放入static里面。 否则有可能出现以下情况:
- 明明下载出来的是js,怎么文件一打开全是html内容?
- 直接引用的时候就一直报错。
- 建议采用我上面的方案
- 正确的情况
2.使用webview
vue页面
js
<web-view
v-if='showWebView'
class="web-view"
:webview-styles="webviewStyles"
:src="`/static/html/index.html?url=${webViewURL}`"
></web-view>
export default {
data() {
return {
showWebView: false,
webViewURL:'',
webviewStyles: {
width: '100%',
height: '100%',
},
}
},
mounted() {
this.getUrl()
},
methods: {
getUrl() {
//url是从后端获取到视频的地址
let url = 'xxx.com'
this.webViewURL = url
this.showWebView = true
}
}
}
html页面
- webview.js文件要放在body里面
- UniAppJSBridgeReady加载完成触发的函数
- getEnv只是获取当前设备环境的函数,可以不使用
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script type="text/javascript" src="js/uni.webview.1.5.5.js"></script>
<video id="video" controls src=""></video>
<script type="text/javascript">
document.addEventListener("UniAppJSBridgeReady", function () {
uni.getEnv(function (res) {
let href = window.location.href
let url = href.split('url=')[1]
let video = document.getElementById('video')
video.setAttribute('src', url)
});
});
</script>
</body>
</html>
3.webview通信
- 上面的案例是webview最简单的使用方法
- 以下介绍如何进行vue页面和html页面的通信,做到在html页面有退出按钮,返回到vue页面。
- 在vue页面通过通信传入数据到html页面。(当然上面的案例是通过拼接地址来做到通信)
vue页面
- @message:网页向应用
postMessage
时,会在特定时机(后退、组件销毁、分享)触发并收到消息。 - @onPostMessage:网页向应用实时
postMessage
- 应用(vue页面)向html发信息evalJS(方法)
js
<web-view
v-if='showWebView'
class="web-view"
:webview-styles="webviewStyles"
src="/static/html/index.html"
@message='handleWebviewMessage'
@onPostMessage='handleWebviewMessage'>
</web-view>
export default {
data() {
return {
showWebView: false,
webviewStyles: {
width: '100%',
height: '100%',
},
stack: null,
}
},
mounted() {
//后端视频地址
let url = 'https:/xxx.com/file/uploads/717a743a-5516-4101-a55f-d1a542d25fe1'
this.showWebView = true
setTimeout(() => {
//在网页端这端代码会报错,加上下面的代码,作用:不在H5页面起作用
//这里加定时器,是为了等待webview完全加载完成后再发信息。
// #ifndef H5
const pages = getCurrentPages()
this.stack = pages[pages.length - 1].$getAppWebview().children()[0]
// 发信息给html
this.stack.evalJS(`receiveData('${url}')`)
// #endif
}, 2000)
},
methods: {
handleWebviewMessage(e) {
// html返回来的数据
console.log('数据', e);
let show = e.detail.data[0]['show']
this.showWebView = show
},
}
}
html页面
- receiveData方法必须和vue页面evalJS()里面的名称对应
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script type="text/javascript" src="js/uni.webview.1.5.5.js"></script>
<video id="video" controls src=""></video>
<button id="btn">退出界面</button>
<script type="text/javascript">
function receiveData(data) {
let video = document.getElementById('video')
video.setAttribute('src', data)
}
document.getElementById('btn').addEventListener('click', function() {
// 通知vue页面进行关闭窗口
uni.postMessage({
data: {
show: false,
}
})
})
</script>
</body>
</html>
可能踩坑: 下面这样都是无法传输的,都是会报错的,因为evalJS传入动态的参数只能采用我上面的例子
js
this.stack.evalJS(`receiveData(${url})`)
this.stack.evalJS("receiveData("+url+"))"