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();
}
}
}
onRequestPermissionsResult
被 requestPermissions
调用,如下所示:
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);
我想使用 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();
}
}
}
onRequestPermissionsResult
被 requestPermissions
调用,如下所示:
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);