ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

expo-live-photo 完全指南:在 Expo / React Native 中渲染 iOS 实况照片

expo-live-photo 完全指南:在 Expo / React Native 中渲染 iOS 实况照片 expo-live-photo 完全指南在 Expo / React Native 中渲染 iOS 实况照片【免费下载链接】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导读expo-live-photo是 Expo 生态中专用于渲染 Live Photo实况照片的模块支持 iOS 与 Web 平台底层以 Swift 封装 ApplePhotosUI框架的PHLivePhotoView实现。本文以该包在仓库中的 CHANGELOG.md 为骨架结合 TypeScript API 定义、React 组件实现 与 iOS 原生源码完整讲解安装方式、LivePhotoView全部 props 与命令式方法、底层加载/播放原理以及从 0.0.1 到 57.0.1 的版本演进脉络。读完后你将能在自己的 Expo / React Native 应用中直接接入并控制实况照片的展示与播放。一、版本演进与里程碑包的完整变更历史集中在 CHANGELOG.md从 2024 年 10 月的首个发布至今经历了若干次里程碑式变更版本时间类型变更要点0.0.12024-10-22 新功能初始发布PR #311930.1.02025-04-04 其他迁移expo-module.config.json到统一平台语法修复 Swift 6 下会升级为错误的警告PR #344451.0.02025-08-13 其他迁移到 React 19PR #3730356.0.02026-05-05 破坏性变更最低 iOS/tvOS 版本提升至 16.4macOS 提升至 13.457.0.12026-07-15—当前版本无面向用户变更解读几个关键节点从0.x到1.0.0的跃升1.0.0的核心变更依据 CHANGELOG是将包迁移到 React 19这标志着该库在 Expo SDK 生态中正式进入稳定 API 阶段此后的55.0.0、56.0.0、57.0.1等版本则跟随 Expo SDK 的版本号体系进行对齐发布多数为无用户可见变更的内部维护。系统版本门槛CHANGELOG 明确记录56.0.0将最低 iOS/tvOS 版本提升到 16.4、macOS 到 13.4。这意味着在当前仓库主分支版本下使用实况照片功能需要设备运行 iOS 16.4。平台适配0.1.0将模块配置迁移到统一平台语法与当前仓库中 expo-module.config.json 的形态一致——该文件声明platforms: [apple]并注册原生模块LivePhotoModule这是理解该包“仅面向 Apple 平台原生实现、其余平台走降级路径”的起点。二、安装与工程配置2.1 安装 npm 包在 bare React Native 工程中需要先确保已安装并配置好expo包然后执行npm install expo-live-photo从 package.json 可以看出该包没有运行时dependencies只依赖expo、react、react-native三个peerDependenciesmain指向build/index.js类型声明在build/index.d.ts而exports字段在支持expo-source条件时直接指向 TypeScript 源码src/index.ts便于 Expo 开发服务器按源码形态打包。2.2 iOS 配置iOS 需要安装 CocoaPods 依赖npx pod-install原生侧由 ExpoLivePhoto.podspec 描述依赖关系编译时依赖PhotosUI与Photos框架见下文原生实现。2.3 Android / Web 的降级行为README 中仅提供 iOS 配置步骤没有 Android 配置章节这与仓库源码一致模块配置声明平台为[apple]因此 Android 上并没有原生实现。从 LivePhotoView.tsx 的源码看const NativeView: React.ComponentTypeNativeLivePhotoViewProps | null isAvailable() ? requireNativeView(ExpoLivePhoto) : null; function isAvailable() { return process.env.EXPO_OS ios; }在非 iOS 平台上组件会打印expo-live-photo is not available on ${process.env.EXPO_OS}警告并渲染null调用命令式方法如startPlayback则会抛出UnavailabilityError。也就是说该库在非 iOS 平台上是“安全降级”而非“模拟实现”这一点对跨平台工程很重要。三、核心 APILivePhotoView包入口 src/index.ts 只导出两样东西export { default as LivePhotoView } from ./LivePhotoView; export * from ./LivePhoto.types;即一个 React 组件LivePhotoView和全部类型定义。3.1 数据模型LivePhotoAsset实况照片本质上是静态照片 配对视频的组合因此source需要同时提供两个文件的 URIexport type LivePhotoAsset { photoUri: string; // 实况照片的静态图片部分 pairedVideoUri: string; // 与之配对的视频部分 };类型注释见 LivePhoto.types.ts特别强调了一个重要约束由于原生限制照片和视频必须来自一个合法的实况照片文件且不能改动。拍摄时照片通过与视频的元数据配对一旦配对关系被破坏就无法将它们重新组合成实况照片。3.2 Props 完整参考LivePhotoViewProps继承ViewProps核心 props 如下均来自源码中的 JSDocProp类型默认值说明sourceLivePhotoAsset \| null—要展示的实况照片资源isMutedbooleantrue播放时是否静音contentFitcontain \| covercontain图片如何缩放适配容器useDefaultGestureRecognizerbooleantrue是否启用 iOS 默认手势识别器为true时用户长按LivePhotoView即开始播放onPlaybackStart() void—播放开始时回调onPlaybackStop() void—播放停止时回调onLoadStart() void—实况照片开始加载时回调onPreviewPhotoLoad() void—预览照片低质量占位图加载完成时回调onLoadComplete() void—实况照片加载完成、可播放时回调onLoadError(error: LivePhotoLoadError) void—加载出错时回调LivePhotoLoadError只包含一个字段export type LivePhotoLoadError { message: string; // 加载失败的原因 };3.3 命令式方法与静态属性通过ref可以拿到LivePhotoViewType它提供两个命令式方法export type LivePhotoViewType { startPlayback: (playbackStyle?: PlaybackStyle) void; stopPlayback: () void; };PlaybackStyle决定播放方式hint—— 只播放视频的一小段用于提示这里是一个实况照片full—— 播放完整视频。此外组件还挂载了静态方法LivePhotoView.isAvailable()用于在渲染前判断当前设备是否支持展示实况照片。四、基础用法与实战示例下面给出一个完整的最小示例加载实况照片、支持长按播放并监听加载与播放状态。import { useRef } from react; import { StyleSheet, View } from react-native; import { LivePhotoView, type LivePhotoAsset, type LivePhotoViewType, } from expo-live-photo; const source: LivePhotoAsset { photoUri: file:///path/to/live-photo.jpg, pairedVideoUri: file:///path/to/live-photo.mov, }; export default function LivePhotoScreen() { const ref useRefLivePhotoViewType | null(null); return ( View style{styles.container} LivePhotoView ref{ref} source{source} isMuted{false} contentFitcover useDefaultGestureRecognizer onLoadStart{() console.log(开始加载实况照片)} onPreviewPhotoLoad{() console.log(预览照片已就绪)} onLoadComplete{() console.log(实况照片可播放)} onLoadError{({ message }) console.error(加载失败:, message)} onPlaybackStart{() console.log(播放开始)} onPlaybackStop{() console.log(播放结束)} style{styles.livePhoto} / /View ); } const styles StyleSheet.create({ container: { flex: 1, alignItems: center, justifyContent: center }, livePhoto: { width: 320, height: 240 }, });4.1 手动控制播放如果希望由自己的交互逻辑触发播放而不是依赖 iOS 默认的长按手势可以关闭默认手势识别器并通过ref手动控制LivePhotoView ref{ref} source{source} useDefaultGestureRecognizer{false} style{styles.livePhoto} / // 播放完整视频 ref.current?.startPlayback(full); // 或仅播放提示片段 ref.current?.startPlayback(hint); // 停止播放 ref.current?.stopPlayback();注意源码实现LivePhotoView.tsx在调用时做了两层保护非 iOS 平台直接抛UnavailabilityErrorstartPlayback未传参时默认以full播放。4.2 加载流程的状态机通过组合事件回调可以构建典型的加载状态机onLoadStart开始→onPreviewPhotoLoad低质量占位图就绪→onLoadComplete完整可播放→ 任一步失败走onLoadError。这与原生加载流程一一对应见下节。五、底层原理iOS 原生实现解析该库在 iOS 侧由三个核心文件协作全部位于 packages/expo-live-photo/ios 目录。5.1 模块注册与 Prop 映射LivePhotoModule.swift 是 Expo Modules 体系下的模块定义public class LivePhotoModule: Module { public func definition() - ModuleDefinition { Name(ExpoLivePhoto) View(LivePhotoView.self) { Events(onLoadStart, onPreviewPhotoLoad, onLoadComplete, onLoadError, onPlaybackStart, onPlaybackStop) Prop(source) { (view: LivePhotoView, source: LivePhotoAsset) in view.source source } Prop(isMuted) { (view: LivePhotoView, isMuted: Bool?) in view.livePhotoView.isMuted isMuted ?? true } // ...contentFit、useDefaultGestureRecognizer 同理 } } }从这里可以看到六个事件名与 JS 侧回调一一对应事件分发由原生EventDispatcher完成JS 层传参在原生侧均为可空值并用??提供与文档一致的默认值isMuted默认true、contentFit默认.contain、手势默认开启从源码层面验证了 API 文档中的默认值约定。5.2 视图封装与手势处理LivePhotoView.swift 是核心视图类内部持有一个PHLivePhotoViewApple PhotosUI 的原生视图并实现PHLivePhotoViewDelegate加载流程loadLivePhoto()source或contentFit变化时异步触发重新加载通过PHLivePhoto.requestSequence流式获取实况照片先拿到低质量占位图触发onPreviewPhotoLoad再拿到高质量结果触发onLoadComplete任一步抛错则触发onLoadError。手势useDefaultGestureRecognizer属性变化时会从PHLivePhotoView添加或移除其内置的playbackGestureRecognizer。播放回调实现代理方法willBeginPlaybackWith/didEndPlaybackWith把原生播放开始/结束翻译为 JS 事件。5.3 加载管线与配对校验PHLivePhotoAsync.swift 用AsyncThrowingStream封装了PHLivePhoto.request(withResourceFileURLs:placeholderImage:targetSize:contentMode:)let isLowQuality loadInfo[PHLivePhotoInfoIsDegradedKey] as? Bool ?? false let error loadInfo[PHLivePhotoInfoErrorKey] as? Error if let error { continuation.finish(throwing: error) return } if let livePhoto { continuation.yield((isLowQuality, livePhoto)) if !isLowQuality { continuation.finish() } return } // 没有返回任何有效数据说明照片和视频 URL 并未配对 continuation.finish(throwing: InvalidSourceException(Provided photo and video urls are not paired))这段代码直接印证了类型定义中的警告当照片与视频未正确配对时系统不会返回有效PHLivePhoto库会以InvalidSourceExceptionProvided photo and video urls are not paired结束加载流最终通过onLoadError暴露给 JS 层。这也解释了为什么photoUri与pairedVideoUri必须来自同一个合法实况照片文件。5.4 枚举映射LivePhotoEnums.swift 定义了枚举到原生 API 的映射ContentFit.contain → PHImageContentMode.aspectFitContentFit.cover → PHImageContentMode.aspectFillPlaybackStyle.full → PHLivePhotoViewPlaybackStyle.fullPlaybackStyle.hint → PHLivePhotoViewPlaybackStyle.hint。JS 层的字符串枚举与 Swift 枚举一一对应保持了 API 的跨层一致性。六、从源码角度理解可用性与平台边界把 LivePhotoView.tsx、expo-module.config.json 与 CHANGELOG 中的破坏性变更串起来可以得到一张完整的平台能力图平台范围模块配置声明[apple]覆盖 iOS含 tvOS与 macOSCHANGELOG 中56.0.0将最低版本分别提升至 iOS/tvOS 16.4 与 macOS 13.4。JS 侧判定isAvailable()通过process.env.EXPO_OS ios判定——注意源码当前仅判定 iOSmacOS 上组件同样走不可用分支。非 iOS 降级组件渲染null 控制台警告命令式方法抛UnavailabilityError保证应用不会崩溃。这一边界设计意味着如果你需要 Android 上展示实况照片不应依赖本库而应在业务层用LivePhotoView.isAvailable()先行分流。结语expo-live-photo用很小的 API 表面积一个组件、六类事件、两个命令式方法封装了 Apple PhotosUI 中最复杂的资源模型之一——照片与视频的配对加载。本文从 CHANGELOG 的版本脉络出发结合仓库内的类型定义、React 组件与 Swift 原生实现完整还原了它的安装配置、API 用法、加载状态机与底层原理。需要深入源码的读者建议按 src → ios 的顺序阅读并结合 CHANGELOG.md 追踪各版本的破坏性变更与平台门槛。【免费下载链接】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),仅供参考
返回列表