奥利奥(写外部存储)许可

Sou*_*enK 17 permissions android

根据"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.
Run Code Online (Sandbox Code Playgroud)

现在,我有READ_EXTERNAL_STORAGE,我正在请求DownloadManager下载Public Download文件夹中的文件

downloadRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, mAttachmentItem.getFilename());
Run Code Online (Sandbox Code Playgroud)

不幸的是,我得到了

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)
Run Code Online (Sandbox Code Playgroud)

我在Manifest中声明了两个权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Run Code Online (Sandbox Code Playgroud)

读取权限已被授予,在运行时我正在请求写入权限,系统不会提示任何消息或对话框,它总是在"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(); */       
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图通过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
Run Code Online (Sandbox Code Playgroud)

Sou*_*enK 25

实际上,这是一个外部问题.我正在使用的App Libs之一请求带有android:maxSdkVersion的WRITE_EXTERNAL_PERMISSION.因此,当与我的Manifest合并时,它将删除整个应用程序的权限.

解决方案是添加:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/> 
Run Code Online (Sandbox Code Playgroud)

  • 在整个周末都遇到了这个bug,这个解决方案很有效. (3认同)

Tin*_*ina 12

您在清单中添加权限是正确的:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Run Code Online (Sandbox Code Playgroud)

对于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);
}
Run Code Online (Sandbox Code Playgroud)

我在活动中调用此方法onCreate:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Other things
    requestAppPermissions();
}
Run Code Online (Sandbox Code Playgroud)

首次加载时,这将提示用户接受权限.

然后,运行,需要读取和写入存储任何代码之前,可以检查这些权限,或者通过存储值或重新运行那些检查用的方法hasReadPermissions()hasWritePermissions()上面所定义.


Joh*_*Doe 6

更新:请参阅此答案以获得更好的解决方案


编辑:这不是解决方案,只是一个快速的解决方法。

如果即使授予权限并且您已经实施了权限检查,您仍然收到权限被拒绝的错误,

确保您不是针对 api 级别 29:

变化targetSdkVersioncompilesdkversion2928或任何其它较低的水平。

  • 这是一个怎样的解决方案——不针对最新的 API?请考虑建议如何在 API 29 中正确实现这一点。 (7认同)

May*_*cia 5

您必须在运行时授予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(); }
        }
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你。


Ang*_*Koh 5

对于奥利奥,

即使您已经请求并被授予 WRITE_EXTERNAL_STORAGE 权限,您也需要明确地执行 READ_EXTERNAL_STORAGE 请求(通过代码),反之亦然。

在此之前,当授予 WRITE_EXTERNAL_STORAGE 时,会自动授予 READ_EXTERNAL_STORAGE。

所以你需要做的是

1)在您的代码中请求WRITE权限。

2) 当用户授予WRITE权限时,再次请求READ权限 - 这将被自动授予(如果您没有明确请求READ,则会出现异常)

Oreo 的更改对我来说没有多大意义(不知道为什么我们需要请求自动授予的权限),但事实就是如此。

https://developer.android.com/about/versions/oreo/android-8.0-changes.html#rmp

  • @svkaka,我认为一般的想法是仅在您需要时才请求许可(例如,仅在用户单击“拍照”按钮时才提示相机/写入权限),而不是在用户打开应用程序时立即询问。 (2认同)