更新记录

0.0.1(2026-06-30)

首个可用版本,包含以下能力:

  • 提供 yyeva-player 播放容器组件
  • 提供 createYyevaPlayer(viewId) 播放器控制器
  • 支持普通视频播放
  • 支持动态素材播放
  • 支持文字动态元素替换
  • 支持图片动态元素替换
  • 支持播放事件监听、暂停、继续、停止和销毁
  • 支持 src 传本地路径与 http/https 网络地址

平台兼容性

uni-app x(5.13)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × 5.0 × × ×

其他

多语言 暗黑模式 宽屏模式
× ×

yyeva-player

yyeva-player 是一个基于 YYEVA-Android 封装的 uni-app x Android UTS 插件,用于在 native-view 中播放视频动效,并支持按素材占位符替换文字和图片。

插件简介

这是一个面向 uni-app x 的 Android 动效播放器插件,适合把设计侧产出的动效素材直接接入业务页面。你可以在保留视频动效表现的同时,按业务数据动态替换昵称、头像等内容,减少为每个用户单独导出视频素材的成本。

支持范围:

  • 当前仅支持 App-Android
  • 当前版本支持普通视频播放、动态文字替换、动态图片替换和事件监听

功能亮点

  • 支持 App-Android 原生播放,适合高频动效场景
  • 支持按素材 key 替换文字和图片资源
  • 提供 native-view 组件和播放器控制器两层能力
  • 支持播放、暂停、继续、停止、销毁和事件监听
  • 可直接用于 uni-app x 业务页面接入

接入收益

  • 业务侧只需要准备一份动效模板,不需要为每个用户重复出片
  • 前端可直接传入昵称、头像等数据,降低素材生产成本
  • 接入方式简单,适合快速嵌入现有页面
  • 插件 API 明确,便于后续二次封装成业务组件

效果截图

当前仓库里的 demo 已经升级为一个全屏交互式调试页,建议截图和展示文案围绕下面这些实际界面来准备:

  • 截图 1:全屏播放器默认界面,顶部显示 READY/WAITING 和当前模式
  • 截图 2:播放参数面板,展示普通模式 / 动态素材模式切换、播放参数、文字动态元素、图片动态元素
  • 截图 3:控制操作面板,展示播放、暂停、继续、停止、更新动态元素、清空动态元素
  • 截图 4:底部事件日志面板展开状态,展示最近 20 条播放事件

如果后续需要发布到插件市场,建议至少准备以下几类截图:

  • 一个完整页面效果图
  • 一个动态元素替换前后对比图
  • 一个控制台或页面参数配置图

当前 demo 页面结构:

  • 全屏 yyeva-player 播放容器
  • 顶部悬浮状态栏和操作按钮
  • 底部可展开的事件日志面板
  • 两个悬浮弹层:播放参数控制操作

适用场景

适合这些场景:

  • 直播间入场动画
  • 礼物动效播放
  • 带昵称、头像替换的祝福动效
  • 活动弹层动效

如果你只是播放普通视频,建议优先使用通用视频组件;如果你需要按素材 key 动态替换文字和图片,再使用本插件。

使用前提

接入前请先确认:

  • 项目为 uni-app x
  • 运行平台为 App-Android
  • HBuilderX 版本不低于 5.13
  • 已安装插件到 uni_modules/yyeva-player
  • 使用自定义基座或自定义打包验证,不能只依赖标准基座

说明:本插件依赖 Android 原生三方库。运行到标准基座时,原生依赖和配置不会生效,请使用自定义基座或正式打包后的安装包验证。

快速接入

1. 放置播放容器

插件提供了一个 easycom 组件:yyeva-player

<template>
  <view class="page-root">
    <yyeva-player viewId="gift-player" @ready="onPlayerReady"></yyeva-player>
  </view>
</template>

<script setup lang="uts">
function onPlayerReady(viewId: string): void {
  console.log('yyeva view ready:', viewId)
}
</script>

<style>
.page-root {
  display: flex;
  flex-direction: column;
  width: 750rpx;
  height: 750rpx;
}
</style>

说明:

  • viewId 是播放器实例和原生视图绑定的唯一标识
  • 同一个页面里不要重复使用相同的 viewId
  • 收到 ready 事件后再创建播放器并调用 play

2. 创建播放器实例

<script setup lang="uts">
import {
  createYyevaPlayer,
  type YyevaPlayer,
  type YyevaEvent,
  type YyevaEventCallback
} from '@/uni_modules/yyeva-player'

let player: YyevaPlayer | null = null
const viewId = 'gift-player'

