news 2026/9/10 0:11:34

expo-video 演进全览:Expo 跨平台视频播放器的能力图谱与升级指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
expo-video 演进全览:Expo 跨平台视频播放器的能力图谱与升级指南

expo-video 演进全览:Expo 跨平台视频播放器的能力图谱与升级指南

【免费下载链接】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

本文以 packages/expo-video/CHANGELOG.md 为脉络主线,结合packages/expo-video包内的 TypeScript 类型定义、Android(Kotlin/ExoPlayer)与 iOS(Swift/AVFoundation)原生实现、config plugin 源码,系统梳理 Expo 官方视频组件expo-video从 2023 年 10 月首发至今的完整能力演进。读者将掌握该组件当前支持的全部核心特性(多轨选择、DRM、缓存、画中画、全屏、Seek/Scrubbing 优化、背景播放等)、各版本破坏性变更带来的升级注意事项,以及这些能力在仓库源码中的落地位置,可直接用于选型评估与迁移升级。

一、expo-video 是什么:定位与版本演进脉络

expo-video是 Expo 生态中面向 React Native 与 Web 的跨平台、高性能视频组件(见 packages/expo-video/package.json 中 "A cross-platform, performant video component for React Native and Expo with Web support" 的描述),支持 Android、iOS 与 Web 三端,底层分别基于 AndroidX Media3 / ExoPlayer(Android)、AVFoundation / AVPlayer(iOS)与 HTML5 Video(Web)。

从 CHANGELOG.md 的版本序列可以清晰看到该项目的发展轨迹:

  • 2023-10-30(0.1.0):iOS 首发;
  • 2023-11~2024-06(0.2.x → 1.2.x):Android 首发、事件系统、DRM、背景播放、画中画(PiP)、全屏等能力密集落地;
  • 2024-10~2025-08(2.0.0-preview → 3.0.x):事件 API 重构(useEvent支持)、音轨/字幕轨、缓存、缩略图生成等大特性合入;
  • 2026-01 起(55.0.0 → 57.0.2):版本号与 Expo SDK 版本序列对齐(从 3.0.15 直接跳至 55.0.0,可推断为跟随 SDK 版本策略),并持续引入 Seek 容差、Scrubbing 模式、自适应码率上限等进阶能力。

截至 2026-07-22,仓库当前版本为57.0.2,Unpublished 段还记录着若干待发布变更(controllerAutoShowmaxResolutionvideoChangeFrameRateStrategy等),说明该组件仍在活跃迭代中。

二、核心能力图谱:从 CHANGELOG 提炼的功能版图

将 CHANGELOG 中所有 "New features" 条目按能力域归类,可以得到expo-video的完整功能版图。以下每项能力都可在仓库源码中找到对应落地。

2.1 播放控制基础能力

能力引入版本说明
播放/暂停/循环/倍速/当前时间1.1.0loopplaybackRatepreservesPitchcurrentTime属性
音量与静音1.1.0(Web)/ 1.2.xvolumemuted,事件系统在 2.0.0-preview.0 拆分为volumeChangemutedChange
时长与直播信息1.1.9 / 1.2.0全平台durationisLive;1.2.6 增加currentLiveTimestampcurrentOffsetFromLive等直播进阶配置
替换源2.1.7replaceAsync(异步加载,不阻塞主线程)
直接创建实例2.0.0-preview.1支持new VideoPlayer()直接实例化

这些属性、方法与默认值的完整定义见 src/VideoPlayer.types.ts:例如loop默认falsevolume默认1.0playbackRate取值0~16.0timeUpdateEventInterval默认0(为 0 时不触发timeUpdate)。注意volumemuted相互独立——静音不改变音量值,设置音量也不会自动取消静音。

2.2 事件系统:从首次支持到useEvent友好

事件是 expo-video 交互的核心。CHANGELOG 中事件相关演进包括:

  • 1.1.0:Android/iOS 事件支持;
  • 1.2.3:Web 事件支持;
  • 2.0.0-preview.0(破坏性变更):所有播放器事件返回类型统一为单个对象,以更好支持useEventhook;同时将volumeChange拆分为volumeChangemutedChange
  • 2.1.0:新增sourceLoad事件(源元数据加载完成)、VideoViewonFirstFrameRender事件(首帧渲染回调,可用于隐藏封面图);
  • 1.2.6:新增timeUpdate事件及配套timeUpdateEventInterval属性。

