这是关于请求Manifest.permission.WRITE_EXTERNAL_STORAGE
权限时的新型号的runtime permissions introduced in Android Marshmallow。
简而言之,我遇到的情况是,如果我请求(并且用户允许) Manifest.permission.WRITE_EXTERNAL_STORAGE
权限,应用程序将无法从外部存储目录中读取和写入,直到我销毁并重新启动应用程序。
这就是我正在做的/正在经历的:
我的应用程序从一种状态开始:
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
这就是说,我没有访问外部存储的权限。
然后,我请求Manifest.permission.WRITE_EXTERNAL_STORAGE的许可,就像谷歌解释的那样
private void requestWriteExternalStoragePermission() {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(this)
.setTitle("Inform and request")
.setMessage("You need to enable permissions, bla bla bla")
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MendeleyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_PERMISSION_WRITE_EXTERNAL_STORAGE);
}
})
.show();
} else {
ActivityCompat.requestPermissions(MendeleyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_PERMISSION_WRITE_EXTERNAL_STORAGE);
}
}
一旦用户允许该权限,就会调用onRequestPermissionsResult
。
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case RC_PERMISSION_WRITE_EXTERNAL_STORAGE: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && PackageManager.PERMISSION_GRANTED
// allowed
} else {
// denied
}
break;
}
}
}
执行allowed
块,确认用户已被授予权限。
在此之后立即,如果我不销毁并再次打开应用程序,我仍然没有访问外部存储的权限。更确切地说:
hasWriteExternalStoragePermission(); // returns true
Environment.getExternalStorageDirectory().canRead(); // RETURNS FALSE!!
Environment.getExternalStorageDirectory().canWrite(); // RETURNS FALSE!!
所以,看起来Android运行时认为我有权限,但文件系统没有...实际上,尝试访问Environment.getExternalStorageDirectory()
会抛出一个异常:
android.system.ErrnoException: open failed: EACCES (Permission denied)
at libcore.io.Posix.open(Native Method)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
at libcore.io.IoBridge.open(IoBridge.java:438)
at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
如果我现在销毁应用程序,并再次打开它的,行为变得像它应该,能够读取和写入外部存储文件夹。
有没有人遇到过这种情况?
我使用了一个官方的模拟器:
我用以下命令构建应用程序:
android {
compileSdkVersion 23
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
}
...
}
如果有人确认了这一点,我想我们需要打开一个bug,但我希望我做错了什么,因为我认为这样的核心功能在SDK中不太可能有bug。
发布于 2015-10-22 12:02:55
http://developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE
从API level 19开始,在由getExternalFilesDir(String)和getExternalCacheDir()返回的特定于应用程序的目录中读/写文件不需要此权限。
运行时权限开始于API23级,显然高于19级,因此不再需要该权限,除非您正在访问getExternalFilesDir()
所指向的文件夹之外的数据。因此,我认为这是一个只有在模拟器上测试时才会出现的错误。
在19级以下的目标上,不支持在运行时请求权限,只需在清单中声明权限,它就会工作。
发布于 2016-05-10 17:56:19
我也有同样的问题。事实证明这似乎是一个更大的问题。更改写入外部存储的权限会更改此进程的GID (在linux端)。为了更改ID,必须重新启动该进程。下次打开应用程序时,将设置新的groupID并授予权限。
长话短说,恐怕这不是模拟器中的bug,而是Linux和Android的一个更大的问题。
我“解决”了这个问题,在应用程序第一次执行时请求许可,当许可如下时重新启动它:
PackageManager packageManager = getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(getPackageName());
ComponentName componentName = intent.getComponent();
Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName);
startActivity(mainIntent);
System.exit(0);
您可以尝试创建一个在后台运行的服务(具有另一个进程id),并为其提供权限。这样,你只需要重新启动服务,而不是整个应用程序。在不好的方面,这可能会给你带来更多的工作。
希望这能有所帮助。
编辑--
用户M66B (https://stackoverflow.com/a/32473449/1565635)找到了相关gids的列表。欲了解更多信息,请点击此处:https://android.googlesource.com/platform/frameworks/base/+/master/data/etc/platform.xml。
发布于 2020-09-02 22:05:44
用于安卓10+的
在我的例子中,它是:
如果目标是Android 10
(API29级)或更高级别,请在应用程序的AndroidManifest
文件中将requestLegacyExternalStorage
的值设置为true。只需将以下代码添加到您的Application
块中。
<application
android:requestLegacyExternalStorage="true"
... >
https://stackoverflow.com/questions/32947638
复制相似问题