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

Neither user  nor current process has android.permission.WRITE_EXTERNAL_STORAGE


它抱怨以下代码行:

DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);


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

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


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

评论

试试这个可能对您有帮助:-stackoverflow.com/a/41221852/5488468

我已经准备了一个库,它将有助于轻松地处理运行时权限。 github.com/nabinbhandari/Android-Permissions

#1 楼

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

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


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

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);


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

 if (Build.VERSION.SDK_INT >= 23) {
      //do your check here
 }


还请确保您的活动实现了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;
    }
}


权限结果回调:

@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
    }
}


评论


@侯赛姆很乐意提供帮助。

– MetaSnarf
16年6月23日在5:55

这不适用于API> = 23的情况,请求Manifest.permission.WRITE_EXTERNAL_STORAGE的权限始终返回“ -1”,即权限被拒绝。查看新文档,它说从API 19开始,您不需要WRITE_EXTERNAL_STORAGE权限。如上述一些评论所述,您应该使用Manifest.permission.READ_EXTERNAL_STORAGE来完成所有这些操作

– AmeyaB
16年8月1日在22:01

@VSB:它位于怪异的地方,但您可以前往:developer.android.com/guide/topics/manifest/…

– AmeyaB
16-10-18在19:54



@AmeyB正如文档所述,对于API> = 19,不需要声明对外部存储的写入权限,前提是应用程序要在外部存储上使用其自己的特定目录,该目录由getExternalFilesDir()返回。在其他情况下,必须先声明android.permission.WRITE_EXTERNAL_STORAGE权限。

–VSB
16-10-19在4:57

是的,它固定了。问题与曲棍球应用程序库有关。这个库已经覆盖了我的写权限。 @MetaSnarf

– Selin
18-11-19在13:34



#2 楼


Android的权限系统是所有人最大的安全隐患之一,因为这些权限是在安装时要求的。一旦安装了
,应用程序将能够访问所有授予的内容
,而无需任何用户的确认,
正是该应用程序在权限下的用途。

Android 6.0 Marshmallow引入了对
权限模型进行的最大更改之一是添加了运行时权限,这是一个新的
权限模型,当您以API 23为目标并且应用运行时,该模型将替换现有的安装时间权限
模型。在Android 6.0+设备上



礼貌转到运行时请求权限。

示例

声明此作为全局

private static final int PERMISSION_REQUEST_CODE = 1;


将其添加到您的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
    }


现在添加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;
    }
}


FYI

onRequestPermissionsResult


此接口是接收结果f的合同或
权限请求。


#3 楼

在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,
};


步骤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;
}


>第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;
    }
}


第4步:
活动的onCreate创建
checkPermissions();

评论


谢谢。对于多个权限,这看起来是一个有希望的答案。但是它缺少一些示例。如何处理不再询问且缺少一些权限?用户会收到任何反馈吗?在代码片段中看到此示例或更多注释的真实示例会很高兴。

–not2qubit
17年1月18日在17:43

要处理,不要再询问是否使用if(shouldshowpermissionrationaleale()){}来阻止添加到权限...这是事实,是否需要权限而不是永远将其关闭

–me_
18年6月20日在4:54

这个应该是正确和优化的答案。

–VikaS GuttE
19-10-25在14:26

#4 楼

除非有明确的外部存储写入要求,否则您始终可以选择将文件保存在应用程序目录中。就我而言,我不得不保存文件,浪费了2至3天后,我发现是否可以将存储路径从

Environment.getExternalStorageDirectory()


更改为

getApplicationContext().getFilesDir().getPath() //which returns the internal app files directory path


在所有设备上都可以正常运行。
这是因为要在外部存储上进行写操作,您需要额外的权限,但是在内部应用程序目录中写操作很简单。

评论


您在哪里编写此代码?我不记得在我的代码上使用Environment.getExternalStorageDiretory()

–royjavelosa
17年11月30日在14:03

#5 楼

您需要在棉花糖中使用运行时权限
https://developer.android.com/training/permissions/requesting.html

您可以签入应用程序信息->权限

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

评论


实际上,此答案应用程序信息->权限解决了崩溃问题:),但是我接受了其他答案以了解操作细节。我希望我能接受两个人

–巴德
2015年10月16日,下午4:32

