美文网首页面试那些事
H5-video适配多端踩坑

H5-video适配多端踩坑

作者: _静夜听雨_ | 来源:发表于2022-07-26 13:28 被阅读0次

最近项目中,用到h5的video去播放视频,N年前也做过,知道有不少坑,这次再次入坑,准备记录一下,同时也可以给用h5去实现视频播放的小伙伴,提供一些参考,能够少踩坑。

这次我们要兼容的手机:安卓和IOS
兼容的环境:h5、小程序、APP和钉钉
不采用视频自身的播放控制,全部由页面自己控制

video代码:

<div className='video-wrapper'>
    <video
        preload='auto'
        ref={videoRef}
        autoPlay={false}
        loop={false}
        muted={muted}
        // poster={$getImage(poster)}
        playsInline
        x5-video-player-type="h5"
        x5-playsinline='true'
        webkit-playsinline='true'
        onPause={onPause}
        onEnded={onEnded}
        onLoadedMetadata={onLoadedMetadata}
        onError={onError}
    >
        <source src={src || ''} type='video/mp4'/>
        您的浏览器不支持播放mp4。
    </video>
    { poster && status === 'init' && (
        <img className='video-poster' src={$getImage(poster) || ''} alt="" />
    )}
</div>

属性问题说明:

1.autoplay

因为ios环境下,需要用户主动触发才能播放,另外进入页面后,直接自动播放,可能对用户也不太友好。所以为了保持统一,放弃了自动播放。

2.muted

静音切换,根据自己需要默认打开还是关闭,注意页面上的静音控制展示要和video播放器一致,别搞反了

3.loop

循环播放,我们要求可以循环播放,同时每次播放结束后上送数据。但是循环播放(loop为true)的时候,无法监听end事件,这就导致无法上送数据。
方法一:如果不想麻烦,可以设置循环播放,利用video的timeupdate事件监听,拿到当前播放时间currentTime,再拿currentTime和duration比较,接近时上送,可能会有<1s的时间误差,或者记录上次播放时间currentTime,如果这次currentTime比上次的小,说明又进入下一次循环播放,再上送数据。
方法二:曲线救国,设置loop为false,这样每次就可以监听到end,然后我们手动触发再次播放,同时上送数据,来达到我们的效果,对用户来说,无感知。

4.poster

视频未加载前的遮罩层图片,
我们放弃直接使用video自带的poster效果,自己用img来控制遮罩层。
video自带的poster对图片有要求,首先图片要和视频播放时的比例一致,因为要匹配不同机型,不然可能会出现,图片位置和视频位置不一致,不能完全遮罩,造成不好的体验。
我们一开始是使用了poster的,适配也刚好。但是在钉钉环境,视频加载完,直接把poster遮罩隐藏掉了,直接显示视频,我们的视频开头刚好是白色,所以给人感觉挂了,所以放弃video自带poster,自己控制,当用户点击了开始播放后,再把遮罩层隐藏掉。

5.loadedmetadata、loadeddata事件

ios事件监听函数必须要在用户手动触发播放后,才能监听到,比如我们想监听视频资源加载完毕后,进行页面按钮显示控制操作,所以我们统一做成了,必须用户手动触发才开始播放。

6.ended事件

播放结束监听函数,只能在整个视频播放结束的时候才能监听到。
如果循环播放,loop为true,则无法触发。
另外ended的时候,一定会触发pause事件监听,所以如果你同时有pause和ended回调的时候,需要注意边界处理

7.pause事件

暂停时监听函数,视频暂停时,会触发暂停监听函数,视频播放结束也会触发,我们这次自己模拟循环播放,所以同时使用了pause和ended,然而ended的时候又不能暂停,所以要过滤掉ended时触发的暂停回调,根据video的ended状态,进行过滤,这样就能模拟正常的循环播放。

业务问题:

1.自己开启了定时器,记录视频的播放时间

自己开启定时器,时间精度不够,每次暂停和播放,都会有一定延时,如果暂停次数太多,时间会出入比较大,因为我们这次注意是测试,精度问题忽略了,不考虑,如果要自己展示视频时长,建议利用updatetime去更新时长,这样更准确点。

2.应用切到后台

切到后台,触发了视频的暂停,但是不同环境表现形式不一样,比如,ios小程序,直接暂停,必须用户手动触发,应该是腾讯做了什么操作,所以我们利用visibilitychange来监听应用的切换

    const visiabilityChangeHandle = ()=>{
        if(document.hidden){
            pause()
        }else{
            play()
        }
    }
    document.addEventListener('visibilitychange', visiabilityChangeHandle)
3.应用切到列表状态

