Проблема
В системе Android 6 и более поздних версиях необходимо проверять разрешения во время выполнения приложения, а также указывать их в манифесте.
Опасными называются ресурсы, которые могут повлиять на сохранность или конфиденциальность информации пользователя и т.д. Для доступа к ресурсам, защищенным опасными разрешениями, необходимо:
- убедиться, что пользователь уже предоставил разрешение до доступа к ресурсу;
- явно запросить разрешения у пользователя, если они ранее не были предоставлены;
- иметь альтернативный план действий, чтобы приложение не вышло из строя, если разрешение не будет предоставлено.
Обсуждение
Для доступа к ресурсу, требующему разрешения, необходимо сначала проверить, предоставил ли пользователь разрешение. Для этого вызовите из класса Activity метод checkSelfPermission
(permission
). Он вернет константы PERMISSION_GRANTED
ИЛИ PERMISSION_DENIED
.
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
PackageManager.PERMISSION_GRANTED) {
// Если вы оказались в этой точке, значит вы получили разрешение и можете что-то сделать
} else {
// См. ниже
}
Если предыдущая проверка указывает, что разрешение не было предоставлено, необходимо явно запросить его, вызвав из класса Activity
метод requestPermissions()
:
void requestPermissions (String[] permissions, int requestCode)
Поскольку этот метод будет взаимодействовать с пользователем, он представляет собой асинхронный запрос. Чтобы получить уведомление об ответе, необходимо переопределить метод onRequestPermissionsResult()
в классе Activity
.
public void onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults);
Например:
// Уникальный код запроса на конкретное разрешение private
private static int REQUEST_EXTERNAL_STORAGE = 1;
...
// Запрос на разрешение для пользователя
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE },
REQUEST_EXTERNAL_STORAGE);
// Обработчик обратного вызова для окончательного ответа
@Override
public void onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
boolean granted = true;
if (requestCode == REQUEST_EXTERNAL_STORAGE) {
// Результат полученного разрешения на внешнее хранение
Log.i(TAG, "Got response for external storage permission request.");
// Проверяем, все ли разрешения получены
if (grantResults.length > 0 ) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
granted = false;
}
}
} else {
granted = false;
}
}
...
// Если переменная granted равна true, выполните активность. Вызов метода
// checkSelfPermission() вернет константу PackageManager.PERMISSION_GRANTED
Как правило, рекомендуется предоставить пользователю информацию о том, зачем нужны разрешения. Для этого из класса Activity
вызывается метод boolean should ShowRequestPermissionRationale(String permission)
. Если пользователь ранее отказался предоставить разрешения, то этот метод вернет значение true
, предоставив вам возможность отобразить дополнительную информацию о том, почему они должны быть предоставлены.
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// Предоставляет дополнительную информацию, если разрешение
// не было дано, а пользователь должен получить разъяснения
Log.i(TAG, "Displaying permission rationale to provide additional context.");
Snackbar.make(mLayout, R.string.external_storage_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View view) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_EXTERNAL_STORAGE);
}
}).show();
Этот метод использует класс Snackbar
, чтобы отобразить разъяснения, пока пользователь не щелкнет на элементе Snackbar, чтобы его отклонить.
Дополнительную информацию можно получить на официальном сайте документации https://developer.android.com/training/permissions/requesting.html.
URL-адрес для загрузки исходного кода
Исходный код этого примера находится в репозитории github.com, в подкаталоге PermissionRequest
(см. раздел “Получение и использование примеров кода” предисловия).