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

Flutter中audioQuery.querySongs()未等待权限授权致崩溃求助

解决audioQuery.querySongs()在权限授予前执行导致的崩溃问题

问题背景

使用audioQuery开发Flutter音乐应用时,audioQuery.querySongs()会在用户完成存储权限授权前提前执行,直接导致应用崩溃。调试日志显示:

W/le.music_playe(29628): Accessing hidden method Landroid/content/ContextWrapper;->getDisplay()Landroid/view/Display; (light greylist, linking)
W/OnAudioQueryPlugin(29628): The application doesn't have access to the library
E/AndroidRuntime(29628): FATAL EXCEPTION: main

初始及修改后的权限检查代码均未解决问题,核心原因是FutureBuilder的异步查询逻辑未等待权限流程完成就已触发。

解决方案

核心思路

通过状态变量标记权限状态,严格控制querySongs()的执行时机,确保仅在权限授予后才执行歌曲查询。

具体修改步骤

  1. 添加权限状态变量
    在State类中新增布尔变量,用于追踪权限是否已授予:
class _HomeState extends State<Home> {
  final audioQuery = OnAudioQuery();
  bool _hasPermission = false; // 新增权限状态标记

  @override
  void initState() {
    super.initState();
    checkPermission();
  }
  // 后续方法
}
  1. 更新权限检查逻辑
    修改checkPermission方法,在权限确认后更新状态变量:
Future<void> checkPermission() async {
  if (!kIsWeb) {
    bool permissionStatus = await audioQuery.permissionsStatus();
    if (!permissionStatus) {
      // 请求权限后更新状态
      permissionStatus = await audioQuery.permissionsRequest();
    }
    setState(() {
      _hasPermission = permissionStatus;
    });
  } else {
    // Web端无需存储权限,直接标记为已授权
    setState(() {
      _hasPermission = true;
    });
  }
}
  1. 控制歌曲查询的执行时机
    修改FutureBuilder,仅在_hasPermission为true时执行querySongs(),否则展示权限提示或加载状态:
FutureBuilder<List<SongModel>>(
  // 仅在权限通过后触发查询
  future: _hasPermission ? audioQuery.querySongs(
    sortType: null,
    orderType: OrderType.ASC_OR_SMALLER,
    uriType: UriType.EXTERNAL,
    ignoreCase: true,
  ) : null,
  builder: (context, snapshot) {
    // 权限未通过时的UI
    if (!_hasPermission) {
      return const Center(child: Text("请授予存储权限以访问音乐"));
    }

    // 处理查询结果
    switch (snapshot.connectionState) {
      case ConnectionState.waiting:
        return const Center(child: CircularProgressIndicator());
      case ConnectionState.done:
        if (snapshot.hasError) {
          return Center(child: Text("加载失败: ${snapshot.error}"));
        }
        final songs = snapshot.data ?? [];
        return ListView.builder(
          itemCount: songs.length,
          itemBuilder: (context, index) {
            return ListTile(title: Text(songs[index].title));
          },
        );
      default:
        return const SizedBox();
    }
  },
)

补充说明

  • 避免直接在FutureBuilder的future参数中写入异步调用,否则组件每次重建都会重复执行查询逻辑;
  • 若用户拒绝权限,可在checkPermission中添加引导逻辑,跳转到应用设置页面开启权限。

内容的提问来源于stack exchange,提问作者Esa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 23:23:12