Ошибка разрешения хранилища в Marshmallow
В 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" />
Я очистил и перестроил проект, но все равно сбой.
Ответы
Ответ 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);
Конечно, это только для устройств зефира, поэтому вам нужно проверить, работает ли ваше приложение на Marshmallow:
if (Build.VERSION.SDK_INT >= 23) {
//do your check here
}
Также убедитесь, что ваша активность реализует OnRequestPermissionResult
Полное разрешение выглядит следующим образом:
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
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[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
//resume tasks needing this permission
}
}
Ответ 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
Этот интерфейс - это контракт на получение результатов для запросы на разрешение.
Ответ 3
Если для внешнего хранилища не существует определенного требования, вы всегда можете сохранить файлы в каталоге приложения. В моем случае мне пришлось сохранять файлы, и после траты времени от 2 до 3 дней я узнал, изменил ли я путь хранения из
Environment.getExternalStorageDirectory()
to
getApplicationContext().getFilesDir().getPath() //which returns the internal app files directory path
он работает как шарм на всех устройствах.
Это связано с тем, что для записи на внешнем хранилище вам нужны дополнительные разрешения, но запись во внутреннем каталоге приложения проста.
Ответ 4
Проверить несколько разрешений на уровне 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 of Activity
checkPermissions();
Ответ 5
вам нужно использовать разрешение runtime в marshmallow
https://developer.android.com/training/permissions/requesting.html
вы можете проверить информацию о приложении → разрешение
ваше приложение получает разрешение на запись внешнего хранилища или нет
Ответ 6
Кажется, пользователь отклонил разрешение, и приложение пытается записать на внешний диск, вызывая ошибку.
@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
Ответ 7
После многого поиска Этот код работает для меня:
Проверить разрешение уже есть:
Проверить разрешение 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 метод проверки - это разрешить или запретить пользователю
@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();
}
}
Ответ 8
это сработало для меня
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();
}
}
}
}
Ответ 9
Из версии marshmallow разработчикам необходимо запросить разрешения пользователя во время выполнения.
Позвольте мне дать вам весь процесс для запроса разрешений времени выполнения.
Я использую ссылку отсюда: настройки времени прогона marshmallow 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();
}
Над фрагментом кода запрашивается четыре разрешения за раз. Вы также можете запросить любое количество разрешений в любой вашей деятельности в соответствии с вашими требованиями.
Ответ 10
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;
}
}
}