)
Expo Video Thumbnails 使用指南从视频生成封面图的跨平台实践expo-video-thumbnails【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expoexpo-video-thumbnails是 Expo 生态中用于从视频提取静态帧生成缩略图/封面图的官方模块典型应用场景是视频画廊、短视频列表封面、视频聊天预览等。本文基于当前仓库中 packages/expo-video-thumbnails 的源码与文档完整讲解其安装、API 使用、平台行为差异与底层实现原理读者读完后可以独立在 Expo 应用中将任意本地或远程视频转换成 JPEG 图片并正确设置质量、取帧时间与网络请求头等参数。模块概览该模块对外暴露的唯一核心能力是一个异步函数getThumbnailAsync接收一个视频地址本地或远程 URI返回一张由该视频指定时刻解码生成的 JPEG 图片文件。其在当前仓库中的定位是独立可发布的 Expo 模块包版本为57.0.1见 package.json零运行时第三方依赖dependencies为空仅以expo作为 peer 依赖并通过expo-modules-core的模块体系桥接到 Android 与 iOS 原生层。与expo-video播放和expo-av不同本模块专注于单帧提取不涉及播放控制代码量小、集成成本低非常适合作为视频列表页封面的轻量方案。安装与平台配置在托管managedExpo 项目中安装在托管工作流Expo Go / EAS Build下直接使用 Expo CLI 的安装命令即可自动匹配当前 SDK 的兼容版本npx expo install expo-video-thumbnailsnpx expo install会读取当前项目 SDK 版本对应的bundledNativeModules.json见仓库根目录 bundledNativeModules.json来锁定兼容版本避免手动选版出错。在裸bareReact Native 项目中安装裸工程需要先确保已经安装并配置好expo包expo模块运行时然后同样执行npx expo install expo-video-thumbnails随后按平台做如下配置Android无需任何额外设置。原生清单 AndroidManifest.xml 中不声明额外权限读本地文件依赖expo-file-system的文件权限服务进行校验。iOS安装 npm 包后执行npx pod-install让 CocoaPods 将 ExpoVideoThumbnails.podspec 中声明的 AVFoundation、UIKit 等系统框架链接进工程。注意Web 平台不受支持。类型声明 ExpoVideoThumbnails.web.ts 中的getThumbnailAsync会直接抛出ExpoVideoThumbnails not supported on Expo Web错误因此 Web 端需要做平台降级或隐藏该能力。API 与类型详解getThumbnailAsyncgetThumbnailAsync(sourceFilename: string, options?: VideoThumbnailsOptions): PromiseVideoThumbnailsResultsourceFilename视频的 URI可以是本地文件路径也可以是远程 HTTP(S) 地址file://、content://与普通 URL 均可。options可选配置对象。返回值一个 Promiseresolve 为VideoThumbnailsResult。JS 层入口实现在 src/VideoThumbnails.ts其内部直接调用原生模块ExpoVideoThumbnails.getThumbnail(sourceFilename, options)没有额外包装逻辑因此所有参数语义均由原生层解释。VideoThumbnailsOptions类型定义见 src/VideoThumbnailsTypes.types.ts共三个可选字段参数类型默认值说明qualitynumber1.0输出图片质量取值0.01.0。1表示不压缩质量最高0表示压缩最狠质量最低。timenumber0取帧的时间位置单位为毫秒ms。0即视频开头第一帧。headersRecordstring, string{}当sourceFilename为远程 URI 时随网络请求一起发送的 HTTP 请求头适用于需要鉴权才能访问的视频源。默认值在原生层有对应实现Android 侧 VideoThumbnailOptions.kt 中quality 1.0、time 0、headers emptyMap()iOS 侧 VideoThumbnailsOptions.swift 中quality 1.0、time 0、headers [String: String]()两端默认语义完全一致。VideoThumbnailsResulttype VideoThumbnailsResult { uri: string; // 生成图片的 URI可直接作为 Image/Video 组件的 source width: number; // 生成图片的宽度像素 height: number; // 生成图片的高度像素 };完整示例视频画廊封面以下是一个结合expo-image展示视频封面的最小可用示例sourceFilename既可以是本地缓存文件也可以是远程视频地址import { useState } from react; import { Button, StyleSheet, View } from react-native; import { Image } from expo-image; import * as VideoThumbnails from expo-video-thumbnails; export default function VideoCover() { const [uri, setUri] useStatestring | null(null); const generateCover async () { try { const { uri } await VideoThumbnails.getThumbnailAsync( https://example.com/videos/demo.mp4, { time: 5000, // 取第 5 秒的帧 quality: 0.7, // 适度压缩平衡清晰度与体积 headers: { Authorization: Bearer YOUR_TOKEN, // 远程源需要鉴权时使用 }, } ); setUri(uri); } catch (error) { console.error(生成视频封面失败:, error); } }; return ( View style{styles.container} {uri Image source{{ uri }} style{styles.cover} contentFitcover /} Button title生成封面 onPress{generateCover} / /View ); }几个实用建议展示尺寸与输出尺寸分离getThumbnailAsync输出的是视频原始分辨率的帧质量按quality压缩。列表页建议用Image的contentFitcover裁剪展示避免一次性解码超大图。封面缓存返回的 URI 指向应用缓存目录下的临时文件可用于本次会话内展示若需长期保存请自行复制到持久化目录如expo-file-system的 document 目录。远程视频预检先确认视频可访问网络、鉴权头正确再调用取帧避免在 UI 线程附近触发长耗时网络解码。平台实现与底层原理AndroidMediaMetadataRetrieverAndroid 端实现位于 VideoThumbnailsModule.kt核心链路如下URI 校验与读取权限检查用URLUtil.isValidUrl校验来源合法性若为file://URI则通过appContext.filePermission服务FilePermissionService校验 READ 权限无权限抛出ThumbnailFileException。按 URI 类型分路设置数据源file://解码路径后调用retriever.setDataSource(path)content://通过contentResolver.openFileDescriptor拿到文件描述符后设置数据源其余远程 URL直接retriever.setDataSource(sourceFilename, videoOptions.headers)将headers透传给网络层。取帧retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)。注意源码中time先乘以 1000 再传给系统 API——这是因为模块 API 的time以毫秒为单位而 Android 的getFrameAtTime要求微秒OPTION_CLOSEST_SYNC表示返回最接近指定时间点的关键帧同步帧。压缩写出将 Bitmap 以 JPEG 格式、(quality * 100).toInt()的压缩质量写入缓存目录cacheDir/VideoThumbnails/最终返回file://URI 与宽高。异常收敛IOException与RuntimeException统一以E_VIDEO_THUMBNAILS错误码 reject模块销毁OnDestroy时取消 IO 协程作用域避免内存泄漏。取帧失败、无法读取源文件、权限模块缺失等场景分别对应 Exceptions.kt 中定义的InvalidSourceFilenameException、ThumbnailFileException、GenerateThumbnailException、FilePermissionsModuleNotFound等可编码异常。iOSAVAssetImageGeneratoriOS 端实现位于 VideoThumbnailsModule.swift基于 AVFoundation对file://源做可读性校验FileSystemUtilities.isReadableFile失败抛FileSystemReadPermissionException。用AVURLAsset加载资源并将options.headers映射为AVURLAssetHTTPHeaderFieldsKey注入网络请求与 Android 端的 headers 透传行为对应。创建AVAssetImageGenerator关键设置appliesPreferredTrackTransform true自动应用视频轨道的变换信息保证生成图片方向正确竖屏视频不会横躺requestedTimeToleranceAfter .zero要求精确取帧requestedTimeToleranceBefore .zero仅当请求时间小于视频时长时才设置否则精确取帧会失败源码注释明确说明了该约束。将time毫秒转换为CMTimeMake(value: time, timescale: 1000)后调用copyCGImage(at:actualTime:)同步取帧。用jpegData(compressionQuality: quality)编码并原子写入缓存目录cacheDir/VideoThumbnails/文件名由 UUID 生成返回file://URI 与宽高。从源码结构看iOS 采用“精确取帧”零容差策略而 Android 采用“最近同步帧”策略因此两者在相同time下可能得到略有偏差的帧跨平台对帧内容一致性要求高的场景需要留意。一致的结果契约两端返回结构完全一致{ uri, width, height }Android 侧见 VideoThumbnailOptions.kt 中的VideoThumbnailResultiOS 侧见 VideoThumbnailsModule.swift 的返回字典JS 层无需做平台分支即可消费。版本与变更说明模块版本与 SDK 同步演进CHANGELOG.md 显示57.0.12026-07-15与57.0.02026-06-25均无用户可见变更56.0.0的破坏性变更是将最低 iOS/tvOS 版本提升至 16.4、macOS 提升至 13.4。升级 SDK 时建议使用npx expo install expo-video-thumbnails保持版本匹配。常见问题排查现象可能原因与对策Web 端调用报错模块不支持 WebExpoVideoThumbnails.web.ts 直接抛错需做平台判断或提供降级方案。远程视频取帧失败检查headers是否包含所需的鉴权字段确认网络可访问Android 端取帧失败统一返回E_VIDEO_THUMBNAILS。本地文件读取失败file://路径需通过expo-file-system的权限服务校验跨目录或沙箱外文件会被ThumbnailFileException拒绝。封面方向不对iOS确认未手动禁用appliesPreferredTrackTransform该设置保证图片按轨道变换方向输出。生成图片体积过大调低quality如0.50.7或结合expo-image-manipulator做二次缩放。扩展阅读模块 JS 入口与类型src/VideoThumbnails.ts、src/VideoThumbnailsTypes.types.tsAndroid 原生实现VideoThumbnailsModule.ktiOS 原生实现VideoThumbnailsModule.swift版本演进CHANGELOG.md模块清单与版本锁定bundledNativeModules.json该模块是 Expo 官方 SDK 中面向“视频封面/缩略图”场景的标准化方案API 极简一个函数、三个可选参数两端原生实现语义对齐适合直接嵌入视频列表类应用也可作为理解 Expo ModulesKotlin/Swift 双端桥接架构的轻量参考样本。【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考