function onPlayerReady(_: string): void {
  player = createYyevaPlayer(viewId)
  if (player == null) {
    return
  }

  const onStart: YyevaEventCallback = (event: YyevaEvent) => {
    console.log('start', event.src)
  }

  const onComplete: YyevaEventCallback = (event: YyevaEvent) => {
    console.log('complete', event.message)
  }

  player.on('onStart', onStart)
  player.on('onComplete', onComplete)
}

onUnmounted(() => {
  player?.destroy()
  player = null
})
</script>

3. 播放普通视频素材

播放普通视频时,通常不需要传入动态元素,直接使用普通视频素材即可。

<script setup lang="uts">
import { createYyevaPlayer, type YyevaPlayer } from '@/uni_modules/yyeva-player'

let player: YyevaPlayer | null = null

function playNormalVideo(): void {
  if (player == null) {
    return
  }

  player.play({
    src: '/static/yyeva/car_quanping.mp4',
    loop: false,
    mute: false,
    clearBeforePlay: true,
    stayOnLastFrame: false,
    scaleType: 'centerCrop'
  })
}
</script>

4. 播放动态素材并替换动态元素

播放带动态替换能力的素材时,传入 dynamicElements 即可。

<script setup lang="uts">
import {
  createYyevaPlayer,
  type YyevaDynamicElements,
  type YyevaPlayer
} from '@/uni_modules/yyeva-player'

let player: YyevaPlayer | null = null

function playDynamicEffect(): void {
  if (player == null) {
    return
  }

  const dynamicElements: YyevaDynamicElements = {
    texts: [{
      key: 'anchor_nick',
      text: 'uni-agent',
      color: '#FFFFFF',
      fontSize: 32,
      fontWeight: 'bold',
      textAlign: 'center'
    }],
    images: [{
      key: 'anchor_avatar1',
      src: '/static/logo.png',
      scaleType: 'centerCrop'
    }, {
      key: 'anchor_avatar2',
      src: '/static/logo.png',
      scaleType: 'centerCrop'
    }, {
      key: 'anchor_avatar3',
      src: '/static/logo.png',
      scaleType: 'centerCrop'
    }]
  }

  player.play({
    src: '/static/yyeva/effect.mp4',
    loop: false,
    mute: false,
    clearBeforePlay: true,
    stayOnLastFrame: false,
    scaleType: 'centerCrop',
    dynamicElements: dynamicElements
  })
}
</script>

5. 按当前 demo 自测

如果你要先跟着仓库里的 demo 跑通,建议按下面顺序验证:

  1. 打开 pages/yyeva/yyeva-demo.uvue
  2. 等待顶部状态从 WAITING 变成 READY
  3. 点击 播放参数,切到普通模式,使用 static/yyeva/car_quanping.mp4 验证全屏播放
  4. 再切到动态素材模式,使用 static/yyeva/effect.mp4 并传入动态元素,验证文字和图片替换
  5. 通过 控制操作 面板验证 播放 / 暂停 / 继续 / 停止 / 更新动态元素 / 清空动态元素
  6. 通过底部事件日志面板观察 onPreparedonStartonCompleteonError 等事件是否按预期触发

当前 demo 的可见交互入口包括:

  • 顶部悬浮状态与模式标签
  • 播放参数 按钮
  • 控制操作 按钮
  • 底部可展开事件日志面板

完整最小示例

下面这个页面可以直接作为接入模板。它是一个最小可运行示例,不等同于仓库里的完整交互式 demo 页面:

<template>
  <view class="page-root">
    <view class="player-box">
      <yyeva-player viewId="gift-player" @ready="onPlayerReady"></yyeva-player>
    </view>
    <button class="action-button" @tap="playEffect">播放动效</button>
    <button class="action-button" @tap="stopEffect">停止</button>
  </view>
</template>

<script setup lang="uts">
import {
  createYyevaPlayer,
  type YyevaEvent,
  type YyevaEventCallback,
  type YyevaPlayer
} from '@/uni_modules/yyeva-player'

const playerViewId = 'gift-player'
let player: YyevaPlayer | null = null

const onError: YyevaEventCallback = (event: YyevaEvent) => {
  console.log('yyeva error', event.code, event.message)
}

function onPlayerReady(_: string): void {
  player = createYyevaPlayer(playerViewId)
  player?.on('onError', onError)
}

function playEffect(): void {
  if (player == null) {
    return
  }

  player.play({
    src: '/static/yyeva/effect.mp4',
    loop: false,
    mute: false,
    dynamicElements: {
      texts: [{
        key: 'anchor_nick',
        text: 'uni-agent',
        color: '#FFFFFF',
        fontSize: 32,
        fontWeight: 'bold',
        textAlign: 'center'
      }],
      images: [{
        key: 'anchor_avatar1',
        src: '/static/logo.png',
        scaleType: 'centerCrop'
      }]
    }
  })
}

