首次启动时的视频质量很差
最近我把应用从 Expo 48 升级到 Expo 51。
现在一旦在设备上安装并启动应用,视频质量会异常糟糕;但登录并登出后,质量就会恢复。
我该如何防止在首次启动应用时出现糟糕的画质?
注:视频格式为webm,若有其他解决方案,尽量保持此格式。
版本:
"expo": "^51.0.39",
"react-native-video": "^6.18.0",
代码片段:
<Video
key={`${rerenderComp}-${useFallbackVideo ? "fallback" : "file"}`}
source={fileVideoSource}
resizeMode="cover"
repeat={true}
paused={false}
muted={true}
volume={0}
onLoad={onVideoLoad}
onError={onVideoError}
/>
该应用需要24/7全天候运行。
解决方案
这种行为(首次启动画质差,登录/登出后变好)表明在应用/原生层尚未完全就绪时就已经加载了视频。当你登录再退出时,Video 组件会重新挂载并在更好的条件下重新加载。
下面给出一些切实可行的方法:
-
直到应用准备就绪再延迟挂载
-
仅在应用完成初始设置后再渲染视频
``` import { InteractionManager } from 'react-native';
const [isAppReady, setIsAppReady] = useState(false);
useEffect(() => { const task = InteractionManager.runAfterInteractions(() => { // Small delay to ensure native modules/view hierarchy are ready const timer = setTimeout(() => setIsAppReady(true), 100); return () => clearTimeout(timer); }); return () => task.cancel(); }, []);
// Only render Video when ready {isAppReady && (
-
在视频就绪前显示高质量的海报
<Video key={`${rerenderComp}-${useFallbackVideo ? "fallback" : "file"}`} source={fileVideoSource} resizeMode="cover" repeat={true} paused={false} muted={true} volume={0} poster={highQualityPosterUri} // Use a high-res thumbnail/poster posterResizeMode="cover" onReadyForDisplay={onVideoLoad} // Consider using this - fires when first frame is ready onLoad={onVideoLoad} onError={onVideoError} />3.对于HLS:强制更高画质 -
如果使用HLS,播放器可能会从较低分辨率开始。你可以尝试强制使用更高的轨道。
``` import { SelectedVideoTrackType } from 'react-native-video';
``` 4.当应用获得焦点时强制重新挂载(适用于24/7使用)
-
因为应用全天候运行,可以在应用回到前台时重新挂载视频。
``` import { AppState } from 'react-native';
const [videoKey, setVideoKey] = useState(0);
useEffect(() => { const subscription = AppState.addEventListener('change', (nextAppState) => { if (nextAppState === 'active') { setVideoKey(prev => prev + 1); // Force remount when app becomes active } }); return () => subscription.remove(); }, []);
``` import { AppState } from 'react-native';
const [videoKey, setVideoKey] = useState(0);
useEffect(() => { const subscription = AppState.addEventListener('change', (nextAppState) => { if (nextAppState === 'active') { setVideoKey(prev => prev + 1); // Force remount when app becomes active } }); return () => subscription.remove(); }, []);
我最近也没花太多时间在React Native上,因此把这些想法作为起点,可能需要做一些调整。