小工具知识网

当前位置: 首页 > 行业知识 > IOS H5页面中 HLS视频无法正常播放,使用hls.插件

行业知识

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%;}

上一篇:蓝桥杯倒计时 41天 - KMP 算法

下一篇:怎么建网站放视频?