修复expo-media-library加载音频时不弹出权限弹窗问题
Expo调用expo-media-library无权限弹窗、无法读取本地音乐解决方案
问题背景
- 基于Expo开发音乐类移动应用,调用
expo-media-library读取设备本地音乐时,系统权限申请弹窗未弹出,无法获取文件访问权限 - 技术栈版本:
- expo 45.0
- expo-media-library 14.1.0
- react 17.0.2
- react-native 0.68
- 项目仓库地址:https://github.com/MT1607/Project
问题根因
排查代码和配置后,共有4个直接导致问题的错误:
- 生命周期函数拼写错误:组件挂载生命周期写为
componentDidMounth(正确拼写为componentDidMount),导致组件加载后完全没有执行权限申请逻辑 - 方法名拼写不匹配:自定义权限提示弹窗方法定义为
permissionAllert,后续调用时写为permissionAlert,方法名不一致导致逻辑执行报错 - 缺少权限声明配置:Expo项目未在
app.json中声明存储相关权限,系统不会主动弹出权限申请弹窗 - 权限请求逻辑冗余:原代码重复调用两次权限申请接口,存在逻辑冲突
修复方案
1. 补全app.json权限配置
在项目根目录的app.json中添加对应平台的权限声明:
{ "expo": { "android": { "permissions": [ "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE", "READ_MEDIA_AUDIO" ] }, "ios": { "infoPlist": { "NSAppleMusicUsageDescription": "需要访问媒体库以读取本地音乐文件", "NSPhotoLibraryUsageDescription": "需要访问存储以读取本地音乐文件" } } } }
2. 修正AudioProvider组件代码
修复拼写错误、简化冗余逻辑,修正后完整代码如下:
import { Alert } from 'react-native'; import React, { Component, createContext } from 'react'; import * as MediaLibrary from 'expo-media-library'; export const AudioContext = createContext(); export class AudioProvider extends Component { constructor(props) { super(props); this.state = { audioFiles: [] } } permissionAlert = () => { Alert.alert('需要权限', '应用需读取存储权限才能获取本地音乐文件', [ { text: '去授权', onPress: () => this.getPermission(), }, { text: '取消', onPress: () => this.permissionAlert(), }, ]); }; getAudioFiles = async () => { const media = await MediaLibrary.getAssetsAsync({ mediaType: MediaLibrary.MediaType.audio, first: 2000, }) console.log('读取到音频文件数量:', media.assets.length) this.setState({ audioFiles: media.assets }) } getPermission = async () => { const permission = await MediaLibrary.requestPermissionsAsync(); if (permission.granted) { this.getAudioFiles(); return; } if (permission.canAskAgain) { this.permissionAlert() } else { Alert.alert('权限被永久拒绝', '请前往系统设置-应用管理-权限管理中手动开启存储权限') } } componentDidMount() { this.getPermission() } render() { return ( <AudioContext.Provider value={{ audioFiles: this.state.audioFiles }}> {this.props.children} </AudioContext.Provider> ) } } export default AudioProvider
3. 其余组件代码修正
AudioList组件和App入口组件无核心逻辑错误,仅需清理未使用的导入、调整基础样式即可:
// App.js import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import AudioProvider from './app/context/AudioProvider'; import HomeNavigation from './app/navigation/HomeNavigation'; export default function App() { return( <AudioProvider> <NavigationContainer> <HomeNavigation/> </NavigationContainer> </AudioProvider> ) }
// AudioList.js import { Text, StyleSheet, ScrollView } from 'react-native' import React, { Component } from 'react' import { AudioContext } from '../context/AudioProvider' export class AudioList extends Component { static contextType = AudioContext render() { return ( <ScrollView style={styles.container}> {this.context.audioFiles.map(item => <Text key={item.id}>{item.filename}</Text>)} </ScrollView> ) } } const styles = StyleSheet.create({ container:{ flex:1, padding: 16 } }) export default AudioList
生效验证
修改完成后执行以下命令清除缓存并重启开发服务,避免旧配置不生效:
expo start -c
如果是原生构建的项目,执行expo prebuild --clean重新生成原生工程后再编译,首次启动即可正常弹出权限申请弹窗,授权后可正常读取本地音频文件。
内容的提问来源于stack exchange,提问作者Nguyen Gia Son
相关产品推荐
相关产品推荐

