Marshmallow中的存储权限错误

ful*_*oon 147 permissions android android-6.0-marshmallow

在Lollipop中,下载功能在我的应用程序中运行良好,但是当我升级到Marshmallow时,我的应用程序崩溃并在我尝试从互联网下载到SD卡时出现此错误:

Neither user  nor current process has android.permission.WRITE_EXTERNAL_STORAGE
Run Code Online (Sandbox Code Playgroud)

它抱怨这行代码:

DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
Run Code Online (Sandbox Code Playgroud)

我在应用程序外的清单中拥有权限:

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

我清理并重建了项目,但它仍然崩溃.

Met*_*arf 339

您应该使用以下方法检查用户是否已授予外部存储权限:

if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    Log.v(TAG,"Permission is granted");
    //File write logic here
    return true;
}
Run Code Online (Sandbox Code Playgroud)

如果没有,您需要让用户授予您的应用权限:

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
Run Code Online (Sandbox Code Playgroud)

当然这些仅适用于棉花糖设备,因此您需要检查您的应用是否在Marshmallow上运行:

 if (Build.VERSION.SDK_INT >= 23) {
      //do your check here
 }
Run Code Online (Sandbox Code Playgroud)

还要确保您的活动实施 OnRequestPermissionResult

整个权限如下所示:

public  boolean isStoragePermissionGranted() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG,"Permission is granted");
            return true;
        } else {

            Log.v(TAG,"Permission is revoked");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        Log.v(TAG,"Permission is granted");
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

权限结果回调:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
        Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
        //resume tasks needing this permission
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于API> = 23,请求'Manifest.permission.WRITE_EXTERNAL_STORAGE`的权限始终返回'-1',即权限被拒绝.检查新的文件,上面说的API 19日起,你不需要`WRITE_EXTERNAL_STORAGE`许可.由于上面的一些评论所提到的,你应该做的这一切与`Manifest.permission.READ_EXTERNAL_STORAGE` (14认同)
  • @VSB:它在奇怪的地方,但在这里你去:https://developer.android.com/guide/topics/manifest/uses-permission-element.html (3认同)
  • @AmeyB正如文档所说,对于API> = 19,不需要声明在外部存储上写入的权限**如果**应用程序将在外部存储上使用自己的特定目录,该目录由`getExternalFilesDir()返回.在其他情况下,仍然必须在manfiest中声明"android.permission.WRITE_EXTERNAL_STORAGE"权限. (3认同)
  • @Houssem很乐意提供帮助. (2认同)

Int*_*iya 34

Android的权限系统是最大的安全问题之一,因为在安装时要求这些权限.安装后,应用程序将能够访问所有授予的内容,而无需任何用户确认应用程序对该权限的确切操作.

Android 6.0 Marshmallow通过添加运行时权限引入了权限模型的最大变化之一,这是一种新的权限模型,当您定位API 23并且应用程序在Android 6.0+设备上运行时,该模型将取代现有的安装时权限模型

礼貌用于在运行时请求权限.

将此声明为全局

private static final int PERMISSION_REQUEST_CODE = 1;
Run Code Online (Sandbox Code Playgroud)

在您的onCreate()部分中添加此内容

setContentView(R.layout.your_xml)之后;

 if (Build.VERSION.SDK_INT >= 23)
    {
        if (checkPermission())
        {
            // Code for above or equal 23 API Oriented Device 
            // Your Permission granted already .Do next code
        } else {
            requestPermission(); // Code for permission
        }
    }
  else
    {

       // Code for Below 23 API Oriented Device 
       // Do next code
    }
Run Code Online (Sandbox Code Playgroud)

现在添加 checkPermission()requestPermission()

 private boolean checkPermission() {
    int result = ContextCompat.checkSelfPermission(Your_Activity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (result == PackageManager.PERMISSION_GRANTED) {
        return true;
    } else {
        return false;
    }
}

private void requestPermission() {

    if (ActivityCompat.shouldShowRequestPermissionRationale(Your_Activity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
        Toast.makeText(Your_Activity.this, "Write External Storage permission allows us to do store images. Please allow this permission in App Settings.", Toast.LENGTH_LONG).show();
    } else {
        ActivityCompat.requestPermissions(Your_Activity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.e("value", "Permission Granted, Now you can use local drive .");
            } else {
                Log.e("value", "Permission Denied, You cannot use local drive .");
            }
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

FYI

onRequestPermissionsResult

此接口是接收权限请求结果的合同.


Bip*_*rti 24

检查API级别23中的多个权限第1步:

 String[] permissions = new String[]{
        Manifest.permission.INTERNET,
        Manifest.permission.READ_PHONE_STATE,
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.VIBRATE,
        Manifest.permission.RECORD_AUDIO,
};
Run Code Online (Sandbox Code Playgroud)

第2步:

 private boolean checkPermissions() {
    int result;
    List<String> listPermissionsNeeded = new ArrayList<>();
    for (String p : permissions) {
        result = ContextCompat.checkSelfPermission(this, p);
        if (result != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(p);
        }
    }
    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), 100);
        return false;
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)

第3步:

 @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    if (requestCode == 100) {
        if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // do something
        }
        return;
    }
}
Run Code Online (Sandbox Code Playgroud)

第4步:在onCreate of Activity checkPermissions();

  • 谢谢。对于多个权限,这看起来是一个有希望的答案。但是它缺少一些示例。如何处理“不再询问”并缺少一些权限?用户收到任何反馈吗?如果能在代码片段上看到此示例或更多注释的真实示例,那就太好了。 (2认同)

Muj*_*san 20

除非有明确要求在外部存储上写入,否则您始终可以选择将文件保存在app目录中.在我的情况下,我不得不保存文件,浪费了2至3天后,我发现我是否更改了存储路径

Environment.getExternalStorageDirectory()
Run Code Online (Sandbox Code Playgroud)

getApplicationContext().getFilesDir().getPath() //which returns the internal app files directory path
Run Code Online (Sandbox Code Playgroud)

它在所有设备上都像魅力一样.这是因为要在外部存储上写入,您需要额外的权限,但在内部应用程序目录中编写很简单.


aiw*_*una 5

你需要使用运行时允许在棉花糖 https://developer.android.com/training/permissions/requesting.html

您可以查看应用信息 - >权限

您的应用是否获得写入外部存储的权限

  • 实际上这个答案的应用信息 - >权限解决了崩溃:),但我接受了另一个答案的详细信息.我希望我能接受这两个谢谢你 (2认同)