感谢修复了浏览器崩溃在Android模拟器中下载问题

–sdaffa23fdsf
15年11月15日在22:35

#6 楼


#7 楼

从棉花糖版本开始,开发人员需要向用户请求运行时权限。
让我为您提供询问运行时权限的整个过程。

我在这里使用参考:棉花糖运行时权限android。 br />
首先创建一个方法,该方法检查是否所有权限都已赋予

private  boolean checkAndRequestPermissions() {
        int camerapermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        int writepermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        int permissionLocation = ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION);
        int permissionRecordAudio = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);


        List<String> listPermissionsNeeded = new ArrayList<>();

        if (camerapermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.CAMERA);
        }
        if (writepermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        if (permissionLocation != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        if (permissionRecordAudio != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.RECORD_AUDIO);
        }
        if (!listPermissionsNeeded.isEmpty()) {
            ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
            return false;
        }
        return true;
    } 


现在,这是在上述方法之后运行的代码。我们将覆盖onRequestPermissionsResult()方法:

 @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        Log.d(TAG, "Permission callback called-------");
        switch (requestCode) {
            case REQUEST_ID_MULTIPLE_PERMISSIONS: {

                Map<String, Integer> perms = new HashMap<>();
                // Initialize the map with both permissions
                perms.put(Manifest.permission.CAMERA, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.RECORD_AUDIO, PackageManager.PERMISSION_GRANTED);
                // Fill with actual results from user
                if (grantResults.length > 0) {
                    for (int i = 0; i < permissions.length; i++)
                        perms.put(permissions[i], grantResults[i]);
                    // Check for both permissions
                    if (perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
                            && perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED 
&& perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED 
&& perms.get(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
                        Log.d(TAG, "sms & location services permission granted");
                        // process the normal flow
                        Intent i = new Intent(MainActivity.this, WelcomeActivity.class);
                        startActivity(i);
                        finish();
                        //else any one or both the permissions are not granted
                    } else {
                        Log.d(TAG, "Some permissions are not granted ask again ");
                        //permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
//                        // shouldShowRequestPermissionRationale will return true
                        //show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
                        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) 
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) 
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)
 || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
                            showDialogOK("Service Permissions are required for this app",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            switch (which) {
                                                case DialogInterface.BUTTON_POSITIVE:
                                                    checkAndRequestPermissions();
                                                    break;
                                                case DialogInterface.BUTTON_NEGATIVE:
                                                    // proceed with logic by disabling the related features or quit the app.
                                                    finish();
                                                    break;
                                            }
                                        }
                                    });
                        }
                        //permission is denied (and never ask again is  checked)
                        //shouldShowRequestPermissionRationale will return false
                        else {
                            explain("You need to give some mandatory permissions to continue. Do you want to go to app settings?");
                            //                            //proceed with logic by disabling the related features or quit the app.
                        }
                    }
                }
            }
        }

    }


如果用户单击“拒绝”选项,则showDialogOK()方法将用于显示对话框

如果用户单击拒绝,然后单击一个复选框“不再询问”,则将使用explain()方法显示对话框。

显示对话框的方法:

 private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", okListener)
                .create()
                .show();
    }
    private void explain(String msg){
        final android.support.v7.app.AlertDialog.Builder dialog = new android.support.v7.app.AlertDialog.Builder(this);
        dialog.setMessage(msg)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        //  permissionsclass.requestPermission(type,code);
                        startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:com.exampledemo.parsaniahardik.marshmallowpermission")));
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        finish();
                    }
                });
        dialog.show();
    }


以上代码段一次要求四个权限。您还可以根据需要在任何活动中请求任意数量的权限。

#8 楼

   Try this



int permission = ContextCompat.checkSelfPermission(MainActivity.this,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE);

     if (permission != PackageManager.PERMISSION_GRANTED) {
                Log.i("grant", "Permission to record denied");

                if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setMessage(getString(R.string.permsg))
                            .setTitle(getString(R.string.permtitle));

                    builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int id) {
                            Log.i("grant", "Clicked");
                            makeRequest();
                        }
                    });

                    AlertDialog dialog = builder.create();
                    dialog.show();

                } else {

                    //makeRequest1();
                    makeRequest();
                }
            }


     protected void makeRequest() {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    500);
        }



     @Override
        public void onRequestPermissionsResult(int requestCode,
                                               String permissions[], int[] grantResults) {
            switch (requestCode) {
                case 500: {

                    if (grantResults.length == 0
                            || grantResults[0] !=
                            PackageManager.PERMISSION_GRANTED) {

                        Log.i("1", "Permission has been denied by user");

                    } else {

                        Log.i("1", "Permission has been granted by user");

                    }
                    return;
                }

            }
        }


