更新记录
1.0.1(2026-09-15)
本次修的主要是只有付费加密版才会暴露的问题:源码版开发时一切正常、买家侧才复现。 建议 1.0.0 用户尽快升级。
① 修 H5 白屏:does not provide an export named 'VapScaleType'(P0,加密版必现)
- 根因(三轮才定死):加密插件的平台入口在 H5 端只提供「运行期导出」,而类型在运行期没有任何绑定
组件原本写
import { VapPlayer, VapMixData, VapScaleType } from "@/uni_modules/axen-vap-x"。 付费插件发布后平台入口是密文(.web/.encrypt/**/index.module.js在磁盘上就是密文,构建期解密后 才交给浏览器),而浏览器只能按运行期导出解析具名 import —— 纯类型永远不会有运行期绑定,于是直接抛SyntaxError: The requested module '...' does not provide an export named 'VapScaleType',组件不渲染。 编译期零报错,只在加密版(买家侧)出现。对照:App 三端入口在编译期解密、类型照常解析; mp-weixin 产物是整模块require()+.VapPlayer取值,从不按名字索要类型 —— 只有 H5 的 ESM 具名 import 会暴露这个坑。 - 修复:类型声明按平台分流(组件与示例页都这么写):
WEB || MP-WEIXIN:在文件内本地声明(JS 端类型是结构化匹配,不存在"两个类"的问题)APP-ANDROID || APP-IOS || APP-HARMONY:仍从插件入口import(必须共用同一份声明, 否则触发 compiler-known-issues error17)
- 三条已验证的死路(别再试):
①
import type { ... } from "@/uni_modules/axen-vap-x"—— 编译产物原样保留该语句,web 管线不认这个前缀; ② 从"@/uni_modules/axen-vap-x/utssdk/interface.uts"引 —— 解析不了(TS2307: Cannot find module '.../interface'); ③ 在interface.uts里给类型名配同名运行时值 —— UTS 报invalid redeclaration(类型名与常量同名会冲突,不像 TS 那样分属两个命名空间)。 - 业务侧提醒:H5 / 小程序端不要从插件入口 import 本插件的类型;readme 已给出可直接复制的分流写法。
② H5 融合图片加载失败不再静默(新增播放前预检)
跨域图片被浏览器拦掉后,旧版是静默失败:动画照常播完、只有该融合元素不显示,
控制台里只有一行 blocked by CORS policy,不看控制台根本发现不了。
现在播放前会用与引擎完全相同的方式(crossOrigin=anonymous)预检所有 http(s) 融合图片:
- 失败 → 报
code=2(素材下载失败),并在控制台打印可执行的修复提示 (图片服务器需返回Access-Control-Allow-Origin,或改用同源图片 / 带 CORS 的 CDN); - 播放不中断 —— 缺的只是一个元素,动画本身没问题;
- 同源 / 本地路径(如
/static/user.png)不探测;App / 小程序端走原生下载,完全不受影响。
③ 其他
- 组件 5 条
'player' is possibly 'null'编译告警清理(改用player?.,与本文件其它调用一致)。 - 文档:readme 补「类型导入按平台分流」的可复制写法、以及「打 iOS 模拟器包会链接失败」的报错与自救步骤; PLATFORMS 补 H5 的图片/视频必须可跨域(含实测响应头对照)与本次预检行为。
- 示例工程:融合头像从跨域的
q1.qlogo.cn换成同源/static/user.png,避免示例自踩文档里的 H5 跨域约束。
1.0.0(2026-09-15)
- 跨端 VAP 视频动画特效组件(uni-app x:Android / iOS / HarmonyOS / H5 / 微信小程序)。
- 功能:
- 融合元素:头像 / 昵称 / 图片 / 文字动态合成(VAP 招牌能力)。
- 网络地址自动下载缓存后播放。
- 属性:
src/loop/autoplay/mute/scaleType/mixData。 - 事件:
@started/@finish/@frame/@error/@click。 - 方法:
play()/stop()/pause()/resume()/setMixData()。
- 微信小程序:
VideoDecoder mode 0+MediaAudioPlayer系统级音画同步;像素计算走 WASM(static/vap-pixel.wasm随插件分发):YUV→RGBA / alpha 蒙版 / RGB+alpha 预合成 / 融合元素全帧合成(compose_full:纹理双线性缩放 + 蒙版裁剪 + source-over 都在堆内完成,有融合元素时每帧 canvas 调用从 ~12 次降到 2 次;wasm 不可用或纹理未就绪时自动回退 canvas 逐元素路径,视觉语义一致)。 - 插件加密:
uni_modules.encrypt覆盖全部实现文件 —— 各端utssdk/*/index.uts、utssdk/shared.uts、utssdk/interface.uts、utssdk/app-harmony/builder.ets、 小程序与 web 的辅助实现,以及 组件本体components/axen-vap-x/axen-vap-x.uvue。 仅文档、许可证、插件配置、原生二进制依赖(aar/har/framework)与引擎文件不加密。 说明:static/vap-pixel.wasm为自研引擎产物,当前未列入 encrypt —— 微信小程序只对.js做运行时解密、不解密.wasm,加密后存在加载失败风险, 故保持明文分发(如需加密请先在小程序端实测加载是否正常)。 - 底层:Android(腾讯 VAP animplayer + VapBridge)、iOS(QGVAPlayer)、HarmonyOS(OHOS-VAP)。
- 合规:MIT(Tencent VAP)/ Apache-2.0(OHOS-VAP),保留第三方版权声明。
兼容性修正
- 五端统一暴露
clearCanvas():Android/Harmony 为空实现、web 透传引擎;组件卸载时统一「先清屏再销毁」,修复微信端动画结束后的残影。 - Android 真机跑通(HBuilderX 5.07 + 自编基座),期间修掉四个会导致编译/运行失败的问题:
- 导出类不再实现 AAR 里的
VapBridge.Listener(uvue 编译类路径没有 AAR,会报Cannot access 'VapBridge.Listener' which is a supertype of 'VapPlayer');AAR 相关代码全部收敛进内部VapBridgeAdapter。 - 组件 → 插件改为传普通对象(
UTSJSONObject)+ JSON 字符串(mixDataJson/configJson), 插件侧由新增的utssdk/shared.uts解析,解决uni.UNIxxxx.VapOptions与uts.sdk.modules.uniVapX.VapOptions两个同名类导致的「参数类型不匹配」(compiler-known-issues error17)。 - 共享类型(
VapScaleType/VapMixData/VapOptions/VapEvents)统一只在utssdk/interface.uts声明,各平台import复用。 - 组件内
player.on(...)回调形参补类型标注;onUnmounted里五端都不存在的clear()改为clearCanvas()。
- 导出类不再实现 AAR 里的
- 文档补充:事件回调形参固定为
UTSJSONObject(用getNumber/getString取值);ref调子组件方法的正确类型写法。
融合素材(vapx)播放卡死修复
- 现象:含融合元素的素材(
vapx.mp4)点击后无任何反应——不显示画面、不触发started/error,系统日志里也不创建视频解码器;而无融合元素的demo.mp4一切正常。 - 根因:
VapBridge(AAR 内 Java 桥)的fetchImage/fetchText只在成功取到资源时才回调result, 违反 VAP SDK 官方契约——官方 demo 明确注释「无论图片是否获取成功都必须回调 result,否则会无限等待资源」。 于是有融合元素的素材在播放前卡在资源等待,解码器不会被创建,事件也不会回调。 - 修复:两处回调改为无条件
result.invoke(...)(取不到时传 null),重新编译animplayer-release.aar并替换到utssdk/app-android/libs/。 - 排查附注:
vapx.mp4文件本身完好(设备侧 md5 =f981e0f094ead842ad5ae99f1ffaa1a1,与腾讯官方 demo 登记值一致),排除素材损坏/编码不兼容。 - ⚠️ AAR 源码工程
android-player/未纳入版本控制,重编译 AAR 前请先对照上述修改点,避免改动丢失。
无音轨素材丢尾帧修复(微信小程序)
- 现象:
demo.mp4(80 帧 @25fps 无音轨)在微信端稳定报 78~79 帧,日志end early: 78 / 80;vapx.mp4(240 帧有音轨)始终精确。 - 根因:
VideoDecoder在流尾(EOS)会吞掉硬解管道里最后 1~2 帧;有音轨素材走mode 0+MediaAudioPlayer时音频时钟会把尾帧全量 flush 出来,纯视频轨没有这条时钟。 是否丢帧与文件本身有关(疑与编码器写入的重排缓冲参数有关):vapx.mp4去掉音轨后仍不丢,demo.mp4则 mode 0 / mode 1 都丢,无法靠播放侧策略规避。 - 修复:素材落盘后、播放前原地 remux 加一条静音 AAC 轨(
utssdk/mp-weixin/mp4-remux.uts, 纯字节数学无依赖:解析 moov/stbl 索引 → 视频样本原样拷贝 → 追加 44.1kHz mono 静音轨, 产物为原路径 + ".sil.mp4"伴生文件,faststart 布局),之后与有音轨素材完全同链路 (mode 0+MediaAudioPlayer)。静音帧/esds 为常量字节(AAC 帧间无预测可任意重复), 提取自 ffmpeg anullsrc 产物。remux 失败(非 mp4 / 已有音轨 / co64 / 写盘异常)回退mode 1+ fps 门控兜底;探测失败一律按"有音轨"处理,不引入新风险。 1.5MB 素材 remux 仅几 ms,一次性开销;结果按路径缓存,重播直接播伴生文件。 - 被否决的中间方案(记录防回退):无音轨分流
mode 1+ fps 门控在 Node 状态机里 8 例全绿,但真机仍 78/80 —— mock 全绿 ≠ 真机正确,一切结论以真机日志为准。 - 连带修掉:
loop > 1时每轮只播 1 帧 ——frameIndex在 seek 重播后没归零, 第二轮第一帧就满足"帧数达标即收尾"。现每轮归零,finish上报的即素材总帧数。 - 验证:Node 状态机(伪造 VideoDecoder/MediaAudioPlayer,按真实文件字节判音轨)8 例全绿; remux 产物字节级校验(视频样本与源逐一相等 / vapc 原样保留)+ ffprobe 全量解码零错误; 真机回归:demo.mp4 80/80、vapx.mp4 240/240、大文件去音轨 vapx remux 后 240/240、 包内素材不重复 remux。
已知限制(详见文档)
- Android 引擎不支持
pause/resume(与官方 SDK 一致)。 - HarmonyOS 端暂未开放静音控制(依赖 @ohos/vap 能力)。
- 微信小程序
pause/resume:素材统一走 mode 0(无音轨的已 remux 加静音轨),实时解码无真暂停能力, pause 期间进度继续,音画仍同步。(仅 remux 失败的极少数素材回退 mode 1,pause 即真正停在当前帧。) - iOS 在 Intel Mac 的 x86_64 模拟器上会被 QGVAPlayer 拦截(Apple Silicon 模拟器正常,组件会自动切 OpenGL);
scaleType暂未生效;未实现viewDidFailPlayMP4回调,播放失败以@error之外的下载/超时路径上报。
规划
- uni-app(vue) 老式原生插件版(覆盖非 uni-app x 存量用户)。
- 遮罩 / 事件帧更精细回调。
平台兼容性
uni-app(3.8.4)
| Vue2 | Vue2插件版本 | Vue3 | Vue3插件版本 | Chrome | Chrome插件版本 | Safari | Safari插件版本 | app-vue | app-vue插件版本 | app-nvue | app-nvue插件版本 | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 1.0.0 | √ | 1.0.0 | √ | 1.0.0 | √ | 1.0.0 | √ | 1.0.0 | √ | 1.0.0 | 5.0 | 1.0.0 | 12 | 1.0.0 | √ | 1.0.0 |
| 微信小程序 | 微信小程序插件版本 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 1.0.0 | - | - | - | - | - | - | - | - | - | - | - |
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 三端原生渲染(硬解 + Metal / OpenGL),H5 用 vap-web(WebGL),微信小程序用自研 VideoDecoder + Canvas2D 引擎
- 👤 融合元素:动画内预留 tag,运行时注入头像 / 昵称 / 图片 / 文字(VAP 招牌能力)
- 🔊 音效支持:音效 / 背景音内嵌在 VAP mp4 里,播放即有声、音画天然同步(素材无需单独挂音频文件)—— Android / iOS / 微信小程序端支持:微信端为
VideoDecoder+MediaAudioPlayer系统管线级音画同步,iOS 含静音开关下的音频会话处理(避免"扬声器没声、插耳机才有声");HarmonyOS / H5 暂为无声渲染(见平台能力矩阵) - ⚡ 网络地址:直接传 http(s),组件内部自动下载缓存后播放
- 🎛️ 完整事件:
started / frame / finish / error / click,帧序号与总帧数五端语义已对齐 - 📐 缩放与循环:
scaleType(aspectFit / aspectFill / scaleToFill)、loop、mute - 🪶 低内存:视频硬解 + 只缓存一帧,适配「同屏多礼物、大粒子」场景
⚠️ 本插件适用于 uni-app x 项目。传统 uni-app(vue) 项目请使用配套免费组件
axen-vap(H5 + 微信小程序)。 支付宝等其余小程序平台因无逐帧视频解码 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 不支持,上报 code=5) |
scaleType |
string | aspectFit |
aspectFit / aspectFill / scaleToFill |
config |
any | null | vapc 配置。App 三端可留空(原生引擎自己解析 mp4 的 vapc box);H5 留空时组件会自动 fetch 素材并提取;微信端建议显式传入 —— 留空时自研引擎按「RGB 在上 / alpha 在下」的常见拼版假定渲染,遇到别的拼版会裁剪错误 |
bypassProcess |
boolean | false | 仅微信小程序:跳过素材预处理(包内素材可用) |
事件
| 事件 | 参数 | 触发 |
|---|---|---|
started |
— | 播放开始 |
frame |
{ index } |
每渲染一帧(index 为原生帧序号,基准各端不同) |
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、微信在已结束时 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 { UniVapXComponentPublicInstance } 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?.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 模拟器,详见下节 |
🔧 平台特定说明
iOS
- 只在真机验证动画(重要):组件里没有"模拟器自动切 OpenGL"这类逻辑, 实测模拟器上 VAP 画面不出来(Metal 图层抓不到 / 渲染层不刷新), iOS 端动画一律用真机验证,模拟器只用来验证页面布局与样式。
-
framework 按平台存放(Apple Silicon 上真机 arm64 与模拟器 arm64 无法 lipo 合并, 而 HBuilderX 不会嵌入
.xcframework动态库,所以只能切换):目录 架构 用途 utssdk/app-ios/Frameworks/真机 arm64 默认发布版本,唯一能真正播放 utssdk/app-ios/Frameworks-alt/device/真机 arm64 备份 utssdk/app-ios/Frameworks-alt/simulator/模拟器 x86_64+arm64 仅本地编译校验 切换命令:
bash scripts/use-ios-framework.sh device|simulator|status(会同步到 demo 工程) -
⚠️ 打 iOS 模拟器包会链接失败(别误判成代码问题):
Frameworks/里默认是真机切片, 所以选择「iOS Appstore(模拟器)」或运行到 iOS 模拟器 时,UTS 插件会在链接阶段报:Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_QGVAPWrapView", referenced from: objc-class-ref in index.o这就是缺模拟器切片,跟代码、证书、描述文件都无关。另外:真机切片与模拟器切片 不可能同时就位(见上表),所以真机包与模拟器包不要一次同时提交 —— 同时提交时必有一个用错切片。 确实需要模拟器时(仅验证页面布局/编译,动画在模拟器上不出画面),手动换用模拟器切片 (插件包内没有
scripts/,按目录替换即可):cd uni_modules/axen-vap-x/utssdk/app-ios rm -rf Frameworks/QGVAPlayer.framework cp -R Frameworks-alt/simulator/QGVAPlayer.framework Frameworks/ # 用完换回真机切片:把上面 simulator 换成 device - 重新编译 framework:
bash scripts/build-ios-framework.sh(从vendor/tencent-vap/iOS源码编译真机 + 模拟器两个切片) - 本地校验 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) | ✅ | ⚠️ 伪暂停(时间轴继续走) |
mute 属性 |
✅ | ✅ | ❌ 上报 code=5 |
✅(构造期) | ✅ |
scaleType |
✅ | ✅ | ✅ | ✅ | ✅(仅渲染分支) |
@click |
✅ | ✅ | ✅ | ❌ | ❌ |
@frame 帧序号基准 |
1 基 | 1 基 | 1 基 | 1 基 | 0 基 |
运行期 setMixData/setLoop/setMute |
✅ | ⚠️ 下次播放生效 | ✅ | ❌ 上报 code=5 |
✅ |
| 同页多实例 | ✅ | ✅ | ✅ | ❌ 不保证(容器 id 固定) | ✅ |
| 网络素材缓存 | 进程内按 URL | 按 URL 末段名 | 引擎内部 | 浏览器缓存 | 沙箱 vap-cache(不自动清理) |
其他已知限制(如实告知,避免售后争议):
- Android:
loop语义为"播放次数",<=0只播一次(与 iOS/微信的"无限"不同);setLoop只在下次play()完全生效。 - iOS:网络素材按 URL 末段名缓存到临时目录 —— 同名不同源的素材会互相覆盖(请避免用同名文件);
布局未就绪(父容器 0 尺寸)超过 5 秒会放弃本次播放并上报
code=5。 - 微信小程序:未传
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 - 插件本体授权以插件市场页面 / 购买协议为准

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