Android M пишет на SD-карту - отказано в разрешении
Я пытаюсь скопировать файл из моего приложения на SD-карту, но получаю сообщение об ошибке (разрешение отклонено). Операционная система - Android M, и я позволил разрешения Хранилища времени выполнения (проверено в информации приложения). Я также установил разрешение на использование в AndroidManifest.xml
<application>...</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Не работает, если я копирую на SD-карту
Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/1032-2568/SomeFolder/
Error: java.io.FileNotFoundException: /storage/1032-2568/SomeFolder/SomeFile.txt: open failed: EACCES (Permission denied)
Работает, если я копирую во внутреннюю память
Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/emulated/0/SomeFolder/
Код для копирования файла из источника в место назначения
/*
* Below are the parameters I have tried
*
* inputPath - data/user/0/com.example.myapp/cache or data/user/0/com.example.myapp/cache/
* inputFile - /SomeFile.txt or SomeFile.txt
* outputPath - /storage/1032-2568/SomeFolder/ or /storage/1032-2568/SomeFolder
*/
public static void copyFile(String inputPath, String inputFile, String outputPath) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File (outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(inputPath + inputFile);
out = new FileOutputStream(outputPath + inputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
}
catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
}
catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
ES File Explorer
Я видел, что ES File Explorer также не может ничего записать на SD-карту на устройствах Redmi. Вот видео с решением. Следующие шаги работали для ES Explorer на моем устройстве. Это можно сделать программно?
8 ответов
В соответствии с предложением @CommonsWare здесь мы должны использовать новую платформу Storage Access Framework, предоставляемую android, и должны будут получить разрешение пользователя на запись файла SD-карты, как вы сказали, это уже записано в ES File Explorer приложения File Manager.
Вот код, позволяющий пользователю выбрать "SD-карту":
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), requestCode);
который будет выглядеть примерно так:
И получите путь к документу в pickedDir
и передайте дальше в свой блок copyFile и используйте этот путь для записи файла:
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode != RESULT_OK)
return;
else {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
copyFile(sdCard.toString(), "/File.txt", path + "/new", pickedDir);
}
}
public void copyFile(String inputPath, String inputFile, String outputPath, DocumentFile pickedDir) {
InputStream in = null;
OutputStream out = null;
try {
//create output directory if it doesn't exist
File dir = new File(outputPath);
if (!dir.exists()) {
dir.mkdirs();
}
in = new FileInputStream(inputPath + inputFile);
//out = new FileOutputStream(outputPath + inputFile);
DocumentFile file = pickedDir.createFile("//MIME type", outputPath);
out = getContentResolver().openOutputStream(file.getUri());
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
// write the output file (You have now copied the file)
out.flush();
out.close();
} catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
Вам нужно добавить время выполнения запроса на разрешение в Android 6.0 (API Level 23) и выше, вот официальные документы
Это код для WRITE_EXTERNAL_STORAGE
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG,"Permission is granted");
return true;
}
Спросите разрешение еще как это
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
Я также получил эту проблему, но я решил с помощью запроса разрешение во время выполнения и после принудительно дать разрешение. После разрешения в информации о приложении устройства Android. после объявления разрешения в манифесте => перейдите к настройке вашего устройства => перейдите к информации о приложении => перейдите к разрешению => и, наконец, разрешите разрешение. просто помните, я только что говорил после того, как API уровня 22 означает зефир.
После Android 4.3 на некоторых устройствах вы не можете получить прямой доступ к FileSystem на SD-карте.
Для этого вы должны использовать структуру доступа к хранилищу.
Кажется, что разрешение времени выполнения реализовано правильно, но проблемы видны с устройства. Если вы используете Redmi, вам нужно вручную разрешить разрешение определенного приложения в настройках безопасности Redmi. Эта ссылка показывает, как включить разрешение в безопасности Redmi.
Я вижу, что вы копируете все содержимое одного файла и пытаетесь записать то же самое в другой файл. Я мог бы предложить лучший способ сделать это:
Предполагая, что вы уже проверили существование файла
StringWriter temp=new StringWriter();
try{
FileInputStream fis=new FileInputStream(inputFile+inputPath);
int i;
while((i=fis.read())!=-1)
{
temp.write((char)i);
}
fis.close();
FileOutputStream fos = new FileOutputStream(outputPath, false); // true or false based on opening mode as appending or writing
fos.write(temp.toString(rs1).getBytes());
fos.close();
}
catch (Exception e){}
Этот код работал для моего приложения... Дайте мне знать, если это работает для вас или нет..
Вы не можете копировать или удалять файлы и папки на внешнем хранилище с помощью стороннего приложения. как [файловый менеджер].
Политика данных обновляется после версии KITKAT.
Если только разрешить в системных приложениях. Таким образом, вы можете использовать оригинальный файловый менеджер (Come from ROM).
Если вам нужно использовать стороннее приложение, то ROOT вашего устройства. (Требуется разрешение root)
Начиная с Api 23 и выше, вам нужно явно запросить разрешения. Как вы уже упоминали, вы запрашиваете разрешение во время выполнения. Я предлагаю вам сделать так:
В вашем фрагменте или деятельности
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_CODE);
else
copyFile(params...);
Затем переопределите этот метод в Activity/Fragment
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
case PERMISSION_CODE:
copyFile(params...);
break;
}
}
// if user checks "don't show again" and presses deny on the permission dialog
// then it will not show up again, in that case you need to show some message to the user
// to go in the settings and enable permissions manually
else if (!ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
ToastManager.showLongToast(getActivity(), "Go to app settings and turn on permissions to enjoy complete features");
}