#9 楼

经过大量搜索后,此代码为我工作:

检查权限是否已具有:
检查WRITE_EXTERNAL_STORAGE权限是否允许?

if(isReadStorageAllowed()){
            //If permission is already having then showing the toast
            //Toast.makeText(SplashActivity.this,"You already have the permission",Toast.LENGTH_LONG).show();
            //Existing the method with return
            return;
        }else{
            requestStoragePermission();
        }



private boolean isReadStorageAllowed() {
    //Getting the permission status
    int result = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);

    //If permission is granted returning true
    if (result == PackageManager.PERMISSION_GRANTED)
        return true;

    //If permission is not granted returning false
    return false;
}

//Requesting permission
private void requestStoragePermission(){

    if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)){
        //If the user has denied the permission previously your code will come to this block
        //Here you can explain why you need this permission
        //Explain here why you need this permission
    }

    //And finally ask for the permission
    ActivityCompat.requestPermissions(this,new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_WRITE_STORAGE);
}


实施覆盖onRequestPermissionsResult方法用于检查用户是否允许或拒绝

 @Override
 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    //Checking the request code of our request
    if(requestCode == REQUEST_WRITE_STORAGE){

        //If permission is granted
        if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){

            //Displaying a toast
            Toast.makeText(this,"Permission granted now you can read the storage",Toast.LENGTH_LONG).show();

        }else{
            //Displaying another toast if permission is not granted
            Toast.makeText(this,"Oops you just denied the permission",Toast.LENGTH_LONG).show();
        }
    }


#10 楼

对我有用

 boolean hasPermission = (ContextCompat.checkSelfPermission(AddContactActivity.this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
    if (!hasPermission) {
        ActivityCompat.requestPermissions(AddContactActivity.this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_WRITE_STORAGE);
    }

   @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode)
    {
        case REQUEST_WRITE_STORAGE: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                //reload my activity with permission granted or use the features what required the permission
            } else
            {
                Toast.makeText(AddContactActivity.this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
            }
        }
    }

}


#11 楼

在开始下载之前,请检查您的运行时权限,如果没有权限,则使用类似此方法的请求权限

requestStoragePermission()

private void requestStoragePermission(){
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, 
                android.Manifest.permission.READ_EXTERNAL_STORAGE))
        {

        }

        ActivityCompat.requestPermissions(this, 
            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            STORAGE_PERMISSION_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, 
                @NonNull String[] permissions, 
                @NonNull int[] grantResults) {

    if(requestCode == STORAGE_PERMISSION_CODE){
        if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
        }
        else{
            Toast.makeText(this,
                           "Oops you just denied the permission", 
                           Toast.LENGTH_LONG).show();
        }
    }
}


#12 楼

可以使用manifest.xml文件以简单的方式授予许可,但是直到api级别23 sdk版本6都是可以的,从这里开始,如果我们要获得许可,我们必须要求允许使用该许可

只需将此代码添加到mainActivity.java中。

Override
            public void onClick(View view) {
                // Request the permission
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.CAMERA},
                        PERMISSION_REQUEST_CAMERA);


如果需要,请替换相机或添加WRITE_EXTERNAL_STORAGE,并添加唯一的代码。

                            new String[]{Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    101);


这是获得许可的简单代码。

#13 楼

我找到的最简单的方法是
private boolean checkPermissions(){
    if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
        return true;
    }
    else {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_CODE);
        return false;
    }
}


#14 楼

将以下代码添加到MainAcitivity中的OnCreate()函数中,该函数将显示弹出窗口以请求权限:
if (ActivityCompat.shouldShowRequestPermissionRationale(TestActivity.this,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)){
}
else {
     ActivityCompat.requestPermissions(TestActivity.this,
                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                            100);
}