更新记录

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. 通过底部事件日志面板观察 onPrepared、onStart、onComplete、onError 等事件是否按预期触发

当前 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,也只会实际下载一次。远程地址播放时,还可以通过 onDownloading 和 onCacheHit 事件区分当前是走网络下载还是直接命中缓存。

当前 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 会使用一组文字资源和三张头像资源,方便直接验证 setDynamicElements、clearDynamicElements 和播放时传入 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: remoteSrc、cachePath
  • onCacheHit: remoteSrc、cachePath、fileSize

YyevaPlayer.off(eventName, callback?)

取消事件监听。

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

错误码说明

当播放器触发 onError 时,可以结合 event.code 和 event.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,暂不支持 iOS、H5 和各类小程序平台
  • 依赖 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. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。