使用 UTS 开发 UniApp X iOS 原生视频播放器插件:从零实现 IvVideo

随着 UniApp X 的推出,其全新的语言 UTS(Uni TypeScript) 为开发者带来了更深层次的原生能力调用支持。相比传统的 uni.createNativeView + 原生模块通信的方式,UTS 允许我们在接近原生开发体验的同时,依然保持跨端开发的便利性。

本文将带你使用 UTSiOS 端 实现一个轻量级的原生视频播放器插件 —— IvVideo,基于 AVFoundation 框架,支持基础播放控制、视频加载、音量调节等功能,适用于需要高性能视频播放的场景。

为什么选择 UTS 实现原生视频播放?

在传统 UniApp 开发中,<video> 组件虽然简单易用,但在复杂场景下存在诸多限制:

  • 不支持自定义播放器 UI 层级
  • 无法精确控制播放行为(如 seek 精度、缓冲策略)
  • 性能瓶颈(尤其在列表中大量视频播放时)
  • 缺乏对原生 AVPlayer 高级特性的调用能力

而通过 UTS,我们可以直接调用 iOS 的 AVFoundation 框架,实现真正意义上的原生级视频播放体验,同时无缝集成到 UniApp X 的视图系统中。

技术栈概览

技术说明
UniApp X新一代跨平台应用开发框架
UTS跨平台原生语言,支持直接调用 iOS/Android 原生 API
AVFoundationiOS 媒体播放核心框架
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 中的原生视图元素,用于绑定原生 UIView
  • playerAVPlayer 实例,控制播放逻辑
  • playerLayerAVPlayerLayer,负责视频画面渲染
  • 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)

使用 AVAssetAVPlayerItem 加载远程视频资源:

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
}

建议在 onUnloadonDetached 钩子中调用。

如何在 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 对 CMTimeNSNotification 等类型支持尚不完善,部分功能需等待官方完善
  • 暂未实现播放状态监听(如播放结束、缓冲状态)
  • 未处理横竖屏适配与自动旋转

🔮 后续优化方向

  • 封装事件回调(如 onPlayonPauseonEnded
  • 支持 HLS / DASH 流媒体
  • 添加加载状态 UI(loading 指示器)
  • 实现画中画(PiP)模式
  • Android 端兼容实现(使用 MediaPlayer 或 ExoPlayer

参考文档

通过 UTS,我们得以在 UniApp X 中实现真正意义上的原生级功能扩展。本文实现的 IvVideo 播放器只是一个起点,未来我们可以构建更复杂的多媒体应用,如短视频播放器、直播推流、滤镜处理等。

UTS 正在打开一扇通往“跨端 + 原生”融合开发的新大门,值得每一位跨端开发者深入探索。

0

发表回复