尽管有权限,但写入外部存储的权限被拒绝

Permission denied on writing to external storage despite permission

我有一个 Android 7.0 测试设备,我的 APK 目标 = "targetSdkVersion 22",其中:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

与:

final File f = new 
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + "DressUpBaby" + photonumber + ".png");
f.createNewFile();

此时我收到警告:

W/System.err: java.io.IOException: Permission denied

如何获取保存文件?当我在 Eclipse 上创建它时这是有效的,但现在我已经更新并移动到 Android Studio 它似乎已经损坏了一些东西。

如果您 运行 您的应用处于 API 级别 23 或更高级别,您必须在运行时请求权限。

请求许可:

String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions, WRITE_REQUEST_CODE);

然后处理结果:

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
       case WRITE_REQUEST_CODE:
         if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
           //Granted.


         }
       else{
           //Denied.
         }
        break;
    }
}

有关详细信息,请访问 Requesting Permissions at Run Time - Android Doc

Android N 引入了一种新的权限模型,它只在应用真正需要时才请求权限,而不是像以前那样在安装过程中请求权限。

使用以下代码请求权限

注意 - 还要在 Manifest 文件中添加所需的权限

如果您不向 Main Activity 请求权限,请将引用传递给 context/activity

以下示例显示了请求写入外部存储权限的示例,可以同时请求多个权限(google 不推荐)。

public class MainActivity extends AppCompatActivity {
/**
 * Variables for requiesting permissions, API 25+
 */
private int requestCode;
private int grantResults[];


/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {if(ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED ){
        //if you dont have required permissions ask for it (only required for API 23+)
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},requestCode);


        onRequestPermissionsResult(requestCode,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},grantResults);
    }

    @Override // android recommended class to handle permissions
    public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
        switch (requestCode) {
            case 1: {

            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                Log.d("permission","granted");
            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.uujm
                Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();

                //app cannot function without this permission for now so close it...
                onDestroy();
            }
            return;
        }

        // other 'case' line to check fosr other
        // permissions this app might request
    }
}

这是我在类似情况下所做的:

第 1 步:向清单文件添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

第 2 步:创建权限检查函数

void checkForPermissions()
{
    // Here, thisActivity is the current activity
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {

        // Permission is not granted
        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            // Show an explanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.
            // This part I didn't implement,because for my case it isn't needed
            Log.i(TAG,"Unexpected flow");
        } else {
            // No explanation needed; request the permission
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE);

            // MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE is an
            // app-defined int constant. The callback method gets the
            // result of the request.
        }
    } else {
        // Permission is already granted, call the function that does what you need

        onFileWritePermissionGranted();
    }
}

第 3 步:实施 onRequestPermissionsResult

 @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission was granted, yay! 
                    // call the function that does what you need
                    onFileWritePermissionGranted();
                } else {
                    Log.e(TAG, "Write permissions has to be granted tp ATMS, otherwise it cannot operate properly.\n Exiting the program...\n");
                }
                return;
            }

            // other 'case' lines to check for other
            // permissions this app might request.
        }
    }

第四步:使用权限:)

void onFileWritePermissionGranted()
{
   // Write to some file
}

更新:参见以获得更好的解决方案


编辑:对于那些没有时间寻找解决方案的人来说,这只是一种解决方法。 *

如果您收到 permission denied 错误,即使已授予权限并且您已经实施了权限检查,

确保你没有瞄准 api 29 级:

targetSdkVersioncompilesdkversion29更改为28 或任何其他较低级别。

如果您以 SDK 29 为目标,但在成功请求 WRITE_EXTERNAL_STORAGE 权限后仍然出现 "permission denied" 错误,您应该添加

android:requestLegacyExternalStorage="true"

到AndroidManifest.xml中的应用程序定义。

<manifest ... >
  <!-- This attribute is "false" by default on apps targeting
       Android 10 or higher. -->
    <application android:requestLegacyExternalStorage="true" ... >
      ...
    </application>
</manifest>

https://developer.android.com/training/data-storage/compatibility

与“确保你没有瞄准 api 级别 29...”的答案相关,我找到了这个。

https://developer.android.com/reference/android/os/Environment#getExternalStorageDirectory

。。。。。。。。。

“getExternalStoragePublicDirectory”

此方法已在 API 级别 29 中弃用。

为了提高用户隐私,直接访问 shared/external 存储设备已被弃用。当应用面向 Build.VERSION_CODES.Q 时,应用无法再直接访问从此方法返回的路径。通过迁移到 Context#getExternalFilesDir(String)、MediaStore 或 Intent#ACTION_OPEN_DOCUMENT.

等替代方案,应用可以继续访问存储在 shared/external 存储中的内容

。。。。。。。。。

所以,在这种情况下,您必须用其他方法替换“getExternalStoragePublicDirectory”。

在最新版本的 android 中,请求权限有点不同,例如, 如果你想先访问存储权限 您需要向 Manifest.xml

请求访问权限

喜欢:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

最重要的是不要忘记在 Manifets.xml、

的应用程序标签中允许这样做
`android:requestLegacyExternalStorage="true"'

//并从您的 activity 创建方法来请求 运行 权限 在需要的任何地方从 activity 调用此函数。

private boolean requestPermission(){
        boolean request=true;
        String[] permissions={Manifest.permission.CAMERA,
                                Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.READ_EXTERNAL_STORAGE,
                                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                Manifest.permission.ACCESS_COARSE_LOCATION,
                                Manifest.permission.ACCESS_FINE_LOCATION};
        if (permissions.length!=0){
            ActivityCompat.requestPermissions(this,permissions,102);
            request= true;
        }

        else{
            toastMsg("Permissions Denied");
            println("Permissions not allowed by User...");
            request=false;
        }

        return request;

    }