Ошибка разрешения хранения в Зефире
В 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" />
Я очистил и перестроил проект, но он все равно вылетает.
15 ответов
Вы должны проверить, предоставил ли пользователь разрешение внешнего хранилища, используя:
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[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
//resume tasks needing this permission
}
}
Система разрешений 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
Этот интерфейс является контрактом на получение результатов для запросов на разрешение.
Проверка нескольких разрешений на уровне 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();
Если нет определенных требований к записи на внешнее хранилище, вы всегда можете сохранить файлы в каталоге приложения. В моем случае мне нужно было сохранять файлы, и, потратив на это 2-3 дня, я узнал, изменил ли я путь к хранилищу с
Environment.getExternalStorageDirectory()
в
getApplicationContext().getFilesDir().getPath() //which returns the internal app files directory path
это работает как шарм на всех устройствах. Это связано с тем, что для записи во внешнее хранилище требуются дополнительные разрешения, но запись во внутреннем каталоге приложения проста.
Вам нужно использовать разрешение времени выполнения в зефире https://developer.android.com/training/permissions/requesting.html
Вы можете проверить информацию о приложении -> разрешение
ваше приложение получает разрешение на запись во внешнее хранилище или нет
Похоже, пользователь отклонил разрешение, и приложение пытается выполнить запись на внешний диск, что приводит к ошибке.
@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
Начиная с версии "Зефир", разработчики должны запрашивать у пользователя разрешения во время выполнения. Позвольте мне дать вам весь процесс запроса разрешений во время выполнения.
Я использую ссылку здесь: зефир разрешения на выполнение 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();
}
Приведенный выше фрагмент кода запрашивает четыре разрешения одновременно. Вы также можете запросить любое количество разрешений в любой вашей деятельности в соответствии с вашими требованиями.
Самый простой способ, который я нашел, был
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;
}
}
Добавьте приведенный ниже код к вашей функции OnCreate() в MainAcitivity, которая будет отображать всплывающее окно с запросом разрешения:
if (ActivityCompat.shouldShowRequestPermissionRationale(TestActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)){
}
else {
ActivityCompat.requestPermissions(TestActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Log.d(TAG, "Permission granted");
} else {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}
fab.setOnClickListener(v -> {
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.refer_pic);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/*");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(requireActivity().getContentResolver(),
b, "Title", null);
Uri imageUri = Uri.parse(path);
share.putExtra(Intent.EXTRA_STREAM, imageUri);
share.putExtra(Intent.EXTRA_TEXT, "Here is text");
startActivity(Intent.createChooser(share, "Share via"));
});
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;
}
}
}
Это работает для меня
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();
}
}
}
}
Простым способом разрешение может быть предоставлено с помощью файла 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);
Это простой код для получения разрешения.
Перед началом загрузки проверьте разрешения во время выполнения и, если у вас нет разрешения, запросите разрешения, как этот метод
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();
}
}
}
После долгих поисков этот код работает для меня:
Проверьте, есть ли у разрешения: Проверьте разрешение 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();
}
}