完整事件清单见 src/VideoPlayerEvents.types.ts,包括statusChangeplayingChangeplaybackRateChangevolumeChangemutedChangeplayToEndtimeUpdatesourceChangesourceLoadvideoTrackChange/audioTrackChange/subtitleTrackChange及对应的available*TracksChange,iOS 独有isExternalPlaybackActiveChange(AirPlay 状态变更)。sourceLoad的 payload 同时携带duration与三组可用轨道数组(availableVideoTracks/availableSubtitleTracks/availableAudioTracks),是构建"清晰度/字幕/音轨切换面板"的数据基础。

2.3 多轨支持:音轨、字幕与视频轨(含 HLS 细节)

这是 expo-video 区别于轻量视频库的关键能力:

  • 2.0.0-preview.2:支持列出与选择字幕轨(closed captions);
  • 2.2.0:支持音轨——player.audioTrack设置当前音轨、player.availableAudioTracks列出可用音轨;
  • 2.1.0:支持列出可用视频轨与当前播放视频轨;
  • 55.0.0:视频轨新增averageBitrate/peakBitrate(原bitrate标记为 deprecated)、url(HLS 轨 URL)、videoRange(SDR/HLG/PQ);
  • 55.0.7:HLS 视频轨增加url字段;AudioTrack/SubtitleTrack增加nameisDefaultautoSelect字段。

在源码层面,轨道相关类型定义于 src/VideoPlayer.types.ts:VideoTrack包含idurlsizemimeTypeisSupported(Android)、bitrate/averageBitrate/peakBitrateframeRatevideoRangeAudioTrackSubtitleTrack均含languagelabel等字段。使用时有两点平台注意(源码 JSDoc 明确标注):

  • iOS 上使用 HLS 源时,URL 需含.m3u8扩展名,或将VideoSource.contentType显式设为'hls',否则视频轨不可用;
  • CHANGELOG 55.0.16 修复了 HLS 多音轨场景下availableVideoTracks的重复问题,55.0.7 起 iOS 26+ 的 HLS 视频轨获取逻辑已更新。

2.4 缓存能力与缓存管理 API

2.1.0引入缓存功能。缓存相关约束(CHANGELOG 与类型定义双重确认):

  • iOS 上 HLS 源无法使用缓存(平台限制);
  • Android/iOS 均不支持对 DRM 保护视频使用缓存;
  • 缓存时会考虑 Authorization 等鉴权请求头(Unpublished 段修复项)。

配套的缓存管理 API 定义在 src/VideoModule.ts:

  • setVideoCacheSizeAsync(sizeBytes):设置缓存上限(字节),默认 1GB,持久生效;缓存按 LRU(最近最少使用)淘汰,实际占用可能略超设定值;
  • clearVideoCacheAsync():清空全部视频缓存;
  • getCurrentVideoCacheSize():查询当前缓存占用字节数。

两个写入类 API 都要求当前不存在任何VideoPlayer实例时方可调用。缓存机制的 iOS 原生实现位于 ios/Cache 目录(VideoCacheManagerCachableRequestMediaFileHandle等),Unpublished 段还修复了两个缓存崩溃:缓存裁剪期间 open-file 注册表的数据竞争(iOS)、写入缓存时磁盘写满导致NSFileHandleOperationException崩溃(iOS,改用可捕获的 Swift 抛错 API)。

2.5 DRM:ClearKey / PlayReady / Widevine / FairPlay

1.1.0引入 Android/iOS DRM 支持,1.2.0增加 iOS FairPlay base64 证书支持。DRM 类型与选项定义在 src/VideoPlayer.types.ts:

export type DRMType = 'clearkey' | 'fairplay' | 'playready' | 'widevine'; // Android: ClearKey、PlayReady、Widevine;iOS: FairPlay export type DRMOptions = { type: DRMType; licenseServer: string; // 许可服务器 URL headers?: Record<string, string>; // 许可请求头 multiKey?: boolean; // Android 多密钥 DRM contentId?: string; // iOS certificateUrl?: string; // iOS FairPlay 证书 URL base64CertificateData?: string; // iOS base64 证书,设置后忽略 certificateUrl };

