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

Android端下载MP3弹出音频应用列表如何实现直接保存为文件

结论

该需求完全可以实现。当前点击下载按钮后弹出音频应用选择列表,并非下载逻辑本身的问题,是你代码中主动加入的「下载完成后打开文件」逻辑触发的系统行为。

问题原因

你现有代码在Dio下载完成后执行了这行逻辑:

OpenFile.open("${dir.path}/$fileName", type: 'audio/mpeg');

该方法会向系统发起打开MP3音频文件的请求,系统会检索所有注册了音频类型处理能力的应用(Spotify、VLC、系统自带音乐播放器等),当存在多个可处理该类型文件的应用时,就会弹出选择列表。如果仅需要将文件保存到本地、不需要下载完成后自动打开,直接删除这行代码即可,不会再弹出应用选择窗口。

现有代码的Android端兼容性修正

你当前的实现还有两个Android平台适配问题,会导致部分机型下载失败、用户无法在本地找到下载的文件:

  • 权限适配错误:Permission.storage在Android 13(API 33)及以上版本已被废弃,该版本起系统对存储权限做了细分,应用写入公共下载目录在Android 10及以上版本不需要申请任何存储权限,仅Android 9及以下版本需要申请存储写入权限。
  • 存储路径不合理:getApplicationDocumentsDirectory()获取的是应用沙盒私有目录,用户无法通过系统文件管理器直接访问该目录下的文件,如果要让用户能直接在本地找到下载的MP3,需要将文件存储到系统公共下载目录。
修正后的参考代码

首先确认pubspec.yaml中引入所需依赖:

dependencies:
  dio: ^稳定版
  permission_handler: ^稳定版
  path_provider: ^稳定版
  device_info_plus: ^稳定版 # 用于获取系统版本做权限适配

修正后的MobileDownloadService实现:

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:path_provider/path_provider.dart';
import 'package:device_info_plus/device_info_plus.dart';

class MobileDownloadService {
  Future<void> download({required String url, required String fileName}) async {
    // 校验下载权限
    bool hasPermission = await _checkRequiredPermission();
    if (!hasPermission) return;

    // 获取存储路径:Android存公共下载目录,iOS存应用文档目录
    Directory saveDir;
    if (Platform.isAndroid) {
      saveDir = (await getExternalStoragePublicDirectory(StorageDirectory.downloads))!;
    } else {
      saveDir = await getApplicationDocumentsDirectory();
    }
    String savePath = '${saveDir.path}/$fileName';

    // 执行文件下载
    Dio dio = Dio();
    await dio.download(
      url,
      savePath,
      onReceiveProgress: (int received, int total) {
        // 可在此处实现下载进度更新逻辑
      },
    );

    // 已删除原OpenFile.open调用,不会再弹出应用选择窗
    // 可在此处触发UI提示,告知用户文件已保存至下载目录
  }

  Future<bool> _checkRequiredPermission() async {
    if (!Platform.isAndroid) return true;

    AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo;
    int sdkInt = androidInfo.version.sdkInt;
    // Android 10(API 29)及以上写入公共下载目录无需权限
    if (sdkInt >= 29) return true;

    // Android 9及以下申请存储写入权限
    PermissionStatus status = await Permission.storage.request();
    return status.isGranted;
  }
}

另外需要在AndroidManifest.xml的application标签下补充配置,兼容Android 10以下版本的存储访问:

<application
  android:requestLegacyExternalStorage="true"
  ...其他配置>
  ...
</application>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:36:23