uniapp - 腾讯云点播小程序插件

Posted GitLqr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uniapp - 腾讯云点播小程序插件相关的知识,希望对你有一定的参考价值。

欢迎关注微信公众号:FSA全栈行动 👋

一、简介

微信小程序播放教育类视频要求具备有相关资质,但这些资质一般公司很难短时间申请下来(甚至有的公司压根就申请不了),而【短视频播放器小程序插件】含有《信息网络传播视听节目许可证》的资质证书备案,可以利用该插件来解决资质问题,相关截图如下:

图片来源:https://cloud.tencent.com/document/product/266/36849

采购流程于技术无关,以下内容着重讲解如何集成该微信小程序插件。

注:【短视频播放器小程序插件】授权费 3 万/年(有 14 天试用 Licence),如果有购买腾讯云其他服务的话,满足一定条件,会赠送 1 年 免费使用 Licence,详情找腾讯云客服咨询(2022 年 04 月如此,赠送情况可能随时会变)。

二、使用

1、绑定插件

因为微信小程序插件没有实质代码或 SDK,所以无法在本地添加集成,需要在微信小程序平台,将 小程序AppID插件AppID 进行绑定(即给小程序添加插件),开发者工具在编译时会自动引入,绑定有 2 种方式:

  • 方式 1:登录微信小程序平台,在 设置-第三方设置 中找到 添加插件,输入插件 AppID(wx116d0dd5e6a39ac7 )搜索并添加:

云点播短视频播放器文档:https://mp.weixin.qq.com/wxopen/pluginbasicprofile?action=intro&appid=wx116d0dd5e6a39ac7&lang=zh_CN

2、集成插件

微信小程序原生工程需要 在 app.json 里声明使用的插件及版本,对应到 uniapp 工程,则是在 manifest.json 文件中微信小程序特有配置(即 mp-weixin 节点) 处,进行 plugins 配置声明:

// manifest.json 源码视图

  /* 小程序特有相关 */
  "mp-weixin": 
    "appid": "wxxxxxxxxxxx",
    "plugins": 
      // 云点播短视频播放器
      // 文档:https://mp.weixin.qq.com/wxopen/plugindevdoc?appid=wx116d0dd5e6a39ac7&token=1835838344&lang=zh_CN
      "cloudPlayer": 
        "version": "0.1.2",
        "provider": "wx116d0dd5e6a39ac7"
      
    
  

manifest.json 配置项说明:https://uniapp.dcloud.io/collocation/manifest.html

3、页面内使用播放器

微信小程序原生工程需要 在 页面的 xxxx.json 里声明,对应到 uniapp 工程,则是在 pages.json 文件中,在需要使用插件的 页面的 style 的微信小程序特有配置(即 mp-weixin 节点)处,进行 usingComponents 配置声明:

// pages.json

  "pages": [
    ...,
    
      "path": "pages/course/course",
      "style": 
        "navigationBarTitleText": "课程",
        "mp-weixin": 
          // 云点播短视频播放器
          "usingComponents": 
            "cloud-player": "plugin://cloudPlayer/player"
          
        
      
    
  ],
  "globalStyle": 
    ...
  

pages.json 配置项说明:https://uniapp.dcloud.io/collocation/pages.html#style

声明完哪个页面需要使用插件播放器之后,就可以在那个页面的布局文件中使用插件播放器了:

// 在wxml里插入
<cloud-player
  appid="xxxxx"
  fileid="xxxxxxxx"
  playerid="myPlayerId"
></cloud-player>

注:微信小程序原生工程中,页面是 wxml 文件,uniapp 工程中是 vue 文件。另外,目前这种声明方式只对单个配置过的页面有效,也就是说,如果其他页面也需要使用插件播放器,还需要在其他页面的style中单独进行配置,这就很麻烦了,不过现在不用烦恼,后面会解决这个问题。

4、组件内使用播放器

