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

时间:2018-12-01 18:02:54

标签: android android-permissions

我想使用公共外部存储在设备中写入图像。因此,我有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包含一行以将文件保存到存储中:但是它返回此异常...

来源

目标是在用户授予许可后致电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(权限   W / System.err:at java.io.FileOutputStream.open0(Native   方法)           在java.io.FileOutputStream.open(FileOutputStream.java:287)W / System.err:在   java.io.FileOutputStream。(FileOutputStream.java:223)   W / System.err:位于   java.io.FileOutputStream。(FileOutputStream.java:110)           在com.example ... ClipboardDialogFragment.saveImageAndShareIt(ClipboardDialogFragment.java:115)           在com.example ... ClipboardDialogFragment.access $ 300(ClipboardDialogFragment.java:42)   W / System.err:位于   com.example ... ClipboardDialogFragment $ 1 $ 2 $ 1.onTaskCompleted(ClipboardDialogFragment.java:75)   W / System.err:位于   com.example ... DownloadImageTask.onPostExecute(DownloadImageTask.java:34)           在com.example ... DownloadImageTask.onPostExecute(DownloadImageTask.java:10)   W / System.err:位于android.os.AsyncTask.finish(AsyncTask.java:695)           在android.os.AsyncTask.-wrap1(未知来源:0)W / System.err:在   android.os.AsyncTask $ InternalHandler.handleMessage(AsyncTask.java:712)   W / System.err:位于   android.os.Handler.dispatchMessage(Handler.java:105)           在android.os.Looper.loop(Looper.java:164)           android.app.ActivityThread.main(ActivityThread.java:6944)W / System.err:java.lang.reflect.Method.invoke(本机方法)           在com.android.internal.os.Zygote $ MethodAndArgsCaller.run(Zygote.java:327)           在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

1 个答案:

答案 0 :(得分:2)

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

您需要使用DocumentsProvider或通过StorageVolume获得另一个权限/ uri,并使用DocumentsContractsample project)进行解析。

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

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

默认外部目录为/storage/emulated/0,看起来您忘记在目录名称后添加分隔符:

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