Запрос и разрешение WRITE_EXTERNAL_STORAGE во время выполнения не влияет на текущий сеанс

Это касается новой модели разрешений во время выполнения, введенных в Android Marshmallow при запросе разрешения Manifest.permission.WRITE_EXTERNAL_STORAGE .

Короче говоря, то, что я испытываю, заключается в том, что если я запрошу (и пользователь разрешает) разрешение Manifest.permission.WRITE_EXTERNAL_STORAGE , приложение не сможет читать и писать из внешнего каталога хранилища, пока я не уничтожу и не перезапущу приложение .

Это то, что я делаю / испытываю:

Мое приложение начинается с состояния, в котором:

 ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED 

Это значит, что у меня нет прав доступа к внешнему хранилищу.

Затем я запрашиваю разрешение Manifest.permission.WRITE_EXTERNAL_STORAGE, как объясняет Google

 private void requestWriteExternalStoragePermission() { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { new AlertDialog.Builder(this) .setTitle("Inform and request") .setMessage("You need to enable permissions, bla bla bla") .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCompat.requestPermissions(MendeleyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_PERMISSION_WRITE_EXTERNAL_STORAGE); } }) .show(); } else { ActivityCompat.requestPermissions(MendeleyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_PERMISSION_WRITE_EXTERNAL_STORAGE); } } 

Как только пользователь разрешает разрешение, вызывается onRequestPermissionsResult .

 @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case RC_PERMISSION_WRITE_EXTERNAL_STORAGE: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && PackageManager.PERMISSION_GRANTED // allowed } else { // denied } break; } } } 

allowed блок выполняется, подтверждая, что пользователь предоставил разрешения.

Сразу же после этого, если я не уничтожу и не открою приложение снова, у меня все еще нет доступа к внешнему хранилищу. Более конкретно:

 hasWriteExternalStoragePermission(); // returns true Environment.getExternalStorageDirectory().canRead(); // RETURNS FALSE!! Environment.getExternalStorageDirectory().canWrite(); // RETURNS FALSE!! 

Итак, кажется, что среда выполнения Android думает, что у меня есть разрешения, но файловая система не … Действительно, попытка доступа к Environment.getExternalStorageDirectory() выдает исключение:

 android.system.ErrnoException: open failed: EACCES (Permission denied) at libcore.io.Posix.open(Native Method) at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186) at libcore.io.IoBridge.open(IoBridge.java:438) at java.io.FileOutputStream.<init>(FileOutputStream.java:87) at java.io.FileOutputStream.<init>(FileOutputStream.java:72) 

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

Кто-нибудь испытывает это?

Я использую один официальный эмулятор с:

  • Последний Android 6.0 (API 23) API 23, Rev 1.
  • Эмулятор, работающий под управлением Intel X86 Atom System Image, API 23, Rev 1.

Я создаю приложение с помощью:

 android { compileSdkVersion 23 buildToolsVersion "22.0.1" defaultConfig { minSdkVersion 16 targetSdkVersion 23 } ... } 

Если кто-то подтвердит это, и я не единственный, я думаю, нам нужно будет открыть ошибку, но я надеюсь, что что-то сделаю неправильно, так как я думаю, что такая основная функция вряд ли будет ошибкой в ​​SDK.

Solutions Collecting From Web of "Запрос и разрешение WRITE_EXTERNAL_STORAGE во время выполнения не влияет на текущий сеанс"

http://developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE :

Начиная с уровня API 19, это разрешение не требуется для чтения / записи файлов в ваших каталогах приложений, возвращаемых getExternalFilesDir (String) и getExternalCacheDir ().

«Запрос на разрешение времени выполнения» начинается с уровня API 23, очевидно, выше 19, поэтому разрешение больше не требуется, если только вы не получаете доступ к данным за пределами папки, на которую указывает getExternalFilesDir (). Поэтому я считаю, что это ошибка эмулятора.

На нижних объектах ниже уровня 19, которые не поддерживают запрашиваемое разрешение во время выполнения, просто уточните разрешение в манифесте, и оно будет работать.

У меня такая же проблема. Оказывается, это, кажется, большая проблема. Изменение разрешения на запись во внешнее хранилище изменяет GID для этого процесса (на стороне Linux). Чтобы изменить идентификатор, процесс необходимо перезапустить. В следующий раз, когда вы откроете приложение, будет установлен новый идентификатор groupID и будет предоставлено разрешение.

Короче говоря, я боюсь, что это не ошибка в эмуляторе, а на самом деле большая проблема с Linux и Android.

Я «решил» это, запросив разрешение при первом запуске приложения и перезапустив его, когда это разрешение указано так:

 PackageManager packageManager = getPackageManager(); Intent intent = packageManager.getLaunchIntentForPackage(getPackageName()); ComponentName componentName = intent.getComponent(); Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName); startActivity(mainIntent); System.exit(0); 

Вы можете попытаться создать службу, работающую в фоновом режиме (с другим идентификатором процесса), и предоставить ей разрешение. Таким образом вам нужно будет только перезапустить службу, а не полное приложение. С нижней стороны это может сделать больше работы для вас.

Надеюсь это поможет.

— РЕДАКТИРОВАТЬ —

Пользователь M66B ( https://stackoverflow.com/a/32473449/1565635 ) нашел список связанных показателей. Дополнительную информацию можно найти здесь: https://android.googlesource.com/platform/frameworks/base/+/master/data/etc/platform.xml