奥利奥(WRITE EXTERNAL STORAGE)许可

时间:2018-01-09 16:23:13

标签: android permissions

根据"developer.android.com"

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

7 个答案:

答案 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)

如果即使授予了权限并且您已经实施了权限检查,您也会得到拒绝权限错误,

确保您未定位到api级别29:

targetSdkVersion compilesdkversion 29 更改为 28 或其他任何较低级别。


希望这将为某些人节省精神健康和头发。我失去了一些与这种胡说八道作斗争的东西。