Expo-MediaLibrary选择照片权限下照片加载异常问题求助
问题解决方案
问题根源
当用户在系统设置中修改媒体库权限(从“选择照片”改为“选择更多照片”)后,当前Gallery组件未感知权限变化,也未触发媒体库数据重新拉取,导致新增的可访问照片无法加载,必须重新进入组件才会刷新。
可行解决方案
1. 监听AppState状态,后台返回时刷新数据
用户修改权限需离开App进入系统设置,返回App时触发照片拉取:
// 导入AppState import { AppState } from 'react-native'; // 组件内添加状态与监听 const [appState, setAppState] = useState(AppState.currentState); useEffect(() => { const subscription = AppState.addEventListener('change', nextAppState => { // 从后台回到前台时触发 if (appState.match(/inactive|background/) && nextAppState === 'active') { requestMediaLibraryPermissions(); } setAppState(nextAppState); }); return () => subscription.remove(); }, [appState]);
2. 监听组件焦点(React Navigation)
若用户通过导航返回Gallery组件,监听焦点事件触发刷新:
useEffect(() => { const unsubscribe = navigation.addListener('focus', () => { requestMediaLibraryPermissions(); }); return unsubscribe; }, [navigation]);
3. 实时监听媒体库权限变化
用Expo MediaLibrary的权限监听API,感知权限变更:
useEffect(() => { const listener = MediaLibrary.addPermissionsListener(({ status }) => { if (status === 'granted') { // 权限变更为允许时重置并拉取照片 initPhotos(); fetchPhotos(); } }); return () => listener.remove(); }, []);
优化:合并逻辑避免重复请求
修改fetchPhotos方法支持重置列表,整合监听逻辑:
// 升级fetchPhotos方法 const fetchPhotos = async (cursor?: string | undefined, reset = false) => { setIsLoading(true); try { const { assets, endCursor: newEndCursor, hasNextPage } = await MediaLibrary.getAssetsAsync({ mediaType: MediaLibrary.MediaType.photo, first: 20, after: cursor, }); // 重置则替换列表,否则追加 setPhotos(reset ? assets : prev => [...prev, ...assets]); setEndCursor(newEndCursor); setHasNextPage(hasNextPage); setIsLoading(false); } catch (error) { console.log('Error fetching photos:', error); } }; // 修改权限请求方法 const requestMediaLibraryPermissions = async () => { const { status } = await MediaLibrary.requestPermissionsAsync(); if (status !== 'granted') { console.log('Media library permission denied'); Linking.openSettings(); return; } // 权限通过时重置拉取 fetchPhotos(undefined, true); };
整合后的核心代码片段
const Gallery = ({ navigation, route }: GalleryScreenProps) => { const [photos, setPhotos] = useState<MediaLibrary.Asset[]>([]); const [isLoading, setIsLoading] = useRecoilState(LoadingState); const [hasNextPage, setHasNextPage] = useState<boolean>(false); const [endCursor, setEndCursor] = useState<string | undefined>(undefined); const [selectedPhtos, setSelectedPhtos] = useState<MediaLibrary.Asset[]>([]); const [appState, setAppState] = useState(AppState.currentState); const { limit, callback } = route.params; const requestMediaLibraryPermissions = async () => { const { status } = await MediaLibrary.requestPermissionsAsync(); if (status !== 'granted') { console.log('Media library permission denied'); Linking.openSettings(); return; } fetchPhotos(undefined, true); }; const fetchPhotos = async (cursor?: string | undefined, reset = false) => { setIsLoading(true); try { const { assets, endCursor: newEndCursor, hasNextPage } = await MediaLibrary.getAssetsAsync({ mediaType: MediaLibrary.MediaType.photo, first: 20, after: cursor, }); setPhotos(reset ? assets : prev => [...prev, ...assets]); setEndCursor(newEndCursor); setHasNextPage(hasNextPage); setIsLoading(false); } catch (error) { console.log('Error fetching photos:', error); } }; useEffect(() => { requestMediaLibraryPermissions(); // AppState监听 const appStateSub = AppState.addEventListener('change', nextAppState => { if (appState.match(/inactive|background/) && nextAppState === 'active') { requestMediaLibraryPermissions(); } setAppState(nextAppState); }); // 组件焦点监听 const navSub = navigation.addListener('focus', () => { requestMediaLibraryPermissions(); }); // 权限监听 const permSub = MediaLibrary.addPermissionsListener(({ status }) => { if (status === 'granted') { fetchPhotos(undefined, true); } }); return () => { appStateSub.remove(); navSub(); permSub.remove(); }; }, [appState, navigation]); // 其余组件代码保持不变... };
内容的提问来源于stack exchange,提问作者고윤태
相关产品推荐
相关产品推荐

