随着 UniApp X 的推出,其全新的语言 UTS(Uni TypeScript) 为开发者带来了更深层次的原生能力调用支持。相比传统的 uni.createNativeView + 原生模块通信的方式,UTS 允许我们在接近原生开发体验的同时,依然保持跨端开发的便利性。
本文将带你使用 UTS 在 iOS 端 实现一个轻量级的原生视频播放器插件 —— IvVideo,基于 AVFoundation 框架,支持基础播放控制、视频加载、音量调节等功能,适用于需要高性能视频播放的场景。
为什么选择 UTS 实现原生视频播放?
在传统 UniApp 开发中,<video> 组件虽然简单易用,但在复杂场景下存在诸多限制:
- 不支持自定义播放器 UI 层级
- 无法精确控制播放行为(如 seek 精度、缓冲策略)
- 性能瓶颈(尤其在列表中大量视频播放时)
- 缺乏对原生
AVPlayer高级特性的调用能力
而通过 UTS,我们可以直接调用 iOS 的 AVFoundation 框架,实现真正意义上的原生级视频播放体验,同时无缝集成到 UniApp X 的视图系统中。
技术栈概览
| 技术 | 说明 |
|---|---|
| UniApp X | 新一代跨平台应用开发框架 |
| UTS | 跨平台原生语言,支持直接调用 iOS/Android 原生 API |
| AVFoundation | iOS 媒体播放核心框架 |
| UIKit | 构建原生视图容器 |
| CoreFoundation | 处理几何结构(如 CGRect) |
核心类设计:IvVideo
我们封装了一个名为 IvVideo 的类,负责管理视频播放的生命周期。以下是核心结构:
export class IvVideo {
element: UniNativeViewElement | null = null
player: AVPlayer | null = null
playerLayer: AVPlayerLayer | null = null
playerItem: AVPlayerItem | null = null
videoContainerView: UIView | null = null
width: Int = 100
height: Int = 100
constructor(element: UniNativeViewElement, width: number = 100, height: number = 100) {
this.element = element
this.setVideoSize(width, height)
this.bindView()
}
}
成员说明
element: 对应 UTS 中的原生视图元素,用于绑定原生UIViewplayer:AVPlayer实例,控制播放逻辑playerLayer:AVPlayerLayer,负责视频画面渲染playerItem: 包装视频资源的播放项videoContainerView: 容器视图,承载playerLayer
视图绑定:bindView()
通过 UIView 创建一个原生容器,并将 AVPlayerLayer 添加为其子图层:
bindView(): void {
const cgRect = CGRect.init(0, 0, this.width, this.height)
this.videoContainerView = UIView.init(frame: cgRect)
this.player = AVPlayer.init()
this.playerLayer = AVPlayerLayer.init(player: this.player)
this.playerLayer!.frame = this.videoContainerView!.bounds
this.playerLayer!.videoGravity = AVLayerVideoGravity.resizeAspect // 保持宽高比
this.videoContainerView!.layer.addSublayer(this.playerLayer!)
if (this.element != null) {
this.element.bindIOSView(this.videoContainerView!)
}
}
注意:必须通过
bindIOSView()将原生UIView绑定到UniNativeViewElement,否则无法在页面上显示。
加载视频:setVideoUrl(url: string)
使用 AVAsset 和 AVPlayerItem 加载远程视频资源:
setVideoUrl(url: string): void {
try {
const urlString: URL = URL.init(string: url)!
if (!urlString) {
console.error(`Invalid URL: ${url}`)
return
}
const asset: AVAsset = AVAsset.init(url: urlString)
this.playerItem = AVPlayerItem.init(asset: asset)
this.player!.replaceCurrentItem(with: this.playerItem)
} catch (error) {
console.error(`Failed to set video URL: ${error}`)
}
}
该方法支持 HTTP/HTTPS 视频流,后续可扩展支持本地文件或 HLS 流。
播放控制 API
我们封装了常用播放控制方法:
| 方法 | 功能 |
|---|---|
play() | 开始播放 |
pause() | 暂停播放 |
seekTo(time: number) | 跳转到指定时间(秒) |
getCurrentTime() | 获取当前播放时间 |
getDuration() | 获取视频总时长 |
setVolume(volume) | 设置音量(0.0 ~ 1.0) |
destroy() | 销毁播放器,释放资源 |
资源释放:destroy()
防止内存泄漏,必须在组件销毁时调用:
destroy(): void {
console.log('video player destroy')
this.pause()
this.player = null
this.playerLayer = null
this.playerItem = null
}
建议在 onUnload 或 onDetached 钩子中调用。
如何在 UniApp X 中使用?
1. 注册原生视图
<template>
<native-view class="iv-video" @init="onViewInit"></native-view>
</template>
<script setup lang="uts">
import { IvVideo } from '@/uni_modules/iv-video'
let videoPlayer : IvVideo | null = null
const props = withDefaults(defineProps<{ src ?: string }>(), {
src: ''
})
function onViewInit(e : UniNativeViewInitEvent) {
const width : number = Math.floor(uni.rpx2px(750))
const height : number = Math.floor(uni.rpx2px(421))
videoPlayer = new IvVideo(e.detail.element, width, height)
if (videoPlayer != null) {
videoPlayer.setVideoUrl(props.src)
videoPlayer.play()
}
}
onUnmounted(() => {
if (videoPlayer != null) {
videoPlayer?.destroy()
}
})
</script>
<style lang="scss">
.iv-video {
width: 750rpx;
height: 421rpx;
}
</style>
2. 页面中使用
<iv-video src="https://alivod.qujingm.com/a078b8556c4971ef837f4531858c0102/71677ca99a4a628b6217b75b8655e95d-sd.m3u8"></iv-video>
优势总结
- ✅ 原生性能:基于
AVPlayer,播放流畅,支持硬件解码 - ✅ 灵活控制:可精确控制播放、跳转、音量等
- ✅ 无缝集成:通过
UniNativeViewElement与前端视图系统融合 - ✅ 可扩展性强:后续可支持弹幕、画中画、倍速播放等
当前限制与后续优化
⚠️ 已知限制
- UTS 对
CMTime、NSNotification等类型支持尚不完善,部分功能需等待官方完善 - 暂未实现播放状态监听(如播放结束、缓冲状态)
- 未处理横竖屏适配与自动旋转
🔮 后续优化方向
- 封装事件回调(如
onPlay,onPause,onEnded) - 支持 HLS / DASH 流媒体
- 添加加载状态 UI(loading 指示器)
- 实现画中画(PiP)模式
- Android 端兼容实现(使用
MediaPlayer或ExoPlayer)
参考文档
通过 UTS,我们得以在 UniApp X 中实现真正意义上的原生级功能扩展。本文实现的 IvVideo 播放器只是一个起点,未来我们可以构建更复杂的多媒体应用,如短视频播放器、直播推流、滤镜处理等。
UTS 正在打开一扇通往“跨端 + 原生”融合开发的新大门,值得每一位跨端开发者深入探索。