You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android视频播放器APP:使用Storage Access Framework下载SD卡视频后执行加密操作遭遇权限拒绝问题

解决SD卡环境下视频加密的权限问题

嘿,我一眼就看出问题所在了——你遇到的java.io.FileNotFoundException: ... EACCES (Permission denied)错误,本质是Android 10及以上的分区存储机制限制了对外置SD卡的直接文件访问,哪怕你申请了传统的存储权限也没用。你之前用FileRandomAccessFile直接操作SD卡路径的方式,在内部存储没问题,但SD卡属于共享存储,必须通过你已经在使用的Storage Access Framework(SAF)来操作。

核心原因

从Android 10开始,系统禁止APP直接通过文件路径访问共享存储(包括SD卡)的文件,必须使用SAF提供的UriContentResolver来进行读写操作。你原来的代码直接用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

火山引擎 最新活动