为了功能复用,以及方便代码维护,实际开发中,往往会自定义组件,对常用的布局、功能进行封装。微信小程序原生工程可以在自定义组件的 json 文件中进行配置,跟页面相同的 usingComponents 配置即可:

官方的 云点播短视频播放器-开发文档 只说明在了如何在网页中使用插件,但没有对组件中如何使用插件进行说明,很无语,希望后续官方能完善一下。另外,这是我发起工单询问之后,腾讯技术售后给我的 demo 工程中的代码,是否有效暂不确定 -_-!

uniapp 遵循 vue 规范,想要在自定义组件要使用其他自定义组件,需要在 vue 文件中的 <script> 标签中,配置 components ,例如:

<script>
import leadHeader from "./lead-header.vue";
export default 
  components: 
    leadHeader,
  ,
;
</script>

那么依葫芦画瓢,是否也可以这样配置插件播放器呢?例如:

<script>
import cloudPlayer from "plugin://cloudPlayer/player";
export default 
  components: 
    cloudPlayer,
  ,
;
</script>

可惜不行,编译时会报错 Error: Can't resolve 'plugin://cloudPlayer/player',而且 uniapp 也没有提供对应的配置项。不过呢,uniapp 是可以直接使用微信小程序自定义组件的,这是否意味着,可以将用到插件的自定义组件改用 wxml+wcss 的方式进行编写,然后再引入到 uniapp 工程中呢?

uniapp 使用小程序原生组件:https://uniapp.dcloud.io/tutorial/miniprogram-subject.html#小程序自定义组件支持

仔细想想,这个方案是有问题的。首先,对不熟悉微信小程序原生开发的人很不友好,其次,wxcomponents 目录下的小程序组件,要使用的话,还需要在 pages.json 中进行配置,这意味着 uniapp 自定义组件中是不能直接使用小程序组件的,无法解决 组件中引入组件 的情况,所以,这个方案不行。难道 uniapp 对此就无解了吗?非也,仔细阅读上面的 uniapp 官方文档,可以找到这么一句:当需要在 vue 组件中使用小程序组件时,注意在 pages.json 的 globalStyle 中配置 usingComponents,而不是页面级配置

于是,在 pages.json 文件中做如下修改:

// pages.json

  "pages": [
    ...,
    
      "path": "pages/course/course",
      "style": 
        "navigationBarTitleText": "课程",
        // "mp-weixin": 
        //  "usingComponents": 
        //    "cloud-player": "plugin://cloudPlayer/player"
        //  
        // 
      
    
  ],
  "globalStyle": 
    // #ifdef MP-WEIXIN
    "usingComponents": 
      "cloud-player": "plugin://cloudPlayer/player"
    ,
    // #endif
    ...
  

可以发现,我把页面 style 下的 mp-weixin 配置给注释掉了,原因是在 globalStyle 下配置了 usingComponents 之后,就可以全局使用插件播放器,不管是页面或是组件中,都不需要再单独去配置 usingComponents,这样就可以在项目中随心所欲地使用播放器插件了,nice~

5、获取播放器 Context

当需要在业务逻辑中控制视频播放或暂停时,会用到 videoContext,如果使用默认的 <video> 标签,那么可以通过 uni.createVideoContext(videoId, this) 来获取视频播放器上下文,再通过上下文执行 play()pause() 等方法,即可控制视频播放,详细说明见 uniapp 官方文档:

createVideoContext:https://uniapp.dcloud.io/api/media/video-context.html#createvideocontext

但是,uni.createVideoContext(videoId, this) 对腾讯云点播插件无效,需改用 requirePlugin(pluginName).getContext(videoId) 来获取,例如:

const plugin = requirePlugin("cloudPlayer");
let player = plugin.getContext("myVideo");

该解决方案源自一篇社区帖子 《腾讯云点播 wx.createVideoContext(“myVideo”).pause()无法暂停》:https://developers.weixin.qq.com/community/develop/doc/0004eae9e6cd08e31d6d827e657800

