23

Это касается новой модели runtime permissions introduced in Android Marshmallow при запросе разрешения Manifest.permission.WRITE_EXTERNAL_STORAGE.Запрос и разрешение 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 
    } 
... 
} 

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

+2

«Кто-нибудь испытывает это?» - Я не, но я не пробовал это на эмуляторе. Я использую оборудование. – CommonsWare

+0

Тогда это, скорее всего, будет только на эмуляторе ... Я обновлю, когда получу обновление Android M. – GaRRaPeTa

+1

https://code.google.com/p/android-developer-preview/issues/detail?id=2982 – greywolf82

ответ

7

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

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

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

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

+0

Это только половина правды. К сожалению, некоторые устройства на Lollipop по-прежнему требуют определенных разрешений, поэтому вам следует избегать удаления разрешений на уровне API 19 и выше (я сделал это, и теперь мне нужно его снова ввести). См. Http://stackoverflow.com/questions/27016647/why-do-i-need-the-write-external-storage-permission-with-getexternalcachedir-o?sgp=2 – sven

+0

@sven true.Но, согласно документу, я все еще считаю его ошибкой, хотя на практике я запрашиваю разрешение на хранение. – crazii

+0

@ crazil: 100% согласен. Просто понаблюдайте, чтобы указать на это здесь, чтобы избежать того, чтобы другие разработчики удалили разрешение, просто чтобы узнать, что им нужно будет добавить его снова ... – sven

4

У меня была та же проблема. Оказывается, это, кажется, большая проблема. Изменение разрешения на запись во внешнее хранилище изменяет 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); 

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

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

--- EDIT ---

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

+0

Да, я думаю, это работает и должно быть принято ответ – user755499

+0

Рад это слышать! :) –

+1

Просьба представить образец проекта, который демонстрирует эту проблему. Затем рассмотрите [вопрос о регистрации] (http://b.android.com). Я не вижу ни одного отчета о проблеме, связанного с этим, и я никогда не видел этого поведения в рамках множества приложений. Если проблема ограничена 'canRead()'/'canWrite()', я вижу, возможно, что есть проблема. Но для фактического чтения и записи вам не нужно перезапускать процесс, чтобы получить разрешенное разрешение. – CommonsWare

 Смежные вопросы

  • Нет связанных вопросов^_^