If the app targets Android 8.0 (API level 26), the system grants only
READ_EXTERNAL_STORAGE at that time; however, if the app later requests
WRITE_EXTERNAL_STORAGE, the system immediately grants that privilege
without prompting the user.
现在,我有READ_EXTERNAL_STORAGE,我要求DownloadManager下载公共下载文件夹中的文件
downloadRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, mAttachmentItem.getFilename());
不幸的是,我得到了
E/UncaughtException: java.lang.IllegalStateException: Unable to create directory: /storage/emulated/0/data/user/0/com.abc.cba/files
at android.app.DownloadManager$Request.setDestinationInExternalPublicDir(DownloadManager.java:699)
我已在Manifest中声明了两个权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
读取权限已经被授予,在运行时我正在请求写入权限,系统不会提示任何消息或对话框,它总是在“onRequestPermissionsResult”中被拒绝(未授予)
public static boolean isPermissionsToAccessStorageAreGranted(Context context, Activity activity) {
ArrayList<String> permissions = new ArrayList<>();
if (!PermissionUtil.checkPermissions(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!permissions.isEmpty()) {
String[] permissionsList = permissions.toArray(new String[permissions.size()]);
PermissionUtil.requestPermissions(activity, permissionsList,
PermissionUtil.REQUESTCODE_ACCESS_STORAGE);
return false;
} else {
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode==REQUESTCODE_ACCESS_STORAGE && grantResults[0]== PackageManager.PERMISSION_GRANTED){
/* downloadFile(); */
}
}
我正在尝试通过ADB授予这两个权限,它显示了一个错误:
adb shell pm grant com.abc.cba
android.permission.WRITE_EXTERNAL_STORAGE
Operation not allowed: java.lang.SecurityException: Package com.abc.cbs
has not requested permission android.permission.WRITE_EXTERNAL_STORAGE
adb shell pm grant com.abc.cba
android.permission.READ_EXTERNAL_STORAGE
Operation not allowed: java.lang.SecurityException: Can't change
android.permission.READ_EXTERNAL_STORAGE. It is required by the
application
答案 0 :(得分:16)
实际上,这是一个外部问题。其中一个App Libs我正在使用带有android:maxSdkVersion的WRITE_EXTERNAL_PERMISSION请求。因此,当与我的Manifest合并时,它将删除整个应用程序的权限。
解决方案是添加:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>
答案 1 :(得分:7)
向清单添加权限是正确的:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
对于Lollipop及更高版本,您还需要在运行时请求权限。为了解决这个问题,我创建了一个新方法requestAppPermission
,我在创建主活动时调用它。此方法仅针对Lollipop及更高版本运行,否则提前返回:
private void requestAppPermissions() {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
if (hasReadPermissions() && hasWritePermissions()) {
return;
}
ActivityCompat.requestPermissions(this,
new String[] {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_WRITE_STORAGE_REQUEST_CODE); // your request code
}
private boolean hasReadPermissions() {
return (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
}
private boolean hasWritePermissions() {
return (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
}
我在活动的onCreate
中调用此方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Other things
requestAppPermissions();
}
首次加载时,会提示用户接受权限。
然后,在运行任何需要读取和写入存储的代码之前,您可以通过存储值或使用上面定义的方法hasReadPermissions()
和hasWritePermissions()
再次运行这些检查来检查这些权限
答案 2 :(得分:3)
奥利奥,
即使您已经请求并且被授予了WRITE_EXTERNAL_STORAGE权限,您也需要显式执行READ_EXTERNAL_STORAGE请求(通过代码),反之亦然。
在此之前,当授予WRITE_EXTERNAL_STORAGE时,会自动授予READ_EXTERNAL_STORAGE。
所以你需要做的就是
1)在您的代码中要求 WRITE 权限。
2)当用户授予 WRITE 权限时,再次询问 READ 权限 - 这将自动授予(如果您不要求,则会收到例外情况) 明确阅读)
Oreo的变化对我来说没有多大意义(不知道为什么我们需要请求自动授予的权限),但这就是它。
https://developer.android.com/about/versions/oreo/android-8.0-changes.html#rmp
答案 3 :(得分:2)
使用此
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:remove="android:maxSdkVersion"/>
代替
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE/>"
您的某些第三方库像maxSdkVersion
一样被覆盖com.vungle:publisher-sdk-android
,要查找它们,只需检查清单屏幕下方的Merged Manifest
。参见this
对于SDK 29及更高版本
如果您仍然无法访问外部存储,请考虑在清单的android:requestLegacyExternalStorage="true"
标签中使用<application>
。
答案 4 :(得分:1)
您必须在 Marshmallow 或更高版本的运行时授予权限。 示例代码段:
private static final int REQUEST_WRITE_STORAGE = 112;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
boolean hasPermission = (ContextCompat.checkSelfPermission(getBaseContext(),
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
ActivityCompat.requestPermissions(SplashScreen.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.RECORD_AUDIO, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.INTERNET
},
REQUEST_WRITE_STORAGE);
}else{ startMainActivity(); }
}
希望它有所帮助。
答案 5 :(得分:1)
仅需注意:在Android P上,我必须向要求重新启动应用程序的用户显示一个终止对话框,因为即使在上面编写的所有应用程序都无法读取外部存储,只有重新启动后才可以。认真地说,谷歌的这些家伙每次都会使Android变得更好。 6、8,现在有9的麻烦,又进行了一次如此愚蠢的更新,我将转到iOS:)
答案 6 :(得分:1)
如果即使授予了权限并且您已经实施了权限检查,您也会得到拒绝权限错误,
将 targetSdkVersion 和 compilesdkversion 从 29 更改为 28 或其他任何较低级别。
希望这将为某些人节省精神健康和头发。我失去了一些与这种胡说八道作斗争的东西。