三、封装

腾讯云点播插件 <cloud-player> 与默认的 <video> 标签在使用上差异不多,就以下几点:

  • <cloud-player> 使用时需要配置 appid 属性。
  • <cloud-player> 使用时需要配置 widthheight 属性。
  • <cloud-player> 视频源属性是 fileid<video> 视频源属性是 src
  • <cloud-player> id 属性是 playerid<video> id 属性是 id
  • <cloud-player> 上下文通过 requirePlugin(pluginName).getContext(videoId) 获取,<video> 上下文通过 uni.createVideoContext(videoId, this) 获取。

所以,为了代码可维护性,统一模板代码,我们可以自定义组件(名为 video-mix)对两者进行封装,用法上跟 <video> 标签差不多:

<video-mix
  videoId="videoPlayer"
  width="710rpx"
  height="400rpx"
  :fileid="curPlayEpisode.code"
  src="http://xxxx/video1.mp4"
  :poster="curPlayEpisode.cover_img"
  :controls="true"
  :autoplay="true"
  :show-progress="showProgress"
  @error="onVideoError"
  @controlstoggle="onVideoControlsToggle"
></video-mix>

注:我个人设想在微信小程序上使用腾讯云点播插件播放视频,在其他平台上还是继续使用 <video> 标签,于是设计为 fileidsrc 共存。

以下是 video-mix.vue 的完整代码:

// video-mix.vue
<template>
  <view class="video-mix-container">
    <!-- #ifdef MP-WEIXIN -->
    <cloud-player
      appid="GitLqr亲自打码"
      :id="videoId"
      :playerid="videoId"
      :width="width"
      :height="height"
      :fileid="fileid"
      :autoplay="autoplay"
      :loop="loop"
      :muted="muted"
      :controls="controls"
      :danmu-list="danmuList"
      :danmu-btn="danmuBtn"
      :enable-danmu="enableDanmu"
      :page-gesture="pageGesture"
      :show-progress="showProgress"
      :show-fullscreen-btn="showFullscreenBtn"
      :show-play-btn="showPlayBtn"
      :show-center-play-btn="showCenterPlayBtn"
      :enable-progress-gesture="enableProgressGesture"
      :object-fit="objectFit"
      :poster="poster"
      :show-mute-btn="showMuteBtn"
      :title="title"
      :play-btn-position="playBtnPosition"
      :enable-play-gesture="enablePlayGesture"
      :auto-pause-if-navigate="autoPauseIfNavigate"
      :auto-pause-if-open-native="autoPauseIfOpenNative"
      :vslide-gesture="vslideGesture"
      :vslide-gesture-in-fullscreen="vslideGestureInFullscreen"
      :ad-unit-id="adUnitId"
      :poster-for-crawler="posterForCrawler"
      @play="onPlay"
      @pause="onPause"
      @ended="onEnded"
      @timeupdate="onTimeUpdate"
      @fullscreenchange="onFullScreenChange"
      @waiting="onWaiting"
      @error="onError"
      @progress="onProgress"
      @loadedmetadata="onLoadedMetaData"
      @controlstoggle="onControlsToggle"
    >
    </cloud-player>
    <!-- #endif -->
    <!-- #ifndef MP-WEIXIN -->
    <video
      :id="videoId"
      :style=" width: width, height: height "
      :src="src"
      :autoplay="autoplay"
      :loop="loop"
      :muted="muted"
      :controls="controls"
      :danmu-list="danmuList"
      :danmu-btn="danmuBtn"
      :enable-danmu="enableDanmu"
      :page-gesture="pageGesture"
      :show-progress="showProgress"
      :show-fullscreen-btn="showFullscreenBtn"
      :show-play-btn="showPlayBtn"
      :show-center-play-btn="showCenterPlayBtn"
      :enable-progress-gesture="enableProgressGesture"
      :object-fit="objectFit"
      :poster="poster"
      :show-mute-btn="showMuteBtn"
      :title="title"
      :play-btn-position="playBtnPosition"
      :enable-play-gesture="enablePlayGesture"
      :auto-pause-if-navigate="autoPauseIfNavigate"
      :auto-pause-if-open-native="autoPauseIfOpenNative"
      :vslide-gesture="vslideGesture"
      :vslide-gesture-in-fullscreen="vslideGestureInFullscreen"
      :ad-unit-id="adUnitId"
      :poster-for-crawler="posterForCrawler"
      @play="onPlay"
      @pause="onPause"
      @ended="onEnded"
      @timeupdate="onTimeUpdate"
      @fullscreenchange="onFullScreenChange"
      @waiting="onWaiting"
      @error="onError"
      @progress="onProgress"
      @loadedmetadata="onLoadedMetaData"
      @controlstoggle="onControlsToggle"
    ></video>
    <!-- #endif -->
  </view>
