更新记录
1.1.2(2026-09-23)
维护位版本:1.1.1 已于同日上架,本版暂无代码改动(1.1.1 之后的工作为文档一致性维护与 构建可复现性修复,不影响运行行为)。后续改动将追加到本条。
1.1.1(2026-09-18)
本版重点:iOS 打包彻底免切换 + 模拟器不再偶发崩溃。
模拟器统一走软解(消除苹果 VT/CoreVideo 偶发崩溃)
模拟器上 VT 软解每帧都要经过 CoreVideo 像素池,该池在模拟器下存在已知缺陷
(x86_64/Rosetta 必崩、arm64 偶发崩,栈为 CVPixelBuffer::setDefaultAttachments)。
本版把所有模拟器统一路由到自研 AVAssetReader 顺序软解解码器(独立分配路径,绕开该池),
真机不受影响(仍是原生 VT 硬解)。实测 arm64 与 x86_64 模拟器连续多轮播放均稳定、画面与声音正常。
iOS 依赖形态:单一静态 xcframework(打包自动选架构,无需切换)
iOS 端由"真机/模拟器分目录 + 手动切切片"改为单一 QGVAPlayer.xcframework
(内含 ios-arm64 与 ios-arm64_x86_64-simulator 两个变体,静态库):
真机与模拟器打包均由 Xcode 自动选切片 —— 此前选「iOS Appstore(模拟器)」会报
Undefined symbols ... _OBJC_CLASS_$_QGVAPWrapView,现在两种打包类型都直接通过。
静态库无需嵌入(HBuilderX 对 .xcframework 不做 embed,动态库形态会 dyld 失败),
且其 UTS 插件模板自带 -ObjC,静态库中的分类不会被剥离。
1.1.0(2026-09-18)
本版重点:iOS 模拟器从"不可用"变为"可用",首播更快,鸿蒙融合头像修复。
iOS 模拟器现在可以播放动画(此前官方源码层面不支持)
腾讯 VAP 源码里原本有两道"模拟器不支持":p_playHWDMP4 的禁播守卫(按 hw.machine
为 x86_64/i386 时直接返回)、以及 Metal 渲染链在 #if TARGET_OS_SIMULATOR 下被整块挖空。
本版按架构编译期隔离地全部解决(真机零影响):
- 取消 Metal 挖空,模拟器与真机共用同一 Metal 链路(含 vapx 融合合成);
- 渲染器增加 IOSurface 兜底拷贝(模拟器软解输出无 IOSurface 背板,
CVMetalTextureCache会失败); - 移除禁播守卫;
- x86_64(Rosetta)另拆四处闸门:
AVAudioPlayer初始化间歇挂起(改为后台异步,避免阻塞)、kCVPixelBufferMetalCompatibilityKey在 x86_64 有害(撤销)、 CoreVideo 像素池在 Rosetta 下损坏(该架构改用自研AVAssetReader顺序软解解码器绕开)。
验收(2026-09-18):iPhone 真机 total=240/12.07s(20fps 满帧)+ total=80;
arm64 模拟器首播 0.5s、x86_64 模拟器首播 1.0s,均为满帧且有声、融合画面正常。
首播更快(预取 + 管线预热)
- 新增
preloadVap(src):素材预取,页面创建即下载到与播放同一份缓存(幂等、失败静默), 消除首播时"点了要等下载"的 1-2 秒;其它平台为空操作,API 一致。 - 框架侧 Metal 管线状态预热:把原本"首个 draw 才编译"的管线编译提前到视图初始化, 消除首播头几帧的编译卡顿。
HarmonyOS 融合头像修复
本地静态图(/static/user.png)在鸿蒙上不显示(动画正常、无报错)。两个机制坑:
① autoplay 由 builder.ets 直接播放,不经过 UTS 的 play();② XComponent 的 ctx
不是完整 Context(resourceDir 为 undefined),ArkTS 侧无法自行拼路径。
现改为在 UTS 构造函数 / setMixData 里统一用 UTSHarmony.getResourcePath() 解析真实路径,
两条播放路径共用同一份 params.mixJson。
其它
- 修 SW 软解解码器的一个潜在死锁:显示循环抖动导致的非连续帧请求原本被静默丢弃 (缓冲永不回填 → 播放中途冻住),改为"领先则追赶、落后则忽略"。
- 平台声明:传统 uni-app 段全部标不支持(同 1.0.2 口径,本版起随版本号一并生效)。
平台兼容性
uni-app(3.8.4)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
uni-app x(4.0)
| Chrome | Chrome插件版本 | Safari | Safari插件版本 | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 | 微信小程序 | 微信小程序插件版本 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 1.0.0 | √ | 1.0.0 | 5.0 | 1.0.0 | 12 | 1.0.0 | √ | 1.0.0 | √ | 1.0.0 |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | × | √ |
axen-vap-x 跨端 VAP 视频动画特效组件
基于 Tencent VAP(MIT)、OHOS-VAP(Apache-2.0)与自研微信引擎封装的 uni-app x UTS 组件,五端一套代码:Android / iOS / HarmonyOS(原生渲染)+ H5 + 微信小程序。
用于直播间进房动效、礼物特效、活动弹窗等需要透明度与融合元素的场景。
✨ 特性
- 🖥️ 五端一套组件:同一份 UTS 组件 —— App 三端原生渲染(真机硬解,iOS 模拟器走自研软解;Metal / OpenGL),H5 用 vap-web(WebGL),微信小程序用自研 VideoDecoder + Canvas2D 引擎
- 👤 融合元素:动画内预留 tag,运行时注入头像 / 昵称 / 图片 / 文字(VAP 招牌能力)
- 🔊 音效支持(五端均出声):音效 / 背景音内嵌在 VAP mp4 里,播放即有声、音画天然同步(素材无需单独挂音频文件)。
各端出声路径:Android/iOS 走原生解码 + 系统音频会话(iOS 含静音开关下的会话处理,避免"扬声器没声、插耳机才有声");
微信小程序为
VideoDecoder+MediaAudioPlayer管线级音画同步;H5 由 web 引擎的 video 元素出声; HarmonyOS 由 OHOS-VAP 原生播放器的InitAudioPlayer出声。 ⚠️ 与"出声"是两件事:mute属性在各端支持度不同 —— 鸿蒙侧@ohos/vap无 mute API,mute属性被静默忽略(不生效、也不报错;只有直接调播放器的setMute()才会收到code=5), H5 仅构造期生效。详见下方平台能力矩阵。 - ⚡ 网络地址:直接传 http(s),组件内部自动下载缓存后播放
- 🎛️ 完整事件:
started / frame / finish / error / click,帧序号与总帧数五端语义已对齐 - 📐 缩放与循环:
scaleType(aspectFit / aspectFill / scaleToFill)、loop、mute - 🪶 低内存:视频硬解 + 只缓存一帧,适配「同屏多礼物、大粒子」场景
为什么鸿蒙只在 uni-app x 里支持(机制说明)
本插件的 App 三端统一走「原生视图」:组件里放 <native-view>,UTS 侧通过
element.bindHarmonyWrappedBuilder(wrapBuilder(buildVap)) 把 ArkTS @Builder 构造的原生视图
(鸿蒙为 XComponent + OHOS-VAP 的 libvap.har;Android 为 animplayer-release.aar)挂到该节点上,
尺寸与位置由 native-view 在页面布局中的盒子决定(因此内联小尺寸同样可用,不只是全屏覆盖层)。
关键点:这条路径只在 uni-app x 中存在 ——
- 传统 uni-app 的「兼容模式」UTS 组件:官方明确不支持鸿蒙,且依赖 nvue(已不再维护);
- renderjs:只支持
app-vue与 web(依赖 webview 视图层),鸿蒙 Next 真机上 renderjs 内部函数不会触发; - 「标准模式」组件:仅限 uni-app x。
⇒ 所以"传统 uni-app 项目 + 鸿蒙 + 原生组件"在官方机制上没有路径,鸿蒙能力请使用本插件(uni-app x)。 (另注:市场上部分传统 uni-app 插件在平台表里标注"鸿蒙 √",按上述机制其无法在传统鸿蒙工程中提供 原生组件能力,选购时建议自行验证。)
⚠️ 本插件仅适用于 uni-app x 项目(交付物是
axen-vap-x.uvue,传统 uni-app 无法使用 vue 之外的后缀)。 传统 uni-app(vue) 项目请使用配套免费组件axen-vap—— H5 + 微信小程序, Vue2 / Vue3 工程均已真机验证通过(2026-09-16)。 平台声明已按此如实标注(1.0.2 起,此前误标了传统 uni-app 支持)。 支付宝等其余小程序平台因无逐帧视频解码 API 不支持(详见PLATFORMS.md的 11 平台矩阵)。
📦 安装
插件市场搜索 axen-vap-x,或直接将 uni_modules/axen-vap-x 导入项目。
- 需 HBuilderX 4.61+ 且为 uni-app x 工程
- 五端均已实测跑通(App 三端真机 / 模拟器、H5 浏览器、微信真机),验证证据见
PLATFORMS.md,排查记录见TROUBLESHOOTING.md
原生二进制(AAR / Framework / HAR)的集成与编译步骤见
uni-vap-x-demo/README.md。 使用前请先读 各端使用前提 —— 它会直接影响能否直接跑通。
🚀 快速开始
<template>
<view>
<axen-vap-x
ref="vap"
:src="'/static/demo.mp4'"
:loop="1"
:autoplay="true"
:scaleType="'aspectFit'"
:mixData="mixList"
@started="onStarted"
@frame="onFrame"
@finish="onFinish"
@error="onError"
@click="onClick"
/>
</view>
</template>
<script setup lang="uts">
// 类型:H5/小程序端本地声明(加密入口在运行期不提供类型导出),App 三端从插件入口引
// #ifdef WEB || MP-WEIXIN
type VapMixData = { tag: string; imgUri?: string; txt?: string; color?: string; fontSize?: number; textAlign?: string; fontWeight?: string }
// #endif
// #ifdef APP-ANDROID || APP-IOS || APP-HARMONY
import { VapMixData } from "@/uni_modules/axen-vap-x"
// #endif
const mixList: Array<VapMixData> = [
{ tag: "[imgUser]", imgUri: "https://.../avatar.png" }, // 融合头像
{ tag: "[textUser]", txt: "星河Momo", color: "#FFF1AE", fontSize: 28, textAlign: "center", fontWeight: "bold" }
]
function onStarted() { console.log("started") }
// ⚠️ 事件回调形参必须写 UTSJSONObject(不能写 any,也不能省略类型):
// - 写 `e: any` → UTS 的 Any 没有动态属性,`e.totalFrameCount` 报「找不到名称」
// - 不写类型 → 报「Cannot infer type for this parameter」
// 取值用 getString / getNumber / getBoolean。
function onFrame(e: UTSJSONObject) { console.log("frame", e.getNumber("index")) }
function onFinish(e: UTSJSONObject) { console.log("finish", e.getNumber("totalFrameCount")) }
function onError(e: UTSJSONObject) { console.log("error", e.getString("message")) }
function onClick(e: UTSJSONObject) { console.log("click", e.getString("tag")) }
</script>
📖 API 文档
属性
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
src |
string | — | mp4 地址:本地路径或 http(s) 网络地址(网络地址自动下载并缓存) |
mixData |
Array\<VapMixData> | [] |
融合元素,见下 |
loop |
number | 1 | 循环播放次数:1 播一次;2 播两次;<=0 无限循环 |
autoplay |
boolean | false | 挂载后自动播放 |
mute |
boolean | false | 静音(Android / iOS / H5 / 微信支持;HarmonyOS 上该属性不生效,且不会因此上报事件) |
scaleType |
string | aspectFit |
aspectFit / aspectFill / scaleToFill |
config |
any | null | vapc 配置。App 三端可留空(原生引擎自己解析 mp4 的 vapc box);H5 留空时组件会自动 fetch 素材并提取;微信端建议显式传入 —— 留空时自研引擎按「RGB 在上 / alpha 在下」的常见拼版假定渲染,遇到别的拼版会裁剪错误 |
bypassProcess |
boolean | false | 仅微信小程序:跳过素材预处理(包内素材可用) |
模块级函数(从插件入口 import,不是组件 ref 上的方法)
| 函数 | 说明 |
|---|---|
preloadVap(src) |
素材预取(推荐调用):在页面初始化阶段就把素材下载到与播放同一份缓存,消除首播时"点了要等下载"的 1-2 秒。幂等、失败静默。iOS 已实现;其它平台为空操作(API 保持一致,便于跨端书写)。用法:import { preloadVap } from "@/uni_modules/axen-vap-x" 后直接调用(不是 vapRef.value?.preloadVap()) |
事件
| 事件 | 参数 | 触发 |
|---|---|---|
ready |
— | 组件侧播放器封装对象已创建、事件回调已接好(native-view / canvas 就绪)。App 三端此时调 play() 最稳妥;鸿蒙原生播放器另有初始化时序,未就绪时 play() 会上报 code=5 |
started |
— | 播放开始 |
frame |
{ index } |
每渲染一帧。index 五端统一 1 基(第 1 帧为 1,1.1.1 起对齐;1.1.0 时 iOS 与微信曾为 0 基) |
finish |
{ totalFrameCount } |
播放完成,totalFrameCount = 总帧数(不是「最后一帧序号」) |
error |
{ code, message } |
失败上报,五端统一错误码(见下表) |
click |
{ tag } |
点击到融合元素(iOS / Android / HarmonyOS 支持;H5 / 微信暂不支持,见「平台能力矩阵」) |
回调形参类型固定为
UTSJSONObject(见上例),用getNumber("totalFrameCount")/getString("tag")取值。
@error 错误码(五端统一,业务侧按此分支)
| code | 含义 | 触发场景 |
|---|---|---|
1 |
引擎不可用 | 小程序基础库不支持 createVideoDecoder;H5 引擎脚本加载/初始化失败 |
2 |
素材下载失败 | 网络 src 或网络融合图片下载/落盘失败 |
3 |
解码或播放失败 | 解码器启动失败、播放中途报错、原生引擎抛错 |
4 |
参数/素材非法 | src 为空或非法;H5 素材里找不到 vapc 配置 |
5 |
动作不被支持 | Android 的 pause/resume、鸿蒙的 setMute(直接调播放器时)与"播放器未就绪时 play()"、微信在已结束时 resume、H5 运行期 setMixData/setLoop/setMute |
定义在
utssdk/interface.uts的VapErrorCode。能力缺失一律报 5,不再静默空实现 —— 例如在 Android 上调pause()会收到code=5,请据此把暂停按钮置灰或改走stop()。
totalFrameCount的来源按平台:iOS 为原生真实总帧数;Android / 微信 / H5 / 鸿蒙为引擎帧计数。 实测校准:demo.mp4 → 80 帧、vapx.mp4 → 240 帧,与 mp4stsz.sample_count/ vapcinfo.f一致。 做进度条请统一用index / totalFrameCount,不要假设index从 0 开始。
方法(ref 调用)
组件已 defineExpose 以下方法(示例为 uvue / App 端写法):
<axen-vap-x ref="vapRef" :src="src" />
import { AxenVapXComponentPublicInstance } from "@/uni_modules/axen-vap-x/components/axen-vap-x/axen-vap-x.uvue"
const vapRef = ref<UniVapXComponentPublicInstance | null>(null)
vapRef.value?.play() // 播放 / 重播
vapRef.value?.stop() // 停止
vapRef.value?.pause() // 暂停:iOS / HarmonyOS 支持;H5 支持;微信为"伪暂停"(时间轴继续走,resume 后续播);
// **Android 不支持**(会上报 code=5,animplayer 无暂停能力)
vapRef.value?.resume() // 恢复:同上;微信在解码器已结束时调用会收到 code=5,需重新 play()
vapRef.value?.setMixData(arr) // 动态更新融合元素后重播
vapRef.value?.clear() // 清空画布(ref 上暴露的名字是 clear(),内部转调 player.clearCanvas();组件卸载时已自动调用)
组件在
onUnmounted里会先clearCanvas()再destroy(),所以「切场景 = 换 props +v-if重挂载」这种声明式用法无需手动调方法(演示工程即如此)。
VapMixData 融合元素
type VapMixData = {
tag: string // 素材内占位 tag,如 [imgUser]
imgUri?: string // 图片地址(本地或网络,用于头像/图片填充)
txt?: string // 文字内容
color?: string // 文字颜色 #RRGGBB
fontSize?: number // 字号
textAlign?: string // left / center / right
fontWeight?: string// normal / bold
}
tag必须与素材里的占位符完全一致(含方括号):素材里是[imgUser],代码里也要写[imgUser]。 文字对齐与颜色以素材 vapc 为准(与官方 Android 行为一致:对齐固定居中,颜色取 vapc 记录值)。
调试日志
插件的过程日志默认 静默,不会往控制台刷屏。排查时显式打开:
import { setVapDebug } from "@/uni_modules/axen-vap-x"
setVapDebug(true) // 打开后输出 [vap-x] 前缀的过程日志
错误日志([vap-x] 的 error 级)始终输出,不受该开关影响。
🎨 素材制作
VAP 素材 = 普通 mp4 + 内嵌 vapc 配置(JSON)。使用官方 VapTool 生成:
- PS / AE 导出带 alpha 的视频帧
- 在 VapTool 中标记融合元素(矩形区域 + tag),导出
xxx.mp4 - 将 mp4 放入应用
static或服务器
imgUri可以写网络地址,插件会自动处理:Android 底层(腾讯 VAP 的animplayerAAR)只接受本地文件路径 (其decodeBitmap是File(path).exists() ? decodeFile(path) : null,且取不到图时不会回调, 会让整段播放卡在等资源上)。因此本插件在 Android 端播放前会把所有网络imgUri先下载成本地文件; 万一下载失败,该融合元素会被自动剔除 —— 宁可少一个头像,也不会让整段动效放不出来。
📁 插件目录约定(重要)
uni_modules/axen-vap-x/
├── components/axen-vap-x/axen-vap-x.uvue # 组件本体
├── utssdk/
│ ├── interface.uts # 公共类型(VapPlayer / VapMixData / ...)
│ ├── shared.uts # 参数解析 + 日志开关(各端共用)
│ ├── app-android/ app-ios/ app-harmony/ # 原生三端
│ ├── mp-weixin/ # 微信小程序自研引擎
│ └── web/ # H5(vap-web)
└── static/
├── vap.min.js # H5 引擎(官方 vap-web 产物)
└── vap-pixel.wasm # 微信端像素计算引擎
两条必须遵守的约定:
-
UTS 插件不要建根
index.uts—— 入口由编译器按平台解析到utssdk/<平台>/index.uts,interface.uts放utssdk/下(与官方uts-api模板一致)。 若在根index.uts里用条件编译手动 re-export 各平台文件,JS 打包阶段会把 iOS 源码当普通模块解析而报Rollup failed to resolve import "UIKit"。 业务侧照官方文档引用即可:import { VapPlayer } from "@/uni_modules/axen-vap-x"—— ⚠️ 但类型(VapMixData/VapScaleType/VapOptions/VapEvents)要按平台分流: H5 / 微信小程序端不能从插件入口 import 类型(付费插件发布后入口是加密二进制,浏览器只能按 运行期导出解析具名 import,而纯类型在运行期没有任何绑定)→ H5 端会直接抛The requested module ... does not provide an export named 'VapScaleType',编译期零报错。 正确写法(本项目组件与示例页就是这么写的):// H5 / 小程序:本地声明(JS 端类型是结构化匹配,不存在"两个类"的问题) // #ifdef WEB || MP-WEIXIN type VapMixData = { tag: string; imgUri?: string; txt?: string; color?: string; fontSize?: number; textAlign?: string; fontWeight?: string } // #endif // App 三端:从入口引(必须与插件共用同一份声明,否则触发 compiler-known-issues error17) // #ifdef APP-ANDROID || APP-IOS || APP-HARMONY import { VapMixData } from "@/uni_modules/axen-vap-x" // #endif两条已验证的死路(别再试):
import type { ... } from "@/uni_modules/axen-vap-x"(编译产物原样保留、 web 管线不认);从"@/uni_modules/axen-vap-x/utssdk/interface.uts"引(解析不了,TS2307)。 如果只是用:mixData传数组、不做类型标注,则不涉及这个问题。 - 二进制与 js 资源必须放
static/——static/会被原样拷进产物,而utssdk/只编译.uts→.js, 放utssdk/下的.wasm/.js/.min.js不会进产物(会导致运行时 404,本插件踩过这个坑)。
⚙️ 各端使用前提(重要)
| 平台 | 前提 |
|---|---|
| H5 | 图片素材(融合头像等)必须可跨域 —— 浏览器对 Image 做 CORS 校验,图片服务器不返回 Access-Control-Allow-Origin 时头像不显示,且是静默失败:动画照常播完、只有控制台报 blocked by CORS policy(2026-09-15 实测)。实测对照:gcore.jsdelivr.net 带 ACAO: *、q1.qlogo.cn 不带。解决:同源图片或带 CORS 的 CDN(示例现已改用同源 /static/user.png)。App / 小程序端为原生下载,不受此限制。跨域加载 mp4 时同理 |
| HarmonyOS | 依赖 utssdk/app-harmony/libs/libvap.har。若从仓库拉取后缺失,需先执行 bash scripts/build-harmony-har.sh(从 vendor/ohos-tpc/vap 生成)。另:HBuilderX CLI 不支持鸿蒙发布,报「运行包制作失败」时可用 hdc install 直接安装产出的 hap |
| 微信小程序 | 像素计算依赖随插件分发的 static/vap-pixel.wasm;不可用时自动回退纯 JS 路径(较慢,功能一致);动画只能在真机运行(真机预览 / 真机调试验证播放与音效),开发者工具仅用于页面布局与「不校验合法域名」等配置检查 |
| iOS | 真机或模拟器均可(Apple Silicon 原生 arm64 / x86_64 Rosetta 都已验证),详见下节 |
🔧 平台特定说明
iOS
- iOS 模拟器 ✅ 可播放动画(2026-09-18 起;此前版本的本节曾写"模拟器无法播放",该结论已推翻):
腾讯源码原先有两道"模拟器不支持"——
p_playHWDMP4的禁播守卫(hw.machine== x86_64/i386 时 直接not allowed in Simulator!返回)+ Metal 渲染链在#if TARGET_OS_SIMULATOR下被整块挖空。 本插件已按 arch 编译期隔离地全部解决(真机零影响):- 取消 Metal 挖空,模拟器与真机共用同一 Metal 链;
- 渲染器加 IOSurface 兜底拷贝(模拟器软解输出无 IOSurface 背板,
CVMetalTextureCache会失败); - 移除禁播守卫;
- 模拟器统一改用自研
AVAssetReader顺序软解解码器:模拟器上 VT 软解每帧都要经过 CoreVideo 像素池,该池在模拟器下存在已知缺陷(x86_64/Rosetta 必崩、arm64 偶发崩, 栈为CVPixelBuffer::setDefaultAttachments)。软解走独立分配路径、彻底绕开该池。 真机不受影响(仍是原生 VT 硬解)。 - 另有四处闸门(与上一条"模拟器统一软解"分开计):① 禁播守卫(撤);②
AVAudioPlayer初始化间歇挂起 → 后台异步;③kCVPixelBufferMetalCompatibilityKey有害 → 撤销(保持腾讯原版解码属性); ④ 模拟器 CoreVideo 像素池缺陷 → 由软解路径绕开。 实测(2026-09-18):arm64 与 x86_64 模拟器均total=240(12s,20fps 满帧)+total=80, 连续多轮稳定、有画面有声音、融合画面正常。 ⇒ 使用建议:模拟器可直接验证动画/融合/事件;真机仍是发布前的推荐验收口径(性能与音效更真实)。
- iOS 真机打包前置(付费款必须):本插件含原生 framework,必须用自定义基座,
云打包/自定义基座在 iOS 上要求手动创建的描述文件(Xcode 托管描述文件会被 DCloud 云打包拒绝;
免费个人开发者账号也拿不到 App Store 类型的描述文件)。前置条件与步骤见仓库
SHIPPING.mdB·补 节。 (免费版 iOS 走 WebGL 软路径,不需要自定义基座 —— 这也是拿它当试用入口的原因之一。) - iOS framework 为单一
.xcframework(静态库双变体),打包时自动选切片、无需切换(2026-09-18 起):utssdk/app-ios/Frameworks/QGVAPlayer.xcframework内含ios-arm64(真机)与ios-arm64_x86_64-simulator(模拟器)两个变体,Xcode/HBuilderX 会按打包目标自动选择。- 为什么是静态库:动态库形态下真机 arm64 与模拟器 arm64 同架构不同平台无法合并为单个
.framework;而 HBuilderX 的插件 framework 处理只对.framework判定"是否动态库",.xcframework一律embed=false⇒ 动态库 xcframework 运行期会 dyld 失败。静态库不需要 embed, 因此 xcframework 可用(HBuilderX 的 UTS 插件模板自带-ObjC,静态库里的分类不会被剥离)。 - metallib 处理:静态 framework 的资源不会被复制进 App,故按平台把
default.metallib编译成字节 内嵌进二进制(构建脚本生成QGVAPEmbeddedMetalLib.h),加载器优先读 bundle 资源、其次落临时文件加载。 - 对比:旧版是"真机/模拟器分目录 + 手动切切片",打模拟器包会报
Undefined symbols for architecture x86_64: _OBJC_CLASS_$_QGVAPWrapView。现已不再需要任何切换。 - 如需自行从源码重建:
bash scripts/build-ios-framework.sh(会重新生成 xcframework; 切片备份放在仓库.ios-build/xcf-slices/{device,simulator}/,不再放插件目录内, 避免被构建工具当成"插件依赖框架"误捡)。
- 为什么是静态库:动态库形态下真机 arm64 与模拟器 arm64 同架构不同平台无法合并为单个
- 本地校验 UTS 是否可编译:
bash scripts/check-ios-uts.sh(用 HBuilderX 自带的 UTS→Swift 编译器生成 Swift,再对真实 framework 做swiftc -typecheck,无需打开 HBuilderX) - 网络素材(
src为 http(s))会先下载到NSTemporaryDirectory()下同名文件再播放(同名复用即一级缓存); 融合图片通过loadVapImageWithURL异步下载,本地绝对路径则直接读取 scaleType三档均已支持(通过contentMode:aspectFit→aspectFit、aspectFill→aspectFill、scaleToFill→scaleToFill); 但只认构造时的取值,运行期改scaleType需v-if重挂载(各端一致)- 音频会话(iOS 特有行为):播放前若当前会话是
ambient/soloAmbient(系统默认), 插件会把它切到playback并setActive(true)—— 否则音效遵循机身静音开关,表现为 "扬声器没声、插耳机才有声"。mute=true时不会改宿主会话; 宿主自己配置过会话(如直播间playAndRecord收麦)时插件保持不动。
Android
- 依赖
utssdk/app-android/libs/animplayer-release.aar(腾讯 VAP 官方 + 本插件的VapBridge桥接类) - 融合图片只接受本地路径,网络地址由插件预下载(见「素材制作」一节)
微信小程序
- 只能在真机运行(重要):动画的解码与音画同步管线以真机为准 —— 请用真机预览 / 真机调试验证播放、融合与音效; 开发者工具无法完整播放动画,仅可用于页面布局与「不校验合法域名」等配置检查
⚖️ 平台能力矩阵(含不支持项)
| 能力 | Android | iOS | HarmonyOS | H5 | 微信小程序 |
|---|---|---|---|---|---|
| 播放 / 停止 / 重播 | ✅ | ✅ | ✅ | ✅ | ✅ |
pause / resume |
❌ 上报 code=5 |
✅ | ✅(resume 为重新 play) | ✅ | ⚠️ 伪暂停(时间轴继续走) |
| 内嵌音轨出声(播放即有音效) | ✅ | ✅ | ✅(原生 InitAudioPlayer) |
✅(web video 元素) | ✅(MediaAudioPlayer) |
mute 属性 |
✅ | ✅ | ❌ 不生效且不报错(@ohos/vap 无 mute API;只有直接调 setMute() 才上报 code=5) |
✅(构造期) | ✅ |
scaleType |
✅ | ✅ | ✅ | ✅ | ✅(仅渲染分支) |
@click |
✅ | ✅ | ✅ | ❌ | ❌ |
@frame 帧序号基准 |
1 基(五端统一,1.1.1 起) | ← | ← | ← | ← |
运行期 setMixData/setLoop/setMute |
✅ | ⚠️ 下次播放生效 | setMixData/setLoop ✅;setMute ❌ 上报 code=5 |
❌ 上报 code=5 |
✅ |
| 同页多实例 | ✅ | ✅ | ✅ | ❌ 不保证(容器 id 固定) | ✅ |
| 网络素材缓存 | 进程内按 URL | 按 URL 末段名 | 引擎内部 | 浏览器缓存 | 沙箱 vap-cache(不自动清理) |
其他已知限制(如实告知,避免售后争议):
- Android:
loop语义为"播放次数",<=0只播一次(与 iOS/微信的"无限"不同);setLoop只在下次play()完全生效。 - iOS:网络素材按 URL 末段名缓存到临时目录 —— 同名不同源的素材会互相覆盖(请避免用同名文件);
布局未就绪(父容器 0 尺寸)超过 5 秒会放弃本次播放 —— 不上报事件(仅在
setVapDebug(true)时打印一行日志),需要感知请自行加超时兜底。 - 微信小程序:未传
config时按常见拼版假定渲染;素材需 faststart(moov 在前); 无音轨素材会原地生成.sil.mp4(磁盘占用翻倍);vap-cache与临时文件不会自动清理, 长会话请自行定期清理用户目录;WASM 不可用时回退纯 JS 逐像素路径(较慢)。 - H5:引擎
vap.min.js必须随static/分发;play()需等引擎就绪(首次会动态加载引擎); 运行期不支持setMixData/setLoop/setMute(上报code=5)。 - 全部端:
src/scaleType等 props 变更不会自动重建播放器 —— 换素材请v-if重挂载(演示工程即如此)。
💰 付费授权与试用(买前必读)
- 本插件含 UTS 原生代码 + 原生二进制(AAR / framework / har),只能用「自定义基座」或云打包运行; 官方标准基座、离线打包不支持付费插件 —— 这是插件市场规则,不是插件限制。
- 试用机制:市场提供试用版,但试用基座无法脱离 HBuilderX 独立安装,且每次启动会弹一次测试 toast; 正式购买后使用自己的自定义基座即无 toast。
- 购买前请用「试用 + 自定义基座」跑通你的素材与场景(融合元素、音效、
@click等), 平台能力差异见上表(尤其 Android 无pause/resume、鸿蒙无mute、H5/微信无@click)。
📌 性能定位(VAP 强场景)
VAP 内核 = MP4 视频流 + 逐帧遮罩合成,与 PAG / SVGA(矢量 / 位图数据容器)本质不同。它的性能价值在特定强场景最突出:
- 🎁 同屏多特效 / 直播间多礼物:视频硬解 + 只缓存一帧,内存省、CPU 省
- 💥 大粒子 / 爆场动画:真视频级粒子特效,远超矢量方案的表达上限
定位一句话:主打「直播间多礼物、大粒子、低内存」这类视频特效场景;通用动效请搭配 PAG / SVGA —— 不是 VAP 差,而是它的性能价值在特效礼物场景最突出。
🔐 隐私与安全
本插件不采集任何数据,不使用 IDFA / 定位 / 相机 / 麦克风 / 相册 / 通讯录,也不上报任何日志或统计。
- 播放素材仅使用应用内本地路径,或由插件下载到应用沙箱后再播放;下载仅请求调用方传入的
src/imgUri地址 - 不主动申请任何敏感系统权限
- 融合元素内容(昵称、头像等)由调用方提供,请自行确认已获得用户授权
- 网络请求说明:播放网络素材 / 网络融合图片时,会向调用方传入的 URL 发起请求(对端可见 IP 与 UA), 插件本身不向任何第三方服务器上报数据
- iOS 音频会话说明:播放(且非静音)时会把系统音频会话切到
playback并激活, 以便静音开关打开时仍有声音;mute=true或宿主已自行配置会话时不改动(详见「iOS」一节) - 插件实现文件已通过
uni_modules.encrypt加密分发(详见changelog.md)
📄 许可证
- Android / iOS / H5 部分封装自 Tencent VAP(MIT)— 见
LICENSE-tencent-vap.txt - HarmonyOS 部分封装自 OHOS-VAP(Apache-2.0)— 见
LICENSE-ohos-vap.txt - 插件本体授权以插件市场页面 / 购买协议为准

收藏人数:
购买源码授权版(
试用
使用 HBuilder 导入示例项目
赞赏(0)
下载 57
赞赏 0
下载 12729555
赞赏 1959
赞赏
京公网安备:11010802035340号