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

Android 11下设置音频文件为铃声原有代码失效问题求助

问题成因
  • Android 11开始分区存储强制生效,requestLegacyExternalStorage仅在targetSdkVersion ≤29时有效,当targetSdkVersion ≥30时该配置完全失效,应用无法通过传统File类直接操作公共目录下的媒体文件元数据。
  • MediaStore.MediaColumns.DATA字段在Android 10之后就已被官方废弃,系统不再信任第三方应用传入的本地路径值,导致你插入媒体库的音频元数据无法和实际文件关联,系统只能用媒体库条目ID作为名称展示,就是你看到的数字串。
  • 你代码中给MediaStore.Audio.Media.ARTIST传入的是R.string.app_name,这是int类型的资源ID而非实际的字符串值,存入媒体库的就是数字资源ID,也会导致名称显示异常。
解决方案

1. 调整文件写入+媒体库插入逻辑

不要先写本地文件再插入媒体库,改为先向MediaStore申请插入条目拿到Uri,再通过该Uri打开输出流写入音频数据,完全适配分区存储规则,示例代码如下:

// 适配Android 11+的音频保存+插入媒体库逻辑
ContentResolver mCr = v.getContext().getContentResolver();
ContentValues values = new ContentValues();
// 不需要填写已废弃的DATA字段
values.put(MediaStore.MediaColumns.TITLE, name + ".mp3");
values.put(MediaStore.MediaColumns.DISPLAY_NAME, name + ".mp3");
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mpeg");
values.put(MediaStore.Audio.Media.ARTIST, v.getContext().getString(R.string.app_name)); // 资源ID转字符串
values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
values.put(MediaStore.Audio.Media.IS_ALARM, false);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_RINGTONES); // 指定存储到铃声目录

// 先插入媒体库拿到专属Uri
Uri audioUri = mCr.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
if (audioUri == null) {
    Toast.makeText(v.getContext(), "创建音频条目失败", Toast.LENGTH_SHORT).show();
    return;
}

// 通过Uri打开输出流写入音频数据
try {
    AssetFileDescriptor soundFile = mCr.openAssetFileDescriptor(mUri, "r");
    if (soundFile == null) return;
    FileInputStream fis = soundFile.createInputStream();
    OutputStream fos = mCr.openOutputStream(audioUri);
    byte[] buffer = new byte[1024];
    int len;
    while ((len = fis.read(buffer)) != -1) {
        fos.write(buffer, 0, len);
    }
    fos.close();
    fis.close();
    soundFile.close();
} catch (IOException e) {
    // 写入失败删除无效的媒体库条目
    mCr.delete(audioUri, null, null);
    e.printStackTrace();
}

2. 调整铃声设置逻辑

拿到上面生成的audioUri直接设置为铃声即可,原有逻辑基本不需要修改,可增加媒体扫描触发操作确保系统更新索引:

try {
    if (checkSystemWritePermission()) {
        RingtoneManager.setActualDefaultRingtoneUri(popUp.this, RingtoneManager.TYPE_RINGTONE, audioUri);
        // 触发系统媒体扫描更新索引,避免名称显示延迟
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, audioUri));
        Toast.makeText(popUp.this, "设置铃声成功", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(popUp.this, "请开启修改系统设置权限", Toast.LENGTH_LONG).show();
    }
} catch (Exception e) {
    Log.i("rington",e.toString());
    Toast.makeText(popUp.this, "设置铃声失败", Toast.LENGTH_SHORT).show();
}

3. 权限配置补充

如果你的应用targetSdkVersion ≥33,还需要在AndroidManifest.xml中补充音频读取权限:

<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 13:54:04