uni-app 部分安卓手机无法播放mp4视频 但MP4视频链接复制到手机浏览器可以直接播放

uni-app 部分安卓手机无法播放mp4视频 但MP4视频链接复制到手机浏览器可以直接播放

示例代码:

<template>
<view class="container">
    <!--  
    注意:这是 App 所用页面,请勿引入微信小程序或浏览器运行,最好运行在真机  

    1. new_index.nvue、index.nvue这两个是App页面  

    2. index.nvue - 页面预加载使用 - 在线预加载方案  

    3. 另外:data.js 是上一版本留下的假数据,这一版改成了 URL 请求了(如不需要可以删除,也可作为后端请求参考)  

    4. 请各位大神多多留手,我已经把请求内存开到最大了  

    5. 视频 id 切记是字符串类型  

    6. 这里仅 App 端引入了 App 端专用评论,小程序 、H5 引入的时候 可以作为参考  

    【  
        App、小程序、H5评论请参考插件:https://ext.dcloud.net.cn/plugin?id=7875  
    】  

     -->
    <image v-if="isShowAixin" src="@/static/img/index/aixining.png"  
        :style="'position: fixed; margin-left: '+ aixinLeft +'px; margin-top: '+ aixinTop +'px; width: 70px; height: 65px; transform: rotate('+ Rotate +'deg);'">
    </image>
    <view :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;'" v-if="isShow1">
        <!--   
         1.这里的 swiper 不是用来控制视频滑动的,而是用来控制左右滑动的,如果不需要的可以改成 view  

         2.为了 视频无限加载,已经把 21 行的 appear 去掉了,加上了 loadmore 方法(第10行)  

         3.由于方法比较多,可以采取下面的方式查看代码:  
         (1)Mac:按住 option 键,然后点击方法名,即可跳转到方法  
         (2)windows:按住 Alt 键,然后鼠标左击,即可跳转到方法  
         -->
        <list @loadmore="getData" @scroll="scrolls" :loadmoreoffset="wHeight*1" :show-scrollbar="false"  
            ref="listBox" :pagingEnabled="true" :scrollable="true">

            <!-- 循环数据 -->
            <cell v-for="(item,i) in dataList" :key="i">
                <!-- 用div把视频模组套起来 -->
                <div :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;'" @disappear="stop()"  
                    :ref="'item'+i">

                    <view v-if="(k-i)<=1">
                        <view class="root">
                            <video :id="item._id+''+i" :loop="true" :src="item.src" :muted="item.isplay"  
                                @play="playIngs(i)" :enable-progress-gesture="false" :page-gesture="false"  
                                :controls="false" :http-cache="true" :show-loading="true"  
                                :show-fullscreen-btn="false" :show-center-play-btn="false" :style="boxStyle"  
                                :object-fit="object_fit" @timeupdate="timeupdate($event,i)">
                            </video>
                        </view>

                        <!-- <image v-if="!item.playIng" :src="item.src+'?x-oss-process=video/snapshot,t_480,f_jpg'"  
                            :mode="mode"  
                            :style="'width: '+ windowWidth +'px; height: '+ (wHeight - safeAreaHeight) +'px; position: absolute;'">
                        </image> -->

                        <!-- 直接用 view 就行了,一样是可以覆盖原生组件的 -->
                        <!-- 这个是暂停时出现的图标 -->
                        <view class="videoHover" @click="tapVideoHover(item.state,$event)"  
                            @touchstart="touchstartHover" :style="boxStyle">
                            <image v-if="item.state=='pause'" class="playState" src="@/static/img/index/play.png">
                            </image>
                        </view>

                        <!-- 最底下的文字部分 -->
                        <view class="content"  
                            v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == false">
                            <text class="userName"  
                                :style="'width: '+ (windowWidth - 90) +'px;'">{{item.title}}</text><!-- i={{i}} -->
                            <text class="words"  
                                :style="'width: '+ (windowWidth - 90) +'px;'">{{item.msg}}-{{k+1}}</text><!-- k={{k}} -->
                        </view>
                        <!-- 1.视频预览时的图片,currenttimes:就是获取当前滑块的时间点,如果不需要,可以注释掉 -->
                        <!-- 2.如果使用下面的视频预览的话要注意的是视频链接最好是阿里云上的,因为  
                                https://xxxxxxxxx.mp4?x-oss-process=video/snapshot,t_1000,f_jpg  
                                这个是阿里云的东西,至于其他的视频截帧我还没有试过。  
                                -->
                        <!-- 3.阿里云视频截帧地址:https://help.aliyun.com/document_detail/64555.html -->
                        <image v-if="item.isShowimage == true"  
                            :src="item.src+'?x-oss-process=video/snapshot,t_'+ currenttimes +'000,f_jpg'"  
                            mode="aspectFill"  
                            :style="'width: 120upx; height: 160upx; border-radius: 10upx; position: absolute; bottom: '+ (ProgressBarBottom + 160) +'upx; left: '+ (currentPositions - 15) +'px;'">
                        </image>
                    </view>
                </div>
            </cell>
        </list>
        <!-- 1.注意:进度条这类拖拽的东西不能放进block\cell这些循环体中的,要不然touchmove方法会捕捉有误 -->
        <view v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == true"  
            :style="'position: absolute; bottom: '+ (ProgressBarBottom + this.windowWidth*0.2)/2 +'px; left: '+ (windowWidth*2 - this.windowWidth*1.35)/2 +'px;'">
            <text style="font-size: 22px; font-weight: bold; color: #F1F1F1;">{{changeTime}} / {{videoTimes}}</text>
        </view>
        <!-- 这里就是进度条了:纯手工进度条,调整位置的话就把他们的 bottom 改成一下就行了 -->
        <view v-if="isDragging == false" @touchmove="touchmove" @touchend="touchend" @touchstart="touchstart"  
            style="position: absolute; bottom: 0px; left: 0;">
            <!-- 1.这一步必须加,为了适配低端机型 -->
            <text :style="'width: '+ windowWidth +'px; opacity: 0;'"></text>
            <!-- 2.这是未加载的时的右边的灰色部分 -->
            <view  
                :style="'width: '+ windowWidth +'px; height: 12upx; background-color: #C8C7CC; position: absolute; bottom: 0upx; opacity: '+ ProgressBarOpacity +';'">
            </view>
            <!-- 3.这里我采用的分离式办法:就是让滑动样式和不滑动的样式分开,这样相互不干扰,可以避免进度条闪动的问题 -->
            <!-- 4.注意:isShowProgressBarTime 加入了返回数据中 -->
            <view v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == false"  
                :style="'width: '+ (currentPosition) +'px; height: 12upx; background-color: #1D87FF; position: absolute; bottom: 0upx; left: 0; '">
            </view>
            <view v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == true"  
                :style="'width: '+ (currentPositions) +'px; height: 12upx; background-color: #1D87FF; position: absolute; bottom: 0upx; left: 0; opacity: '+ (ProgressBarOpacity + 0.05) +';'">
            </view>
            <view v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == false"  
                :style="'width: 12upx; height: 12upx; background-color: #1D87FF;position: absolute; bottom: 0upx; left: '+ (currentPosition) +'px;'">
            </view>
            <view v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == true"  
                :style="'width: '+ dotWidth +'px; height: '+ dotWidth +'px; background-color: #1D87FF; border-radius: 10px; position: absolute; bottom: 0upx; left: '+ (currentPositions - 5) +'px; opacity: '+ ProgressBarOpacity +';'">
            </view>
        </view>
    </view>
    <view :style="'width: '+ windowWidth +'px; height: '+ safeAreaHeight +'px; background-color: #fff;'">
        <view @click="openSelect"  
            :style="'width: '+ (windowWidth*0.9) +'px; height: 40px; margin-top: 15px; border-radius: 50px; margin-left: '+ (windowWidth*0.05) +'px; display: flex; flex-direction: row; background-color: #1D87FF;'">
            <text  
                :style="'font-size: 16px; font-weight: bold; color: #FFFFFF; margin-top: 9px; height: 22px; margin-left: 20px; width: '+ (windowWidth*0.6) +'px; overflow: hidden;'">正在播放第{{ Number(k+1) }}集</text>
            <image src="@/static/img/index/up.png"  
                :style="'width: 30px; height: 30px; position: absolute; margin-top: 5px; margin-left: '+ (windowWidth*0.79) +'px;'">
            </image>
        </view>
    </view>
    <!-- 评论弹窗 -->
    <uni-popup type="bottom" ref="pinglun" @touchmove.stop.prevent="moveHandle" v-if="isShow2">
        <view  
            :style="'width: '+ windowWidth +'px; height: '+ (boxStyle.height/heightNum) +'px; background-color: #242424; border-top-left-radius: 10px; border-top-right-radius: 10px;'">
            <!--   
             注意:  
             deleteIOSHeight  
             deleteAndroidHeight  
             这两个参数用于控制评论等的高度  
             -->
            <douyin-scrollview :Width="windowWidth" :Height="(boxStyle.height/1.23)" :deleteIOSHeight="36"  
                :deleteAndroidHeight="15" @closeScrollview="closeScrollview"></douyin-scrollview>
        </view>
    </uni-popup>
    <!-- 选集弹窗 -->
    <uni-popup type="bottom" ref="select" v-if="isShow2">
        <view class="xuanji">
            <view class="morhs"></view>
            <text class="xuanjititle">{{dataList[k].title}}</text>
            <text class="xuanjitext">{{dataList[k].msg}}</text>
            <!-- :scroll-top="scrollTop" -->
            <scroll-view :style="'width: '+ (windowWidth) +'px; height: '+ ((wHeight/1.6)*0.85) +'px;'"  
                :scroll-y="true">
                <view class="xuanjilist">
                    <view class="xuanjilis" v-for="(list,index) in dataList" @click="selectThisVideo(index)">
                        <text class="xuanjilistext" :class="index==k?'active':''">{{ Number(index+1) }}</text>
                        <!-- <view class="xuanjilisplay"><image src="../../static/bfz.png" mode="heightFix"></image></view> -->
                    </view>
                </view>
            </scroll-view>
        </view>
    </uni-popup>
    <!-- 详情弹窗 -->
    <uni-popup type="bottom" ref="detail" v-if="isShow3">
        <view class="xuanji">
            <view class="morhs"></view>
            <text class="xuanjititle">{{ detail.name }}</text>
            <text class="xuanjititle">  
                第{{Number(k + 1)}}集 共{{detail.row_number}}集  
            </text>
            <text class="xuanjitext">{{detail.desc}}</text>

        </view>
    </uni-popup>

    <view class="fhiconf" @click="goBack">
        <image class="fhiconfi" src="../../static/images/fhw.png" mode="heightFix">
        </image>
    </view>