DRM 选项挂在VideoSourceObject.drm字段上;鉴权头请用DRMOptions.headers而非VideoSourceObject.headers(后者仅用于视频请求本身)。iOS 原生实现见 ios/ContentKeyManager.swift 与 ios/ContentKeyDelegate.swift。

2.6 画中画(PiP)与全屏

PiP 演进:0.3.0(iOS)→1.1.0(Android)→1.2.3起 PiP 必须通过 config plugin 开启 →1.2.6(Web)→ 2.2.2 修复非 16:9 源自动进入 PiP 时的窗口宽高比。

全屏演进:1.1.0(Android 全屏)→1.2.6全屏进入/退出事件 →3.0.0全屏方向与自动退出功能 →3.0.5Android 全屏模式始终启用原生控件(对齐 iOS)→55.0.0移除allowsFullscreenprop(改用fullscreenOptions.enable)。

相关类型定义在 src/VideoView.types.ts:

export type FullscreenOptions = { enable: boolean; // 是否提供全屏入口,默认 true orientation?: FullscreenOrientation; // default/portrait/landscape 等 7 种 autoExitOnRotate?: boolean; // 旋转到非指定方向时自动退出全屏,默认 false keepFullscreenOnPiPStop?: KeepFullscreenOnPiPStopBehavior; // iOS,'always'|'autoEnter'|'never' };

VideoView的 PiP 相关 props 包括allowsPictureInPicturestartsPictureInPictureAutomatically(Android 12+ / iOS,默认false)、onPictureInPictureStart/onPictureInPictureStop回调;模块级还有isPictureInPictureSupported()能力探测函数(见 src/VideoModule.ts)。CHANGELOG 中 PiP 相关的 bug fix 非常多(55.0.10 修复 PiP 从全屏自动进入后立即退出的问题等),可见这是多端适配的高频风险区。

2.7 背景播放与 Now Playing 通知

  • 1.1.0:背景播放支持;
  • 1.1.5 / 1.1.6:iOS / Android 自定义 Now Playing 通知;
  • 1.2.6(破坏性变更)showNowPlayingNotification默认值改为false
  • 3.0.9(破坏性变更):Android 上要显示 Now Playing 通知,config plugin 的supportsBackgroundPlayback必须为true
  • 56.1.4:修复与 expo-audio 混用后锁屏控件失效的问题。

相关播放器属性:showNowPlayingNotification(默认false)、staysActiveInBackground(默认false)、keepScreenOnWhilePlaying(默认true,Android 上仅当VideoView可见时生效)。注意 iOS 上 Now Playing 通知依赖音频模式——当audioMixingMode不是doNotMixauto时该功能不可用(见AudioMixingMode类型 JSDoc)。

背景播放与 PiP 的清单级配置由 config plugin 完成,实现见 plugin/src/withExpoVideo.ts:

export type WithExpoVideoOptions = { supportsBackgroundPlayback?: boolean; // 是否启用背景播放 supportsPictureInPicture?: boolean; // 是否启用 Android/iOS 画中画 };

该插件会:向 iOSInfo.plistUIBackgroundModes写入/移除audio;在 Android 上设置主 Activity 的android:supportsPictureInPicture;开启背景播放时注入FOREGROUND_SERVICEFOREGROUND_SERVICE_MEDIA_PLAYBACK权限并注册ExpoVideoPlaybackService前台服务(android:foregroundServiceType="mediaPlayback",绑定MediaSessionServiceintent-filter)。

2.8 Seek 精度与 Scrubbing 模式(55.0.0 起的新进阶能力)

55.0.0 引入了面向精细拖动进度条场景的两组配置:

export type SeekTolerance = { toleranceBefore?: number; // 实际 seek 位置可提前的最大秒数,默认 0 toleranceAfter?: number; // 实际 seek 位置可延后的最大秒数,默认 0 };

容差越大通常 seek 越快;它影响currentTime赋值、seekBy()的精度,Android 上还影响默认原生控件进度条的拖动精度。

export type ScrubbingModeOptions = { scrubbingModeEnabled?: boolean; // 总开关,默认 false;Android 开启后播放会被抑制 increaseCodecOperatingRate?: boolean; // 是否提升编解码器工作频率,默认 true enableDynamicScheduling?: boolean; // ExoPlayer 动态调度,默认 true useDecodeOnlyFlag?: boolean; // API 34+ 使用 MediaCodec.BUFFER_FLAG_DECODE_ONLY 加速 seek allowSkippingMediaCodecFlush?: boolean; // 允许跳过解码器 flush,默认 true };

scrubbingModeOptions建议在用户拖拽进度条的短时段内开启、结束时关闭;Android 上开启后播放被抑制,务必在交互结束后恢复。配合增大seekTolerance可获得最佳拖动体验。

2.9 自适应流控制:maxResolution 与视频刷新率策略(Unpublished 新特性)

Unpublished 段(即尚未发布、已在 main 分支)记录了两项值得关注的 Android 新能力:

  • maxResolution播放器选项:为自适应视频轨选择设置上限——播放器会选择"不超过该分辨率"的最高质量轨。Android 上是硬约束(若无满足条件的轨则回退到最低分辨率轨);iOS 上是软提示(首选上限),且 iOS 仅对 HLS 源生效。对应属性maxResolution: VideoSize | nullnull表示不设限,见 src/VideoPlayer.types.ts)。
  • videoChangeFrameRateStrategyplayer builder 选项:控制 ExoPlayer 是否允许修改显示刷新率以匹配视频帧率。默认'onlyIfSeamless'(仅在无缝切换时匹配);设为'off'可避免自适应刷新率屏(如 Pixel 9/10 系列)在播放 30fps 视频时将整个 App UI(含滚动与动画)压制到 30Hz。帧率匹配主要利好电视类大屏,垂直视频流等场景建议'off'

这两个选项分别落在VideoPlayer.maxResolution属性与PlayerBuilderOptions.videoChangeFrameRateStrategy字段上。后者在 Android 侧由 android/src/main/java/expo/modules/video/records/PlayerBuilderOptions.kt 声明(含seekBackwardIncrement/seekForwardIncrement,取值会被钳制在 0.001~999 秒之间),枚举定义在 android/src/main/java/expo/modules/video/enums/VideoChangeFrameRateStrategy.kt。

2.10 其他实用能力

  • 缩略图生成:2.0.0-preview.0 引入,2.1.0 增加maxWidth/maxHeight限制;generateThumbnailsAsync(times, options)返回原生图片引用(SharedRef<'image'>),可直接作为expo-imageImage源。相关实现见 ios/Thumbnails 与 Android 侧代码,类型见 src/VideoPlayer.types.ts 的VideoThumbnailOptions
  • 缓冲控制:2.0.0-preview.0 引入BufferOptions——preferredForwardBufferDuration(Android 默认 20s,iOS 默认 0 即自动)、waitsToMinimizeStalling(iOS)、minBufferForPlayback(Android 默认 2s)、maxBufferBytes(Android 默认 0 即自动)、prioritizeTimeOverSizeThreshold(Android)。
  • 音频混合模式:2.0.0-preview.1 引入audioMixingMode,取值为mixWithOthers/duckOthers/auto/doNotMix。多播放器并发时按doNotMix > auto > duckOthers > mixWithOthers取最高优先级。Unpublished 段修复了 iOS 默认值——按文档改为auto(原为doNotMix)。
  • Web 专项:1.2.6 支持 Web PiP;1.2.3 修复AudioContext提前创建问题;2.1.5 增加playsInline;2.1.9/3.0.0/3.0.1 围绕crossOrigin反复调整(3.0.0 默认改为anonymous后又回退为undefined);3.0.4 增加实验性useAudioNodePlayback(多实例同时播放时不叠加音量,已知可能破坏部分源的音频);3.0.11 提供nativeRef访问底层HTMLVideoElement;55.0.0 修复旧版 Safari 崩溃。
  • AirPlay(iOS):3.0.0 完整支持,含设备选择按钮组件VideoAirPlayButton(见 src/VideoAirPlayButton.ios.tsx)、isExternalPlaybackActive属性及监听;2.0.0-preview.0 增加allowsExternalPlayback控制。
  • PHAsset 支持(iOS):3.0.11 支持播放PHAssetURI,但只能通过replaceAsync()或默认构造函数加载。
  • Surface 类型(Android):2.1.6 起可通过surfaceType: 'surfaceView' | 'textureView'选择渲染表面,默认surfaceView(功耗更低、性能更好),多视频重叠等场景改用textureView

三、VideoView:视图层能力与控件配置

VideoView是承载播放器的视图组件,核心 props 见 src/VideoView.types.ts:player(可传null,55.0.0 起支持)、nativeControls(默认true;全屏模式下因平台限制始终启用)、contentFitcontain/cover/fill,默认contain)、showsTimecodes(iOS)、requiresLinearPlaybacksurfaceTypecontentPosition(iOS)、allowsVideoFrameAnalysis(iOS 16+,默认true)等。

Android 专属的buttonOptions(即 CHANGELOG 55.0.6 新增的buttonConfiguration,现已重命名)提供细粒度控件可见性控制:

export type ButtonOptions = { showNext?: boolean; // 默认 false(55.0.6 起隐藏) showPrevious?: boolean; // 默认 false showSeekForward?: boolean; // 默认 true showSeekBackward?: boolean;// 默认 true showSubtitles?: boolean | null; // undefined=有字幕时显示 showSettings?: boolean; // 默认 true showPlayPause?: boolean; // 默认 true showBottomBar?: boolean; // 默认 true;全屏下始终可见 };

Unpublished 段新增的controllerAutoShow(Android,默认true)控制原生控件是否在播放开始/暂停/结束时自动显示;设为false后控件不再自动弹出,但仍可点击视图唤起——适合程序化驱动的自动连播列表,避免每次播放时控件闪现。

另外,55.0.6 的PlayerBuilderOptionsseekBackwardIncrement/seekForwardIncrement)会直接作用于原生控件上的快进/快退按钮步长。

四、Hooks 与生命周期:useVideoPlayer / createVideoPlayer

两种创建播放器的方式定义在 src/VideoPlayer.tsx:

  • useVideoPlayer(source, setup?, playerBuilderOptions?):推荐用法,组件卸载时自动释放播放器。实现细节值得注意——当source变化时复用现有播放器调用replaceAsync而非重建(对应 CHANGELOG Unpublished 段的 "When source changes use replaceAsync instead of re-creating the player"),仅当 builder options 变化或replaceAsync失败时才重建实例。
  • createVideoPlayer(source, playerBuilderOptions?):创建不自动释放的直接实例,需手动管理生命周期。

useVideoPlayer的第三个参数playerBuilderOptions对应 Android 原生PlayerBuilderOptions(seek 步长、videoChangeFrameRateStrategy),类型定义见 src/VideoPlayer.types.ts。注意VideoPlayer.replace()在 iOS 上会同步在主线程加载资源并可能长时间阻塞 UI(源码中 JS 层在调用前会打印弃用警告),应优先使用replaceAsync()

五、测试与 Mock:jest-expo 下的可测试性

CHANGELOG Unpublished 段记录了一次重要的测试基础设施修复:修复jest-expo预设下导入expo-videoTypeError: Cannot read properties of undefined (reading 'prototype')的问题——原因是VideoPlayer.tsx在模块加载时对NativeVideoModule.VideoPlayer.prototype.replace打补丁,而自动生成的 mock 表无法表示 SharedObject 类。

修复方案是手写 mock:mocks/ExpoVideo.ts。该文件由jest-expo预设注入到requireNativeModule('ExpoVideo'),实现了带内存状态的VideoPlayer(play/pause/seek/replace 可真实触发状态与事件)与VideoThumbnail,并保持与公共类型定义一致的默认值(如audioMixingMode: 'auto'bufferOptions的跨平台默认值)。文件头注释明确要求不要用expo-modules-test-core重新生成,以免覆盖手写行为。配套的组件测试可参考 src/tests

六、破坏性变更速查:升级前必读

汇总 CHANGELOG 中全部 Breaking changes,按版本排序:

版本破坏性变更应对建议
2.0.0-preview.0事件返回类型改为单对象;volumeChange拆分为volumeChange+mutedChange;iOS/tvOS 最低版本升至 15.1升级useEvent消费方与事件参数解构
1.2.6showNowPlayingNotification默认改为false需要时显式置true
1.2.3PiP 必须通过 config plugin 开启配置supportsPictureInPicture
2.1.9 / 3.0.0 / 3.0.1WebcrossOrigin默认值两次调整,最终为undefined(不启用 CORS)需要 CORS 时显式设置crossOrigin='anonymous'
3.0.5Android 全屏模式始终启用原生控件无需处理,行为对齐 iOS
3.0.9Android Now Playing 通知依赖supportsBackgroundPlayback: true配置 config plugin
55.0.0移除allowsFullscreenprop改用fullscreenOptions.enable
55.0.6Android 原生控件默认隐藏上一首/下一首按钮buttonOptions.showNext/showPrevious重新开启
56.0.0最低版本提升:iOS/tvOS 16.4、macOS 13.4确认工程最低系统版本满足要求
0.2.0AndroidcompileSdkVersion/targetSdkVersion升至 34保持 Gradle 配置同步

依赖层面,Android 侧 media3 依赖持续升级(1.4.0 → 1.8.0 → 1.9.0 → 1.9.1,对应 1.2.6 / 3.0.6 / 56.0.0 / Unpublished 段的版本记录),升级时如遇到 ExoPlayer 相关异常可优先检查依赖版本一致性。

七、结语:从变更日志看 expo-video 的设计取向

回看整个 CHANGELOG,expo-video的演进呈现出三条清晰主线:一是性能与体验打磨——replaceAsync异步加载、iOS 主线程减负、缓存并发与磁盘写满崩溃修复、Seek/Scrubbing 优化,均指向"流畅、不卡主线程"的工程目标;二是企业级媒体能力补齐——DRM、多轨选择、HLS 细节字段、缓存管理 API,使其足以支撑点播/直播类生产应用;三是多端一致性收敛——Android 全屏控件、PiP 行为、audioMixingMode默认值等不断向 iOS 与官方文档对齐。

对开发者而言,升级expo-video前建议:对照本文第六节速查表核查破坏性变更;背景播放与 PiP 功能务必确认 config plugin 配置(plugin/src/withExpoVideo.ts);涉及轨道信息的业务优先消费sourceLoad事件与available*Tracks属性;如需精细的进度条拖动体验,从SeekToleranceScrubbingModeOptions组合调优入手。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 0:10:38

SecureCRT v9.6.2-3540实际使用指南:SSH终端模拟器的会话管理与自动化技巧

简介&#xff1a;这是一份面向网络管理员、运维工程师与开发者的SecureCRT v9.6.2中文汉化移动注册版工具包&#xff0c;解决英文原版界面不友好和安装部署繁琐的问题&#xff0c;内置汉化组件及注册许可&#xff0c;并额外提供单文件版本便于随身携带与快速调用。压缩包内共12…

作者头像 李华
网站建设 2026/9/10 0:10:27

Qt多面板布局进阶:从QDockWidget到高级停靠系统

简介&#xff1a;这是Qt Advanced Docking System&#xff08;Qt高级扩展坞系统&#xff09;的完整源码资源&#xff0c;面向希望构建类似Visual Studio等IDE风格可停靠界面的Qt开发者&#xff0c;适合具备C与Qt基础、需要实现复杂窗口布局管理的中高级用户。包内为核心库源码及…

作者头像 李华
网站建设 2026/9/10 0:09:12

宇视VMS-U门禁权限配置实战:从人员录入到下发排障

在安防项目里&#xff0c;把新来的员工加进VMS-U、把门禁控制器接入平台并下发开门权限&#xff0c;是实施工程师最常碰到的活儿。但每次去现场&#xff0c;总会有人卡在“人员添加了&#xff0c;门禁也配了&#xff0c;就是刷不开”这一步&#xff0c;然后开始怀疑设备坏了、怀…

作者头像 李华
网站建设 2026/9/10 0:06:17

Firefox书签密码丢失怎么办?Profile备份恢复全攻略

上周有个朋友火急火燎地给我发消息&#xff1a;Firefox重启之后&#xff0c;书签、密码、历史记录全没了&#xff0c;浏览器界面像刚装完一样干净。他第一反应是重装浏览器&#xff0c;我赶紧拦住他&#xff0c;这种情况十有八九不是Firefox本身坏了&#xff0c;而是它的用户配…

作者头像 李华