行业知识
IOS H5页面中 HLS视频无法正常播放,使用hls.插件
2026-11-09 10:23:43
来源:互联网转载
IOS H5页面中 HLS视频无法正常播放,使用hls.插件
HLS.js依靠 HTML5 视频和 MediaSource Extensions 进行播放。
所有 iPhone 浏览器 (iOS) 都没有可用的 MediaSourceExtension,因此Hls.js将不起作用。如果您在 iPhone 上检查 Hls.isSupported() ,您会看到该函数返回 false 。
if (Hls.isSupported()) { var hls = new Hls(); hls.loadSource(videoSrc); hls.attachMedia(video); } else if (video.canPlayType('application/vnd.apple.mpegurl')) { video.src = videoSrc; } iOS 可以使用普通的 HTML,因为 Safari 具有原生 HLS 支持。初始化 Hls.js 将阻止本机 HLS 功能根本无法工作。
Hls.isSupported return true
但这个解决方案对我不起作用,因为Hls.isSupported 总是返回 true。我做了以下调整以使其正常工作:
React:
import Hls from "hls.js";import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";interface PlayerProps { src?: string; poster: string; onPlay(): void; onPlayFailed(): void;}export const Player = forwardRef(({ src, poster, onPlay, onPlayFailed }, ref) => { const videoRef = useRef(null); const hlsRef = useRef(null); useEffect(() => { if (!src || !videoRef.current) return; const supportHLS = Boolean(videoRef.current.canPlayType("application/vnd.apple.mpegurl")); if (supportHLS) { videoRef.current.src = src; videoRef.current.play().then(onPlay).catch(onPlayFailed); } else { hlsRef.current = new Hls(); const hls = hlsRef.current; hls.on(Hls.Events.MEDIA_ATTACHED, function () { videoRef.current!.play().then(onPlay).catch(onPlayFailed); }); hls.loadSource(src); hls.attachMedia(videoRef.current); return () => { hls.destroy(); }; } }, [src]); useImperativeHandle(ref, () => videoRef.current!, []); return ( );}); Vue:
然后,你可以在 Vue 组件中这样使用它:
import Hls from 'hls.js'; export default { props: { src: { type: String, default: '' }, poster: { type: String, required: true } }, data() { return { hlsInstance: null }; }, mounted() { this.initializePlayer(); }, beforeDestroy() { if (this.hlsInstance) { this.hlsInstance.destroy(); this.hlsInstance = null; } }, methods: { initializePlayer() { if (!this.src || !this.$refs.videoElement) return; const supportsHLS = this.$refs.videoElement.canPlayType('application/vnd.apple.mpegurl'); if (supportsHLS) { this.$refs.videoElement.src = this.src; this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed); } else { this.hlsInstance = new Hls(); const hls = this.hlsInstance; hls.on(Hls.Events.MEDIA_ATTACHED, () => { this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed); }); hls.loadSource(this.src); hls.attachMedia(this.$refs.videoElement); } }, onPlay() { this.$emit('onPlay'); }, onPlayFailed() { this.$emit('onPlayFailed'); } }, watch: { src() { this.initializePlayer(); } } }; /* Add your styles here */ 在这个 Vue 组件中,我们使用了 Vue 的生命周期钩子 mounted 来初始化播放器,并在 beforeDestroy 钩子中销毁 hls.js 实例以避免内存泄漏。data 对象用来存储 hls.js 的实例。methods 包含了初始化播放器的方法以及处理播放和播放失败的方法。
此外,我们使用 watch 选项来监听 src 属性的变化,如果它变化了,我们重新初始化播放器。
最后,我们通过 $refs 访问到 DOM 元素,这和 React 中的 useRef 类似。我们还通过 $emit 触发自定义事件,以便父组件可以监听这些事件。
注意:在模板中,我们使用 :src="src" 和 :poster="poster" 来绑定属性,这和 React 中的属性绑定类似。
确保在父组件中监听 onPlay 和 onPlayFailed 事件,就像这样:
import Player from './Player.vue'; export default { components: { Player }, data() { return { videoSrc: 'your-video-source-url', videoPoster: 'your-poster-image-url' }; }, methods: { handlePlay() { // 处理播放事件 }, handlePlayFailed() { // 处理播放失败事件 } } }; 画面为初始页面,视频进度会走,有声音
但使用之后,发现项目中的hls视频加载成功,可以播放,但是播放只有声音,画面为初始的画面,调查打断点之后,发现解决方案
import Hls from 'hls.js'export default { name: 'HlsVideoPlayer', props: { hlsUrl: { type: String, required: true } }, data () { return { hlsInstance: null } }, mounted () { this.initializePlayer() }, beforeDestroy () { if (this.hlsInstance) { this.hlsInstance.destroy() this.hlsInstance = null } }, methods: { onLoadedMetadata () { console.log('Video metadata loaded') }, initializePlayer () { if (!this.hlsUrl || !this.$refs.videoElement) return const supportsHLS = this.$refs.videoElement.canPlayType('application/vnd.apple.mpegurl') console.log(Hls.isSupported(), supportsHLS, 'hls.isSupported', 'supportsHLS') // if (supportsHLS) { // this.$refs.videoElement.src = this.hlsUrl // this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed) // } else { // this.hlsInstance = new Hls() // const hls = this.hlsInstance // hls.on(Hls.Events.MEDIA_ATTACHED, () => { // this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed) // }) // hls.loadSource(this.hlsUrl) // hls.attachMedia(this.$refs.videoElement) // } if (Hls.isSupported()) { // 如果支持 hls.js(MediaSource Extensions) this.hlsInstance = new Hls() const hls = this.hlsInstance hls.on(Hls.Events.MEDIA_ATTACHED, () => { this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed) }) hls.loadSource(this.hlsUrl) hls.attachMedia(this.$refs.videoElement) } else if (supportsHLS) { // 如果支持原生播放 // video.src = url // // 自动播放 // video.addEventListener('canplay', function () { // video.play() // }) this.$refs.videoElement.src = this.hlsUrl this.$refs.videoElement.play().then(this.onPlay).catch(this.onPlayFailed) } }, onPlay () { console.log('onPlay') // this.$emit('onPlay') }, onPlayFailed () { console.log('onPlayFailed') // this.$emit('onPlayFailed') } }, watch: { hlsUrl () { this.initializePlayer() } }}.hls-video-player { width: 100%; max-width: 600px; /* 或其他你需要的宽度 */ margin: 0 auto; display: flex; margin: 0 auto; justify-content: center; align-items: center;}.videoElement{ width: 100%;}
下一篇:怎么建网站放视频?