Записать на SD-карту "java.io.FileNotFoundException: в доступе отказано"

Здесь много похожих вопросов о stackru, но я до сих пор не могу найти решение моей конкретной проблемы:

У меня есть приложение с WRITE_EXTERNAL_STORAGE разрешение и не экспортируемый провайдер файлов

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.cgogolin.library"
      ...
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23" />
      ...
      <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.cgogolin.library.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
      </provider>
</application>

что дополнительно указано в provider_paths.xml как

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <external-path name="external_files" path="."/>
  <root-path name="external_files2" path="/storage/"/>
</paths>

и который я хочу использовать для передачи файлов с SD-карты в другие приложения (в этом случае мое приложение действует более или менее как файловый браузер, но не совсем...).

Поскольку я использую уровень API 23, я также динамически запрашиваю разрешения, вызывая

requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_PERMISSION_REQUEST);

Откроется диалоговое окно, и после того, как я нажму "Разрешить" (и перезапущу приложение из-за ошибки, описанной в " Невозможность записи во внешнее хранилище, если приложение не будет перезапущено после предоставления разрешения), приложение правильно получает разрешения, которые я могу проверить". проверяя,

android.support.v4.content.ContextCompat.checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED

и это действительно так. Я также могу получить Uri к File файл с SDCard с чем-то вроде

Uri uri = android.support.v4.content.FileProvider.getUriForFile(context, "com.cgogolin.library.fileprovider", file);

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

Но: несмотря на наличие разрешений на запись, я не могу записать в файл. Все попытки открыть OutputStream или же ParcelFileDescriptor в uri с любым из следующих

context.getContentResolver().openOutputStream(uri, "wa");
context.getContentResolver().openFileDescriptor(uri, "wa");

либо прямо из моего приложения, либо из приложения, открытого через Intent привести к

java.io.FileNotFoundException: Permission denied

Где моя ошибка? Я думал что после checkSelfPermission() говорит мне, что у меня есть WRITE_EXTERNAL_STORAGE Я должен быть в состоянии сделать это.

2 ответа

Ответ заключается в том, чтобы позволить пользователю давать приложениям права на запись через Intent.ACTION_OPEN_DOCUMENT_TREE для всей SDCard (или соответствующего подкаталога), как предлагается также в этом посте Разрешение на запись на SD-карту Android с использованием SAF (Storage Access Framework).

и который я хочу использовать для обслуживания файлов с SDCard для других приложений

Во-первых, нет документированных root-path на FileProvider,

Во-вторых, у вас нет доступа для чтения или записи к съемному хранилищу за пределами очень определенных мест (например, 2-е и последующие значения, возвращаемые getExternalFilesDirs()). Разрешения внешнего хранилища не имеют ничего общего со съемным хранилищем.