Подтвердить что ты не робот

Android M записывает на SD-карту - разрешение отклонено

Я пытаюсь скопировать файл из моего приложения на SD-карту, но я получаю сообщение об ошибке eacces (разрешение отклонено). ОС - 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 файлов

Я видел, что ES File Explorer также ничего не может записать на SD-карте на устройствах Redmi. Вот видео с решением. Следуя инструкциям ES Explorer на моем устройстве. Это можно сделать программно?

4b9b3361

Ответ 1

Как было предложено в @CommonsWare здесь, мы должны использовать новую платформу доступа к хранилищу, предоставленную android, и вам нужно будет получить разрешение от пользователя на запись файла SD-карты, как вы сказали, это уже написано в File File Application Application ES File Explorer.

Вот код для того, чтобы позволить пользователю выбрать "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());
    }
}

Ответ 2

Вам нужно добавить время выполнения запроса на разрешение в Android 6.0 (API Level 23) и выше, вот официальный docs

Это код для 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);

Ответ 3

Я вижу, что вы копируете весь контент одного файла и пытаетесь записать его в другой файл. Я мог бы предложить лучший способ сделать это:

Предполагая, что вы уже проверили существование файла

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

Этот код работал для моего приложения... Позвольте мне знать, работает ли это для вас или нет.

Ответ 4

У меня также есть эта проблема, но я решил использовать запрос во время выполнения и после принудительного предоставления разрешения. После разрешения в информации о приложении Android-устройства. после объявления разрешения в манифесте = > перейти к настройке вашего устройства = > перейти к информации о приложении = > перейти к разрешению = > и, наконец, разрешить разрешение. просто помните, что я просто говорю о том, что после уровня 22 уровня api из зефира.

Ответ 5

Кажется, что разрешения на выполнение выполняются правильно, но проблемы возникают с устройства Если вы используете Redmi, вы должны вручную разрешить разрешение определенного приложения в настройках безопасности Redmi Эта ссылка показывает, как включить разрешение в безопасности redmi

Ответ 6

После Android 4.3 на некоторых устройствах вы не можете получить прямой доступ к файловой системе на SDcard.

Для этого вам следует использовать инфраструктуру доступа к хранилищу.

Ответ 7

Вы не можете копировать или удалять файлы и папки на внешнем хранилище с помощью стороннего приложения. как [файл-проводник].

Эта политика данных обновлена ​​после версии KITKAT.

Разрешить только системные приложения. Таким образом, вы можете использовать оригинальный файловый проводник (Come from ROM).

ЕСЛИ вам нужно использовать стороннее приложение, а затем ROOT ваше устройство. (Требуется разрешение Root)

Ответ 8

Из 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");
            }