Android视频播放器APP:使用Storage Access Framework下载SD卡视频后执行加密操作遭遇权限拒绝问题
解决SD卡环境下视频加密的权限问题
嘿,我一眼就看出问题所在了——你遇到的java.io.FileNotFoundException: ... EACCES (Permission denied)错误,本质是Android 10及以上的分区存储机制限制了对外置SD卡的直接文件访问,哪怕你申请了传统的存储权限也没用。你之前用File和RandomAccessFile直接操作SD卡路径的方式,在内部存储没问题,但SD卡属于共享存储,必须通过你已经在使用的Storage Access Framework(SAF)来操作。
核心原因
从Android 10开始,系统禁止APP直接通过文件路径访问共享存储(包括SD卡)的文件,必须使用SAF提供的Uri和ContentResolver来进行读写操作。你原来的代码直接用File(path)创建文件对象,这在SD卡上会被系统拦截,因为APP没有直接访问该路径的权限。
改造你的加密解密代码
我们需要把方法参数从文件路径改成SAF的Uri,并通过ContentResolver获取文件描述符来操作文件。这里是修改后的代码:
import android.content.ContentResolver; import android.net.Uri; import android.os.ParcelFileDescriptor; import java.io.RandomAccessFile; public class VideoCrypt { public static final int REVERSE_BYTE_COUNT = 1024; // 解密方法:接收ContentResolver和SAF Uri public static boolean decrypt(ContentResolver resolver, Uri fileUri) { try { if (resolver == null || fileUri == null) return false; // 通过SAF获取可读写的文件描述符 ParcelFileDescriptor pfd = resolver.openFileDescriptor(fileUri, "rw"); if (pfd == null) return false; RandomAccessFile f = new RandomAccessFile(pfd.getFileDescriptor(), "rw"); long fileLength = f.length(); int byteToReverse = fileLength < REVERSE_BYTE_COUNT ? ((int) fileLength) : REVERSE_BYTE_COUNT; // 读取开头的字节并反转写入 f.seek(0); byte b[] = new byte[byteToReverse]; f.read(b); f.seek(0); reverseBytes(b); f.write(b); // 关闭资源 f.close(); pfd.close(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } // 加密方法和解密逻辑完全一致(反转两次恢复原数据),直接复用即可 public static boolean encrypt(ContentResolver resolver, Uri fileUri) { return decrypt(resolver, fileUri); } private static void reverseBytes(byte[] array) { if (array == null) return; int i = 0; int j = array.length - 1; byte tmp; while (j > i) { tmp = array[j]; array[j] = array[i]; array[i] = tmp; j--; i++; } } }
使用注意事项
- 传递正确的Uri:你用SAF下载视频时,应该已经获取了该文件的
Uri(比如通过ACTION_CREATE_DOCUMENT创建文件返回的Uri),直接把这个Uri传入encrypt方法即可,不要再转成文件路径。 - 持久化权限:如果需要APP重启后还能访问这个文件,记得在获取Uri后调用
takePersistableUriPermission来保存权限:getContentResolver().takePersistableUriPermission( fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION ); - 权限检查:确保你在使用SAF时已经通过对应的Intent请求了读写权限,而不是依赖传统的
WRITE_EXTERNAL_STORAGE权限。
这样修改后,你的加密解密逻辑就能在SD卡环境下正常运行了,完全符合Android的存储权限规范。
内容的提问来源于stack exchange,提问作者Mukesh Kumar




