Android 14读取OBB扩展文件音频遇权限拒绝问题求助
Android 14访问OBB文件权限被拒问题解决
问题根源
Android 14收紧了对OBB扩展文件的访问限制,禁止直接通过Environment.getExternalStorageDirectory()拼接的路径访问OBB目录,必须使用系统提供的StorageManagerAPI来挂载并获取合法的访问路径。
解决方案
1. 配置FileProvider(解决Uri暴露问题)
在AndroidManifest.xml中注册FileProvider,用于生成安全的文件Uri:
<application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> ... </application>
在res/xml目录下创建file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <cache-path name="cache_files" path="/" /> </paths>
2. 修改代码适配Android 14权限规则
替换原有的直接路径访问逻辑,改用StorageManager挂载OBB文件并获取合法路径:
private void playSelectedSong(String songName) { StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE); String obbFileName = "main.1.com.mesbahi.free.player.obb"; // 获取应用专属OBB目录路径,替代硬编码外部存储路径 String obbFilePath = new File(getObbDir(), obbFileName).getAbsolutePath(); ObbInfo obbInfo = storageManager.getObbInfo(obbFilePath); if (obbInfo == null) { sendFileNotFoundBroadcast(); return; } if (!obbInfo.mounted) { // 异步挂载OBB文件 boolean mountSuccess = storageManager.mountObb(obbFilePath, null, new OnObbStateChangeListener() { @Override public void onObbStateChange(String path, int state) { switch (state) { case OnObbStateChangeListener.MOUNTED: processObbFile(storageManager.getMountedObbPath(path), songName); break; case OnObbStateChangeListener.MOUNT_FAILED: sendFileNotFoundBroadcast(); break; } } }); if (!mountSuccess) { sendFileNotFoundBroadcast(); } } else { // OBB已挂载,直接处理 processObbFile(storageManager.getMountedObbPath(obbFilePath), songName); } sendUpdateButtonStateBroadcast(true); } private void processObbFile(String mountedObbPath, String songName) { try { ZipFile obbZipFile = new ZipFile(mountedObbPath); Enumeration<? extends ZipEntry> entries = obbZipFile.entries(); boolean fileFound = false; while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (entry.getName().startsWith(songName)) { InputStream inputStream = obbZipFile.getInputStream(entry); File tempFile = File.createTempFile(songName, "." + getFileExtension(entry), getCacheDir()); FileOutputStream outputStream = new FileOutputStream(tempFile); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } outputStream.close(); inputStream.close(); // 使用FileProvider生成安全Uri,避免Android 7+的FileUriExposedException Uri uri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", tempFile); // 授予媒体播放器读取权限 grantUriPermission("com.android.mediaplayer", uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); MediaItem mediaItem = MediaItem.fromUri(uri); player.setMediaItem(mediaItem); player.prepare(); player.play(); player.setRepeatMode(Player.REPEAT_MODE_ONE); fileFound = true; break; } } if (!fileFound) { sendFileNotFoundBroadcast(); } } catch (IOException e) { e.printStackTrace(); sendFileNotFoundBroadcast(); } } private void sendFileNotFoundBroadcast() { Intent fileNotFoundIntent = new Intent("com.mesbahi.free.player.FILE_NOT_FOUND"); LocalBroadcastManager.getInstance(this).sendBroadcast(fileNotFoundIntent); } private void sendUpdateButtonStateBroadcast(boolean isPlaying) { Intent updateButtonIntent = new Intent("com.mesbahi.free.player.UPDATE_BUTTON_STATE"); updateButtonIntent.putExtra("isPlaying", isPlaying); LocalBroadcastManager.getInstance(this).sendBroadcast(updateButtonIntent); } private String getFileExtension(ZipEntry entry) { String name = entry.getName(); int lastIndexOf = name.lastIndexOf("."); if (lastIndexOf == -1) { return ""; } // 修正原逻辑,返回不带点的扩展名 return name.substring(lastIndexOf + 1); }
关键修改点
- 使用
getObbDir()获取应用专属OBB目录,替代硬编码的外部存储路径 - 通过
StorageManager异步挂载OBB文件,挂载成功后获取合法访问路径 - 用
FileProvider生成安全Uri,解决Android 7+的文件Uri暴露问题 - 抽取重复的广播发送逻辑,提升代码可读性
- 修正扩展名获取逻辑,避免生成冗余的带点文件名
内容的提问来源于stack exchange,提问作者Sami Almesbahi
相关产品推荐
相关产品推荐