function stopEffect(): void {
  player?.stop()
}

onUnmounted(() => {
  player?.off('onError', onError)
  player?.destroy()
  player = null
})
</script>

<style>
.page-root {
  display: flex;
  flex-direction: column;
  padding: 24rpx;
}

.player-box {
  width: 702rpx;
  height: 702rpx;
}

.action-button {
  margin-top: 24rpx;
}
</style>

素材与路径说明

视频路径

推荐把示例视频放到项目 static 目录下。当前实现支持两类 src/static/... 这类本地资源路径,以及 http/https 网络地址(会先下载到缓存目录再播放)。当前 demo 里默认会用到这些资源:

  • static/yyeva/effect.mp4
  • static/yyeva/car_quanping.mp4

src/static/static/ 开头时,插件会自动转换为 Android 可访问的本地资源路径。

例如下面两种写法都可以:

  • /static/yyeva/effect.mp4
  • static/yyeva/effect.mp4

如果传入的是其它路径,插件会按原值透传给原生层。

如果传入的是 http/https 网络地址,Android 侧会先下载到应用缓存目录,再继续走现有本地文件播放链路。同一个 URL 在缓存文件仍然存在且内容有效时会直接复用,不会在每次播放时重复下载;如果同一时刻有多个播放请求命中同一个 URL,也只会实际下载一次。远程地址播放时,还可以通过 onDownloadingonCacheHit 事件区分当前是走网络下载还是直接命中缓存。

当前 demo 的默认验证路径:

  • 动态素材模式:/static/yyeva/effect.mp4
  • 普通模式:/static/yyeva/car_quanping.mp4

当前 demo 的模式区分方式:

  • 普通模式:使用普通视频素材,不传动态元素
  • 动态素材模式:使用支持替换的素材,并传入 dynamicElements

动态元素 key

动态替换是否成功,取决于你传入的 key 是否和素材文件中预留的占位符一致。

例如素材中预留了这些 key:

  • 文字:anchor_nick
  • 图片:anchor_avatar1
  • 图片:anchor_avatar2
  • 图片:anchor_avatar3

那你就必须传入同名 key 才能替换成功。

当前 demo 默认会按下面这组占位符进行验证:

  • 文本:anchor_nick
  • 图片:anchor_avatar1
  • 图片:anchor_avatar2
  • 图片:anchor_avatar3

默认动态模式下,demo 会使用一组文字资源和三张头像资源,方便直接验证 setDynamicElementsclearDynamicElements 和播放时传入 dynamicElements 的效果。

对外 API

createYyevaPlayer(viewId)

根据 viewId 创建播放器控制器。

返回值:YyevaPlayer | null

viewId 为空字符串时返回 null

YyevaPlayer.play(options)

开始播放。

YyevaPlayOptions 参数说明:

字段 类型 必填 说明
src string 视频路径,支持本地文件路径和 http/https 网络地址
loop boolean 是否循环播放
mute boolean 是否静音
scaleType 'centerCrop' | 'fitXY' | 'centerInside' 视频缩放模式
dynamicElements YyevaDynamicElements 动态文字和图片替换数据
clearBeforePlay boolean 播放前是否清理旧内容
stayOnLastFrame boolean 播放结束后是否停留在最后一帧
frameRate number 指定播放帧率
logEnabled boolean 是否开启原生日志

YyevaPlayer.pause()

暂停播放。

YyevaPlayer.resume()

继续播放。

YyevaPlayer.stop()

停止播放。

YyevaPlayer.destroy()

销毁播放器并释放关联资源。页面销毁前建议调用一次。

YyevaPlayer.setDynamicElements(elements)

更新动态元素。

适合先播放,再按业务状态切换昵称、头像等内容。

YyevaPlayer.clearDynamicElements()

清空已设置的动态元素。

YyevaPlayer.on(eventName, callback)

监听事件。

支持的事件名:

  • onDownloading
  • onCacheHit
  • onPrepared
  • onStart
  • onComplete
  • onStop
  • onPause
  • onResume
  • onError

事件对象 YyevaEvent 结构:

字段 类型 说明
name YyevaEventName 事件名
code number 事件码或错误码
message string 事件说明
viewId string 当前播放器绑定的 viewId
src string | null 当前播放源
extra UTSJSONObject | null 原生层附加数据

其中远程地址相关事件的 extra 常见字段如下:

  • onDownloading: remoteSrccachePath
  • onCacheHit: remoteSrccachePathfileSize

YyevaPlayer.off(eventName, callback?)

