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

Android端Flutter Method Channel从URI获取音频元数据失败求助

问题分析与解决方案

你遇到的setDataSource failed: status = 0xFFFFFFEA错误,本质是Content URI的处理方式错误:你拿到的content://com.mi.android.globalFileexplorer.myprovider/external_files/song.mp3是Android的内容URI,不是本地文件系统的绝对路径,直接调用intent.getData().getPath()得到的/external_files/song.mp3没有实际文件意义,导致MediaMetadataRetriever无法找到音频文件,触发IO错误。

修正步骤与代码示例

1. 修正变量名错误

你原代码里的变量名存在拼写错误,先修正:

// 错误写法:private MediaMetadataRetriever song details;
private MediaMetadataRetriever songDetails;
// 移除多余的MetadataDetails[]定义(如果不需要的话)
// private MetadataDetails[] songDetails;

2. 使用支持Content URI的setDataSource重载方法

MediaMetadataRetriever提供了直接接收Context和Uri的重载方法,它会通过ContentResolver正确访问内容URI指向的文件:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    songDetails = new MediaMetadataRetriever();
    Intent intent = getIntent();

    new MethodChannel(AudioServicePlugin.getFlutterEngine(this).getDartExecutor().getBinaryMessenger(), CHANNEL)
            .setMethodCallHandler((call, result) -> {
                if (call.method.equals("song")) {
                    if (intent != null && intent.getData() != null) {
                        try {
                            // 直接传入Context和Content URI
                            songDetails.setDataSource(this, intent.getData());
                            
                            // 注意:不能直接返回MediaMetadataRetriever给Flutter,需提取需要的元数据
                            HashMap<String, String> metadata = new HashMap<>();
                            metadata.put("title", songDetails.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
                            metadata.put("artist", songDetails.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
                            metadata.put("duration", songDetails.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
                            
                            result.success(metadata);
                        } catch (IOException e) {
                            e.printStackTrace();
                            result.error("SET_DATA_SOURCE_FAILED", "无法加载音频元数据", e.getMessage());
                        }
                    } else {
                        result.success(null);
                    }
                }
            });
}

3. 备选方案:通过ParcelFileDescriptor访问文件

如果需要使用文件描述符,需通过ContentResolver获取ParcelFileDescriptor,而不是直接用FileInputStream:

if (intent != null && intent.getData() != null) {
    try (ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(intent.getData(), "r")) {
        if (pfd != null) {
            songDetails.setDataSource(pfd.getFileDescriptor());
            // 提取元数据并返回
            HashMap<String, String> metadata = new HashMap<>();
            metadata.put("title", songDetails.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
            result.success(metadata);
        } else {
            result.error("FILE_DESCRIPTOR_NULL", "无法获取文件描述符", null);
        }
    } catch (IOException e) {
        e.printStackTrace();
        result.error("IO_ERROR", "访问音频文件失败", e.getMessage());
    }
}

关键注意点

  • 不要直接将MediaMetadataRetriever对象返回给Flutter:原生对象无法被Flutter序列化,必须提取具体的元数据(如标题、艺术家、时长等)封装成Map或JSON格式返回。
  • 权限问题:通过Intent接收的Content URI,系统已临时授予访问权限,无需额外申请存储权限;如果是主动查询的URI,需确保应用有对应权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 07:31:06