Android应用raw目录音频共享:自动添加.mp3后缀名求助
我之前也遇到过一模一样的问题!要解决共享raw目录音频时自动添加.mp3后缀的问题,有两个比较实用的方案,你可以根据需求选:
方案一:复制文件到外部存储并重命名(简单易实现)
因为raw目录下的文件是打包在APK里的,直接获取的原生URI不带后缀,所以我们可以先把文件复制到外部存储的私有目录,给文件名加上.mp3后缀,再共享这个副本的URI。
代码示例(Java)
- 先写一个复制raw文件到外部存储的方法:
private File copyRawToExternal(Context context, int rawResId, String originalFileName) { // 获取应用私有音乐目录,Android 10+无需额外权限 File outputDir = context.getExternalFilesDir(Environment.DIRECTORY_MUSIC); if (outputDir == null) return null; // 拼接带.mp3后缀的文件名 File outputFile = new File(outputDir, originalFileName + ".mp3"); try (InputStream rawStream = context.getResources().openRawResource(rawResId); OutputStream fileStream = new FileOutputStream(outputFile)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = rawStream.read(buffer)) != -1) { fileStream.write(buffer, 0, bytesRead); } return outputFile; } catch (IOException e) { e.printStackTrace(); return null; } }
- 调用这个方法并发起分享:
// 替换成你的raw资源ID和原文件名(不带后缀) File sharedAudio = copyRawToExternal(this, R.raw.my_audio, "my_audio"); if (sharedAudio != null) { // 使用FileProvider生成安全URI(Android 7.0+必须) Uri fileUri = FileProvider.getUriForFile(this, "com.your.app.package.fileprovider", sharedAudio); Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("audio/mpeg"); // 指定音频类型 shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri); shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 授予读取权限 startActivity(Intent.createChooser(shareIntent, "分享音频")); }
必要配置
别忘了在AndroidManifest.xml里注册FileProvider:
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.your.app.package.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
然后在res/xml/下创建file_paths.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="music" path="Music/" /> </paths>
方案二:自定义ContentProvider提供带后缀的文件名(无需复制文件)
如果不想复制文件占用存储,可以自定义ContentProvider,在返回文件信息时给文件名加上.mp3后缀,让接收方识别正确的格式。
代码示例(Java)
- 自定义ContentProvider类:
public class RawAudioProvider extends ContentProvider { private static final String AUTHORITY = "com.your.app.package.rawaudioprovider"; public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/audio/"); @Override public boolean onCreate() { return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 返回包含带后缀文件名的Cursor MatrixCursor cursor = new MatrixCursor(new String[]{MediaStore.MediaColumns.DISPLAY_NAME}); String rawFileName = uri.getLastPathSegment(); cursor.addRow(new Object[]{rawFileName + ".mp3"}); return cursor; } @Override public String getType(Uri uri) { return "audio/mpeg"; // 指定MIME类型为MP3 } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { // 根据文件名获取raw资源ID String rawFileName = uri.getLastPathSegment(); int resId = getContext().getResources().getIdentifier(rawFileName, "raw", getContext().getPackageName()); if (resId == 0) throw new FileNotFoundException(); try { InputStream rawStream = getContext().getResources().openRawResource(resId); return ParcelFileDescriptor.fromStream(rawStream); } catch (IOException e) { throw new FileNotFoundException(); } } // 下面这些方法用不到,直接返回默认值即可 @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } }
- 在
AndroidManifest.xml注册这个Provider:
<provider android:name=".RawAudioProvider" android:authorities="com.your.app.package.rawaudioprovider" android:exported="true" android:grantUriPermissions="true" />
- 发起分享:
// 替换成你的raw文件名(不带后缀) Uri audioUri = Uri.parse("content://com.your.app.package.rawaudioprovider/audio/my_audio"); Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("audio/mpeg"); shareIntent.putExtra(Intent.EXTRA_STREAM, audioUri); shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(Intent.createChooser(shareIntent, "分享音频"));
方案对比
- 方案一:代码简单,容易调试,适合大多数场景,尤其是音频文件不大的情况;唯一缺点是会在外部存储生成一个副本。
- 方案二:无需复制文件,节省空间,但需要自定义ContentProvider,代码量更大,适合对存储占用敏感的场景。
内容的提问来源于stack exchange,提问作者Fabiano Melquiades
相关产品推荐
相关产品推荐