取消事件监听。

  • callback 时:移除指定回调
  • 不传 callback 时:移除该事件下的全部回调

错误码说明

当播放器触发 onError 时,可以结合 event.codeevent.message 快速定位问题。

错误码 含义 常见触发场景
30001 viewId 无效 调用 createYyevaPlayer(''),或传入空 viewId
30002 播放器视图未就绪 yyeva-player 还没触发 ready 就调用了 play / pause / resume / stop
30003 播放地址无效 play 时未传 src,或传入了空字符串
30004 动态元素参数无效 图片或文字替换参数不完整,key 缺失,或图片路径错误
30005 播放资源解析失败 视频文件不存在、远程下载失败,或传入路径无法被 Android 侧访问
30006 原生初始化失败 预留错误码,当前版本主要用于后续扩展原生初始化异常
30007 播放执行失败 素材格式不兼容、原生播放器内部执行失败、或播放器状态异常
30008 当前操作不被允许 例如未播放时调用 pause,未暂停时调用 resume

常见排查顺序:

  1. 先看 viewId 是否和组件上的 viewId 完全一致
  2. 再看是否已经收到 ready 事件
  3. 再检查 src 和动态图片路径是否真实存在
  4. 最后检查动态元素 key 是否和素材预埋占位符一致

类型说明

YyevaDynamicElements

type YyevaDynamicElements = {
  images?: Array<YyevaImageResource> | null,
  texts?: Array<YyevaTextResource> | null
}

YyevaImageResource

type YyevaImageResource = {
  key: string,
  src: string,
  scaleType?: 'centerCrop' | 'fitXY' | 'centerInside' | null
}

YyevaTextResource

type YyevaTextResource = {
  key: string,
  text: string,
  color?: string | null,
  fontSize?: number | null,
  fontWeight?: 'normal' | 'bold' | null,
  textAlign?: 'left' | 'center' | 'right' | null
}

推荐接入顺序

建议按下面顺序联调:

  1. 先用普通视频素材验证容器显示和播放链路,不传动态元素
  2. 再切到带动态替换能力的素材,传入 dynamicElements
  3. 最后再逐个增加文字、图片动态替换

这样更容易快速定位问题到底出在视图绑定、素材本身,还是动态元素 key 不匹配。

常见问题

1. 事件触发了,但画面黑屏

优先检查:

  • 是否使用了自定义基座
  • 是否确实运行在 App-Android
  • 容器是否有明确宽高
  • viewId 是否和 createYyevaPlayer(viewId) 一致

2. 动态元素没有替换成功

优先检查:

  • 传入的 key 是否和素材中占位符完全一致
  • 图片路径是否真实存在
  • 当前播放素材是否支持动态替换

3. 普通视频播放失败

优先检查:

  • src 是否指向有效 MP4 文件
  • 当前是否误传了与普通视频不匹配的动态元素

4. 页面销毁后还在占用资源

请在页面卸载时调用:

player?.destroy()
player = null

已知限制

当前版本有这些限制,接入前建议先确认:

  • 仅支持 App-Android,暂不支持 iOSH5 和各类小程序平台
  • 依赖 Android 原生三方库,必须使用自定义基座或正式打包验证
  • 动态元素替换依赖素材中预埋的 key,不能脱离素材结构单独生效
  • 当前主要能力聚焦文字和图片替换,尚未扩展更多自定义动态元素类型
  • 远程 URL 首版实现采用“先下载后播放”模式,不是边下边播
  • 播放效果最终受素材编码、分辨率、占位符设计和设备性能影响

更新日志

0.0.1

首个可用版本,包含以下能力:

  • 提供 yyeva-player 播放容器组件
  • 提供 createYyevaPlayer(viewId) 播放器控制器
  • 支持普通视频播放
  • 支持动态素材播放
  • 支持文字动态元素替换
  • 支持图片动态元素替换
  • 支持播放事件监听、暂停、继续、停止和销毁
  • 支持 src 传本地路径与 http/https 网络地址

示例页面

项目里已经提供了可直接参考的完整 demo:

  • pages/yyeva/yyeva-demo.uvue

这个页面当前不是简单的播放示例,而是一个用于联调播放器能力的全屏调试页,包含:

  • 普通模式 / 动态素材模式的预设切换
  • 播放参数运行时编辑
  • 文字动态元素与图片动态元素的增删改
  • setDynamicElements / clearDynamicElements 页面级操作入口
  • 播放生命周期事件日志观察

如果你要快速验证接入是否成功,建议先跑通这个页面,再迁移到你自己的业务页面。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

插件本身不主动申请额外系统权限,首版支持 Android 端普通 MP4 播放、YYEVA 动效播放,以及文字、图片动态资源替换

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。