Помилка дозволу на зберігання в Marshmallow


159

У Lollipop функціонал завантаження працює в моєму додатку, але коли я перейшов до Marshmallow, мій додаток виходить з ладу і видає цю помилку, коли я намагаюся завантажити з Інтернету на карту 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
Bipin Bharti

Я підготував бібліотеку, яка допоможе легко обробляти дозволи на виконання. github.com/nabinbhandari/Android-Permissions
Nabin Bhandari

Відповіді:


357

Ви повинні перевірити, чи надав користувач дозвіл на зовнішнє зберігання, використовуючи:

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

2
@Houssem радий допомогти.!
MetaSnarf

14
Це не працює для API> = 23, вимагаючи дозволу на Manifest.permission.WRITE_EXTERNAL_STORAGEзавжди повернення '-1', тобто дозволу відмовлено. Перевірте нову документацію, там написано, що для API 19 і далі вам не потрібен WRITE_EXTERNAL_STORAGEдозвіл. Як згадувалося в деяких вищезазначених коментарях, ви повинні зробити все це за допомогоюManifest.permission.READ_EXTERNAL_STORAGE
AmeyaB

3
@VSB: Його в дивному місці, але ось ви йдете: developer.android.com/guide/topics/manifest/…
AmeyaB

3
@AmeyB Як сказано в документації, для API> = 19 дозвіл на запис на зовнішній сховище не потрібно оголошувати, якщо програма IF буде використовувати свою власну специфічну директорію на зовнішньому сховищі, до якої повертається getExternalFilesDir(). В інших випадках все-таки дозвіл android.permission.WRITE_EXTERNAL_STORAGEповинен бути оголошений у manfiest.
VSB

1
Так, це виправлено. Проблема була пов’язана з бібліотекою хокейних додатків. ця бібліотека змінила мій дозвіл на запис. @MetaSnarf
Селін

38

Система дозволів 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

Цей інтерфейс є договором на отримання результатів для запитів на дозвіл.


29

Перевірте декілька дозволів на рівні 23 API. Крок 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 of Activity checkPermissions ();


2
Дякую. Це виглядає як багатообіцяюча відповідь на кілька дозволів. Але бракує прикладів трохи. Як це стосується never ask againта не має кількох дозволів? Чи отримує користувач відгуки? Було б приємно побачити реальний приклад цього чи більше коментарів до ваших фрагментів коду.
not2qubit

Для вирішення проблем не запитуйте знову оточення додати до дозволів, якщо заблокувати з if (shouldshowpermissionrationale ()) {} ... це правда, якщо дозвіл потрібен, а не назавжди відхилений
me_

Це має бути правильною та оптимізованою відповіддю.
VikaS GuttE

21

Якщо немає певної вимоги писати на зовнішньому сховищі, ви завжди можете зберегти файли в каталозі додатків. У моєму випадку мені довелося зберігати файли, і, витрачаючи 2 - 3 дні, я дізнався, чи зміню шлях зберігання

Environment.getExternalStorageDirectory()

до

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

це працює як шарм на всіх пристроях. Це тому, що для написання на зовнішньому сховищі потрібні додаткові дозволи, але писати у внутрішній каталог додатків просто.


де ти пишеш цей код? Я не можу згадати використання Environment.getExternalStorageDiretory () у своєму коді
royjavelosa

5

вам потрібно скористатися дозволом виконання в зефірі https://developer.android.com/training/permissions/requesting.html

ви можете перевірити інформацію про програму -> дозвіл

це ваш додаток отримати дозвіл на запис зовнішнього сховища чи ні


2
насправді ця інформація про програму відповідей -> дозвіл вирішив аварію :), але я прийняв іншу відповідь для деталей, що робити. Я хочу, щоб я міг прийняти обидва спасибі ua
Badr

Завдяки тому, що виправлена ​​помилка браузера щодо проблеми завантаження в емуляторі Android
sdaffa23fdsf

4

Здається, користувач відмовився від дозволу і програма намагається записати на зовнішній диск, викликаючи помилку.

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

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

Перевірте https://developer.android.com/training/permissions/requesting.html

Це відео дасть вам краще уявлення про UX, обробку дозволів виконання https://www.youtube.com/watch?v=iZqDdvhTZj0


1

З версії зефіру розробникам потрібно запитувати права доступу до користувача. Дозвольте надати вам весь процес запиту дозволів на виконання.

Я використовую тут посилання: дозволи на виконання зефіру для Android .

Спочатку створіть метод, який перевіряє, чи надано всі дозволи чи ні

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();
    }

Вище фрагмент коду запитує чотири дозволи одночасно. Ви також можете запитати будь-яку кількість дозволів у будь-якій діяльності відповідно до ваших вимог.


0

Після багатьох пошуків Цей код працює для мене:

Перевірка дозволу вже є: Перевірити 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);
}

Реалізувати метод Override onRequestPermissionsResult для перевірки - це дозвіл користувача чи denie

 @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();
        }
    }

0

це працює для мене

 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();
            }
        }
    }

}

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

            }
        }

0

Перш ніж розпочати завантаження, перевірте свої дозволи на виконання та якщо у вас немає дозволу на запит дозволів, як цей метод

запитStoragePermission ()

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();
        }
    }
}

0

Простим способом дозвіл можна надати за допомогою файлу 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);

Замініть CAMERA або додайте WRITE_EXTERNAL_STORAGE, якщо хочете, та унікальним кодом.

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

Це простий код для отримання дозволу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.