</view>
</template>
<script>
// import userList from './data.js'//这个是假数据
/**
引入评论组件
*/
import douyinScrollview from '@/components/douyin-scrollview/douyin-scrollview.nvue'
import http from '../../utils/request.js'

export default {
    data() {
        return {
            //下面打

操作步骤:

  • 用户进入播放页面播放不了

预期结果:

  • 解决播放问题

实际结果:

  • 解决播放问题

bug描述:

  • 部分安卓手机无法播放mp4视频 但是MP4视频链接复制到手机浏览器可以直接播放

示例图片


更多关于uni-app 部分安卓手机无法播放mp4视频 但MP4视频链接复制到手机浏览器可以直接播放的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于uni-app 部分安卓手机无法播放mp4视频 但MP4视频链接复制到手机浏览器可以直接播放的实战教程也可以访问 https://www.itying.com/category-93-b0.html


在 uni-app 中遇到部分安卓手机无法播放 MP4 视频的问题,可能涉及多种原因。以下是一些可能的原因及解决方法:


1. 视频编码格式问题

  • 原因: 部分安卓设备对 MP4 视频的编码格式(如 H.264、H.265)支持不完善,尤其是较旧的设备。
  • 解决方法:
    • 将视频重新编码为 H.264 格式(使用工具如 FFmpeg)。
    • 确保视频的分辨率、码率等参数在设备支持范围内。

2. 视频链接协议问题

  • 原因: 如果视频链接是 http,部分安卓设备可能因安全策略禁止加载非 https 资源。
  • 解决方法:
    • 将视频链接改为 https
    • 如果无法使用 https,可以在 manifest.json 中配置允许 http 请求:
      "networkTimeout": {
          "request": 30000,
          "connectSocket": 30000,
          "uploadFile": 30000,
          "downloadFile": 30000
      },
      "plus": {
          "http": {
              "protocol": "http"
          }
      }
      

3. uni-app 播放器兼容性问题

  • 原因: uni-app 内置的 video 组件可能在某些安卓设备上存在兼容性问题。
  • 解决方法:
    • 尝试使用第三方播放器插件,如 video.jsplyr
    • 使用原生 H5 的 video 标签:
      <video :src="videoUrl" controls></video>
      

4. 视频链接缓存或跨域问题

  • 原因: 部分安卓设备对视频链接的缓存处理不当,或者跨域问题导致无法播放。
  • 解决方法:
    • 在视频链接中添加随机参数,避免缓存问题:
      videoUrl = 'https://example.com/video.mp4?t=' + Date.now();
      
    • 确保视频服务器支持跨域请求(CORS)。

5. 安卓系统权限问题

  • 原因: 部分安卓设备可能因权限问题无法加载网络视频。
  • 解决方法:
    • 确保应用已获取网络权限。
    • manifest.json 中配置权限:
      "permission": {
          "android.permission.INTERNET": {}
      }
      

6. 调试与日志

  • 原因: 无法确定具体问题。
  • 解决方法:
    • 使用 console.log 或调试工具检查视频链接是否正确加载。
    • 监听 video 组件的错误事件,打印错误信息:
      <video :src="videoUrl" @error="onVideoError"></video>
      
      methods: {
          onVideoError(e) {
              console.error('Video error:', e);
          }
      }
      

7. 测试与验证

  • 在不同的安卓设备和系统版本上进行测试。
  • 确保视频链接在其他应用或浏览器中能正常播放。

示例代码

以下是一个使用 video 组件的示例:

<template>
  <view>
    <video :src="videoUrl" controls></video>
  </view>
</template>

<script>
export default {
  data() {
    return {
      videoUrl: 'https://example.com/video.mp4?t=' + Date.now()
    };
  }
};
</script>
回到顶部