Android:授予写入存储的运行时权限但仍被拒绝(例如 onRequestPermissionsResult)

Android: runtime permission granted for writing in storage but still denied (onRequestPermissionsResult e.g.)

我想使用 public 外部存储在设备中写入图像。因此,我 1) 在清单中编写了权限标记,并且 2) 在需要时使用 checkSelfPermission 来请求权限。但我仍然有这个例外:java.io.FileNotFoundException: /storage/emulated/03b3d97bd-5186-4506-97dc-9994b7ce0761 (Permission denied).

为什么?我已经阅读 https://developer.android.com/guide/topics/permissions/overview#normal-dangerous 但它没有回答我的问题。

形式化问题

我已授予 Android 设备的存储权限。因此,我的条件 if (permissionCheck != PackageManager.PERMISSION_GRANTED) {(见下文)没有正确执行,但它的 else 是。并且此 else 包含一行用于将文件保存在存储中:但是它 returns 这个异常...

来源

目的是在用户授予权限后调用saveImageAndShareIt

清单

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

通常由于写权限,读的应该被隐式识别。

在DialogFragment中

下面是 onRequestPermissionsResult 方法。 saveImageAndShareIt 在用户同意授予权限时调用。

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    System.out.println("onrequestPR");

    if (grantResults.length > 0) {
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            System.out.println("onrequestPR accepted");
            saveImageAndShareIt();
        }
    }
}

onRequestPermissionsResultrequestPermissions 调用,如下所示:

if (Build.VERSION.SDK_INT >= 23) {
    int permissionCheck = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
    } else {
        System.out.println("last_case1");
        saveImageAndShareIt();
        System.out.println("last_case2");
    }
} else {
    System.out.println("peperoni");
    saveImageAndShareIt();
    System.out.println("pizza");
}

所以如果用户已经授予了权限,就不需要调用requestPermissions,直接调用saveImageAndShareIt(也就是说:onRequestPermissionsResult不会需要执行调用saveImageAndShareIt).

saveImageAndShareIt

FileOutputStream.

的实例化引发异常
private void saveImageAndShareIt() {
    OutputStream output;
    try {
        System.out.println("siasi1");
        output = new FileOutputStream(Environment.getExternalStorageDirectory() + image_uuid);
        byte[] buffer = new byte[1024];
        int bytesRead;
        BitmapDrawable bitmapDrawable = (BitmapDrawable) temp.getDrawable();
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmapDrawable.getBitmap().compress(Bitmap.CompressFormat.JPEG, 100, stream);
        byte[] imageInByte = stream.toByteArray();
        ByteArrayInputStream bis = new ByteArrayInputStream(imageInByte);
        while ((bytesRead = bis.read(buffer, 0, buffer.length)) >= 0) {
            output.write(buffer, 0, bytesRead);
        }
        output.close();
        System.out.println("siasi2");
        intent_share.putExtra(Intent.EXTRA_STREAM, Uri.parse(Environment.getExternalStorageDirectory() + image_uuid));
        activity.startActivity(Intent.createChooser(intent_share, "Share to"));
        System.out.println("siasi3");
    } catch(IOException e) {
        e.printStackTrace();
    }
}

堆栈跟踪

W/System.err: java.io.FileNotFoundException: /storage/emulated/03b3d97bd-5186-4506-97dc-9994b7ce0761 (Permission denied) W/System.err: at java.io.FileOutputStream.open0(Native Method) at java.io.FileOutputStream.open(FileOutputStream.java:287) W/System.err: at java.io.FileOutputStream.(FileOutputStream.java:223) W/System.err: at java.io.FileOutputStream.(FileOutputStream.java:110) at com.example...ClipboardDialogFragment.saveImageAndShareIt(ClipboardDialogFragment.java:115) at com.example...ClipboardDialogFragment.access0(ClipboardDialogFragment.java:42) W/System.err: at com.example...ClipboardDialogFragment.onTaskCompleted(ClipboardDialogFragment.java:75) W/System.err: at com.example...DownloadImageTask.onPostExecute(DownloadImageTask.java:34) at com.example...DownloadImageTask.onPostExecute(DownloadImageTask.java:10) W/System.err: at android.os.AsyncTask.finish(AsyncTask.java:695) at android.os.AsyncTask.-wrap1(Unknown Source:0) W/System.err: at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712) W/System.err: at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6944) W/System.err: at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

即使授予了文件权限,您也无法访问 SD 卡和其他可移动媒体。如果我没记错的话,自 KitKat 以来,除非用户在内置文档应用程序中启用了访问权限。

您需要使用 DocumentsProvider or obtain yet another permission/uri through StorageVolume and parse it with DocumentsContract (sample project).

编辑:根据您的例外情况:

 /storage/emulated/03b3d97bd-5186-4506-97dc-9994b7ce0761

默认外部目录是/storage/emulated/0,貌似你忘了在目录名后添加分隔符:

output = new FileOutputStream(Environment.getExternalStorageDirectory() +"/"+ image_uuid);