应用切到列表状态时,安卓和切到后台一样,我们可控,切后台暂停,切回来,触发播放。但是在ios多环境下,仍然继续播放,因为我们这次没有和原生交互,所以拿不到用户上滑进入应用列表的场景,产品认为没问题,就这样操作了,建议最好统一控制,避免表现形式不一致。

4.控制按钮显示

除了初始的播放,其他自定义的播放控制按钮和视频上层展示的内容,一定要视频开始播放后再显示出来,另外要注意计时器和播放状态的一致性。

5.内存飙升,可能会白屏

在内存小的一些老旧手机上,如果用户多次切换视频,或者从多个入口打开视频,导致内存可能飙升,直接爆掉,出现白屏。
如果出现这种情况,将video的src属性=null,再让父级清空自己,这样内存得到了释放。

6.不设置video的poster

如果我们自己控制poster,而没有设置video的poster,在安卓部分手机上会加载webview默认的poster作为视频背景,在视频播放前,闪一下,很尴尬,可以在webview中修改默认video背景即可。


image.png
7.canvas实现video

因为钉钉环境下,三星Galaxy G9730 Android10,vivo X21A Android9无法内联播放,导致部分功能无法继续进行,备用方案,canvas实现video就上了

let posterWidth = 0
let posterHeight = 0
let requestAnimationFrameId = null
    const initVideo = (config) =>{
        //创建video标签,并且设置相关属性
        videoRef.current = document.createElement('video')
        videoRef.current.preload = 'auto'
        videoRef.current.autoplay = false
        videoRef.current.src = config[businessType]?.video?.url
        videoRef.current.poster = config[businessType]?.video?.poster
        videoRef.current.addEventListener('ended', onceEndCallback, false)
        videoRef.current.addEventListener('pause', onPauseCallback, false)
        videoRef.current.addEventListener('loadedmetadata', onLoadedMetadataCallback, false)
    }

    const drawVideo = () =>{
        ctxRef.current.drawImage(videoRef.current, 0, 0, posterWidth * 3, posterHeight * 3)
        requestAnimationFrameId = requestAnimationFrame(drawVideo)
    }
    
    const draw = (canvas) => {
        if (canvas) {
            //获取canvas上下文
            if(!ctxRef.current){
                ctxRef.current = canvas.getContext('2d')
                // 获取屏幕宽度作为canvas的宽度 这个设置的越大,画面越清晰(相当于绘制的图像大,然后被css缩小)
                canvas.width = posterWidth * 3
                canvas.height = posterHeight * 3
             }
            videoRef.current.play()
            drawVideo()
        }
    }

这里采用poster遮罩层的宽高来适配canvas,如果你要全屏,可以用屏幕可视宽高来适配。

这次又把h5使用video播放视频的坑又过了一遍,下次直接跳过。。。

相关文章

  • iOS13适配

    参考: iOS13 适配踩坑 - 持续更新 iOS 13 适配要点总结 iOS 13 适配要点总结 1、prese...

  • UniversalLink适配踩坑

    iOS UniversalLink适配踩坑 最近微信OpenSDK升级微信OpenSDK更新要求 以及QQ Ope...

  • Xcode 10 适配踩坑

    Xcode 10 release 之后第一时间便是更新了 Xcode 10,但是项目一运行发现编译错误。相信很多人...

  • Xcode 8 适配(踩坑)

    在每一次升级 后,难免会有一些莫名的 Bug 产生,在此记录着,以便快速解决。 1、快捷键不灵 2、模拟器的选项不...

  • ios开发干货

    备注:希望文档坚持不断更新,节约更多的踩坑时间. 1) Iphonex适配,iphonex 手机,当前页面View...

  • iOS 11 适配以及Xcode 9小Tips

    网上适配iOS 11的文章很多,但还是有些坑不踩不知道,这里总结一下自己在项目中适配iOS 11的遇到的问题...

  • 屏幕适配的那些坑

    屏幕适配的那些坑 屏幕适配的那些坑

  • Xcode13踩坑,iOS15适配

    Xcode13踩坑,iOS15适配 1.升级完Xcode13之后遇到滚动tableView到底部时tabbar颜色...

  • iOS中刘海屏幕适配

    iOS适配刘海屏,看我避免踩坑 终生程序员小松哥关注 0.9892018.12.31 17:03:52字数 1,0...

  • ios11适配 那些踩过的坑

    本次适配ios11的迭代版本终于上线了,细数一下,还真的遇到了挺多的坑。在此记录下,给自己踩过的坑留个印记,也为了...

网友评论

    本文标题:H5-video适配多端踩坑

    本文链接:https://www.haomeiwen.com/subject/iwxzirtx.html