You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修复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个直接导致问题的错误:

  1. 生命周期函数拼写错误:组件挂载生命周期写为componentDidMounth(正确拼写为componentDidMount),导致组件加载后完全没有执行权限申请逻辑
  2. 方法名拼写不匹配:自定义权限提示弹窗方法定义为permissionAllert,后续调用时写为permissionAlert,方法名不一致导致逻辑执行报错
  3. 缺少权限声明配置:Expo项目未在app.json中声明存储相关权限,系统不会主动弹出权限申请弹窗
  4. 权限请求逻辑冗余:原代码重复调用两次权限申请接口,存在逻辑冲突

修复方案

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:01:26