android 为什么MediaProvider间歇性地拒绝外部文件访问权限?

yzckvree  于 2023-10-14  发布在  Android
关注(0)|答案(1)|浏览(522)

在运行Android 13的Pixel 6a上,当创建/访问/删除文件时,我有时会在Logcat日志中获取MediaProvider: Permission to access file storage/emulated/0/Documents/com.myappname/myfilename is denied
为了给予一些上下文,下面的Java代码是在自定义Cordova插件中调用的。之前的测试没有发现这个问题。即使是现在,这种情况也只发生在某些难以界定的情况下。每当它失败时,它就会记录上面的消息,我认为这意味着问题不在于调用它的更高级别的JavaScript和Cordova中间层。
有时Java成功地创建了文件,并阅读了它,但在尝试删除它时失败了,我甚至不能使用Android自己的文件应用程序来丢弃该文件,但后来我可以。
我想也许文件还在缓冲中,并尝试在连续的请求之间引入延迟,尽管这并没有解决它。
我也想知道这是否是一个scoped storage的问题,但为什么它有时会工作,而不是其他?
AndroidManifest.xml:

...
    <uses-sdk
        android:minSdkVersion="24"
        android:targetSdkVersion="33" />
...
    <uses-permission android:name="ANDROID.PERMISSION.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="ANDROID.PERMISSION.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="ANDROID.PERMISSION.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
...

OfflineDataFile.java:

public class OfflineDataFile {  
    
    private final String filePath;

    public OfflineDataFile(Context context) {
        String pkg = context.getPackageName();
        String fileDir = pkg+".OfflineData";
        filePath = "/Documents/" + fileDir;
    }

    private File getAppDir() throws IOException {
        String state = Environment.getExternalStorageState();
        if ( Environment.MEDIA_MOUNTED.equals( state ) ) {
                return new File( Environment.getExternalStorageDirectory() + filePath );
        } else {
            throw new IOException("Could not mount storage");
        }
    }

    public void write(String filename, byte[] data) throws IOException {
        File appDirectory = getAppDir();

        if ( !appDirectory.exists() ) {
            appDirectory.mkdirs();
        }

        File dataFile = new File( appDirectory, filename );
        dataFile.createNewFile();

        FileOutputStream fos = new FileOutputStream(dataFile);
        fos.write(data);
        fos.close();
    }

    public byte[] read(String filename, Integer size) throws IOException {
            
        File appDirectory = getAppDir();

        if ( !appDirectory.exists() ) {
            throw new IOException("Data directory does not exist");
        }

        File dataFile = new File( appDirectory, filename );
        InputStream input = new FileInputStream(dataFile);
        byte [] data = OfflineDataUtil.readInputStream(input, size);
        input.close();
        return data;
    }

    protected void remove(String filename) {
        File appDirectory;

        try {
            appDirectory = getAppDir();
        } catch (IOException e) {           
            return;
        }

        if ( !appDirectory.exists() ) {
            return;
        }

        File dataFile = new File( appDirectory, filename );

        if ( !dataFile.exists() ) {
            return;
        }

        dataFile.delete();
    }

}
rhfm7lfc

rhfm7lfc1#

为了解决这个问题,我决定使用私有外部存储而不是共享外部存储,因为这些文件只在应用程序内部使用,所以我重写了如下(现在根据评论进行编辑)。
OfflineDataFile.java:

public class OfflineDataFile {  
    
    private final File appDir;

    public OfflineDataFile(Context context) throws IOException {
        appDir = context.getExternalFilesDir("OfflineData");
    }

    public void write(String filename, byte[] data) throws IOException {

        File dataFile = new File( appDir, filename );

        FileOutputStream fos = new FileOutputStream(dataFile);
        fos.write(data);
        fos.close();
    }

    public byte[] read(String filename, Integer size) throws IOException {

        File dataFile = new File( appDir, filename );
        
        InputStream input = new FileInputStream(dataFile);
        byte [] data = OfflineDataUtil.readInputStream(input, size);
        input.close();
        
        return data;
    }

    protected void remove(String filename) throws IOException {

        File dataFile = new File( appDir, filename );
        
        if (!dataFile.delete()) {
            throw new IOException("Unable to delete file");
        }
    
    }

}

相关问题