</template>

<script>
export default 
  name: "video-mix",
  props: 
    videoId: 
      type: String,
      default: "",
    ,
    width: 
      type: String,
      default: "750rpx",
    ,
    height: 
      type: String,
      default: "420rpx",
    ,
    fileid: 
      type: String,
      default: "",
    ,
    src: 
      type: String,
      default: "",
    ,
    autoplay: 
      type: Boolean,
      default: false,
    ,
    loop: 
      type: Boolean,
      default: false,
    ,
    muted: 
      type: Boolean,
      default: false,
    ,
    initialTime: 
      type: Number,
      default: 0,
    ,
    controls: 
      type: Boolean,
      default: true,
    ,
    danmuList: 
      type: Array,
      default() 
        return [];
      ,
    ,
    danmuBtn: 
      type: Boolean,
      default: false,
    ,
    enableDanmu: 
      type: Boolean,
      default: false,
    ,
    pageGesture: 
      type: Boolean,
      default: false,
    ,
    // direction: 
    // 	type: Number,
    // 	default: undefined,
    // ,
    showProgress: 
      type: Boolean,
      default: true,
    ,
    showFullscreenBtn: 
      type: Boolean,
      default: true,
    ,
    showPlayBtn: 
      type: Boolean,
      default: true,
    ,
    showCenterPlayBtn: 
      type: Boolean,
      default: true,
    ,
    enableProgressGesture: 
      type: Boolean,
      default: true,
    ,
    objectFit: 
      type: String,
      default: "contain",
    ,
    poster: 
      type: String,
      default: "",
    ,
    showMuteBtn: 
      type: Boolean,
      default: false,
    ,
    title: 
      type: String,
      default: "",
    ,
    playBtnPosition: 
      type: String,
      default: "bottom",
    ,
    enablePlayGesture: 
      type: Boolean,
      default: false,
    ,
    autoPauseIfNavigate: 
      type: Boolean,
      default: true,
    ,
    autoPauseIfOpenNative: 
      type: Boolean,
      default: true,
    ,
    vslideGesture: 
      type: Boolean,
      default: false,
    ,
    vslideGestureInFullscreen: 
      type: Boolean,
      default: true,
    ,
    adUnitId: 
      type: String,
      default: "",
    ,
    posterForCrawler: 
      type: String,
      default: "",
    ,
  ,
  emits: [
    "play",
    "pause",
    "ended",
    "timeupdate",
    "fullscreenchange",
    "waiting",
    "error",
    "progress",
    "loadedmetadata",
    "controlstoggle",
  ],
  data() 
    return 
      isVideoPlaying: false,
      videoContext: null,
    ;
  ,
  methods: 
    onPlay(e) 
      this.isVideoPlaying = true;
      this.$emit("play", e);
    ,
    onPause(e) 
      this.isVideoPlaying = false;
      this.$emit("pause", e);
    ,
    onEnded(e) 
      this.isVideoPlaying = false;
      this.$emit("ended", e);
    ,
    onTimeUpdate(e) 
      this.$emit("timeupdate", e);
    ,
    onFullScreenChange(e) 
      this.$emit("fullscreenchange", e);
    ,
    onWaiting(e) 
      this.$emit("waiting", e);
    ,
    onError(e) 
      this.isVideoPlaying = false;
      this.$emit("error", e);
    ,
    onProgress(e) 
      this.$emit("progress", e);
    ,
    onLoadedMetaData(e) 
      this.$emit("loadedmetadata", e);
    ,
    onControlsToggle(e) 
      this.$emit("controlstoggle", e);
    ,
    isPlaying() 
      return this.isVideoPlaying;
    ,
    play() 
      this._log("play");
      this._fetchVideoContext().then(() => 
        this.videoContext.play();
      );
    ,
    pause() 
      this._log("pause");
      this._fetchVideoContext().then(() => 
        this.videoContext.pause();
      );
    ,
    stop() 
      this._log("stop");
      this._fetchVideoContext().then(() => 
        this.videoContext.stop();
      );
    ,
    _fetchVideoContext() 
      const operation = () =>
        new Promise((resolve, reject) => 
          if (!this.videoContext) 
            // #ifdef MP-WEIXIN
            // 这里的cloudPlayer是在json配置上引入的插件子组件名
            const plugin = requirePlugin("cloudPlayer");
            console.log('requirePlugin("cloudPlayer"): ', plugin);
            this.videoContext = plugin.getContext(this.videoId);
            console.log(
              `plugin.getContext($this.videoId): `,
              this.videoContext
            );
            // #endif
            // #ifndef MP-WEIXIN
            // this是在自定义组件下,当前组件实例的this,以操作组件内 video 组件(在自定义组件中药加上this,如果是普通页面即不需要加)
            this.videoContext = uni.createVideoContext(this.videoId, this);
            console.log(
              "uni.createVideoContext(this.videoId, this): ",
              this.videoContext
            );
            // #endif
          

          if (this.videoContext) 
            resolve(this.videoContext);
           else 
            reject("videoContext is empty");
          
        );
      return new Promise((resolve, reject) => 
        this.$utils
          .promiseRetry(operation, 500, 3)
          .then(resolve)
          .catch(reject);
      );
    ,
    _log(msg) 
      console.log(`video-mix : $msg`);
    ,
  ,
;
</script>

<style lang="scss" scoped>
.video-mix-container 

</style>

上述代码中用到的工具方法:

// utils.js
/* Promise 包装好的 setTimeout */
export const promiseWait = (ms) => new Promise((r) => setTimeout(r, ms));
/**
 * Promise 重试
 * @param Function operation 操作函数
 * @param Number delay 时间间隔
 * @param Number retries 重试次数
 */
export const promiseRetry = (operation, delay, retries) =>
  new Promise((resolve, reject) => 
    return operation()
      .then(resolve)
      .catch((reason) => 
        if (retries > 0) 
          return promiseWait(delay)
            .then(promiseRetry.bind(null, operation, delay, retries - 1))
            .then(resolve)
            .catch(reject);
        
        return reject(reason);
      );
  );

如果文章对您有所帮助, 请不吝点击关注一下我的微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不仅有android技术, 还有ios, Python等文章, 可能有你想要了解的技能知识点哦~

以上是关于uniapp - 腾讯云点播小程序插件的主要内容,如果未能解决你的问题,请参考以下文章

uniapp - 腾讯云点播小程序插件

uniapp - 腾讯云点播小程序插件

微信小程序(或uniapp)引入腾讯视频插件播放视频

uniapp开发微信小程序富文本编辑器(样式仿腾讯文档)

JavaWeb-SpringBoot_(上)腾讯点播服务之视频的上传

uni-app 代码