В этой статье мы рассмотрим работу с получением разрешений во время выполнения, которые были добавлены в Android 6 (API 23).
Runtime Permissions в Android API 23. Теория
Одним из основных изменений в Android API 23 является новая система разрешений. В более ранних версиях разрешения объявляли в файле
AndroidManifest.xml
и больше никаких действий не требовалось. Но с Android 6 мы должны запрашивать разрешения из категории «Опасных» во время выполнения.
В документации по работе с разрешениями указано, что их следует получать не все сразу, а по мере необходимости той или иной функции в процессе работы приложения.
Прежде чем запрашивать разрешения, нам нужно описать их в файле
AndroidManifest.xml
.
Процесс получения разрешений:
1). Узнать, получено ли в приложении необходимое разрешение. Например, так:
private boolean isPermissionGranted(String permission) {
// проверяем разрешение - есть ли оно у нашего приложения
int permissionCheck = ActivityCompat.checkSelfPermission(this, permission);
// true - если есть, false - если нет
return permissionCheck == PackageManager.PERMISSION_GRANTED;
}
|
2). Если разрешения нет, то запросить его с помощью метода
requestPermissions()
:
private void requestPermission(String permission, int requestCode) {
// запрашиваем разрешение
ActivityCompat.requestPermissions(this,
new String[]{permission}, requestCode);
}
|
Сразу несколько разрешений можно запросить так:
public void requestMultiplePermissions() {
ActivityCompat.requestPermissions(this,
new String[] {
Manifest.permission.READ_PHONE_STATE
Manifest.permission.READ_SMS
},
PERMISSION_REQUEST_CODE);
}
|
3). Обработать результат запроса на получение разрешений можно так:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
// проверка по запрашиваемому коду
if (requestCode == REQUEST_READ_PHONE_STATE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// разрешение успешно получено
} else {
// разрешение не получено
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
|
Обратите внимание на массив
grantResults[]
— здесь хранятся результаты по каждому из запрашиваемых разрешений. Если в методе requestPermissions()
мы запрашивали 1 разрешение, то обрабатываем только 1 значение массива результатов: grantResults[0]
.
Некоторые разрешения перекочевали в раздел настроек: мы все также описываем их в файле манифеста, однако обрабатывать их нужно уже не внутри приложения, а на странице настроек приложения.
Давайте на примере посмотрим на разные способы получения разрешений.
Runtime Permissions в Android API 23. Практика
В нашем тестовом приложении мы будем получать данные телефона, поэтому нам нужно запрашивать разрешение на получение
Manifest.permission.READ_PHONE_STATE
.
В коде ниже у нас описан весь процесс обработки так называемых «Опасных» разрешений, которые требуют взаимодействия с пользователем. Для начала создайте новый проект в Android Studio.
Идем в файл
AndroidManifest.xml
и добавляем разрешение на работу со звонками:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
Теперь идем в MainActivity.java и описываем процесс получения разрешений и обработку результатов:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
package com.javadevblog.runtimepermissionsapp;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_READ_PHONE_STATE = 10001;
// объявляем разрешение, которое нам нужно получить
private static final String READ_PHONE_STATE_PERMISSION =Manifest.permission.READ_PHONE_STATE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// проверяем разрешения: если они уже есть,
// то приложение продолжает работу в нормальном режиме
if (isPermissionGranted(READ_PHONE_STATE_PERMISSION)) {
Toast.makeText(this, "Разрешения есть, можно работать",Toast.LENGTH_SHORT).show();
} else {
// иначе запрашиваем разрешение у пользователя
requestPermission(READ_PHONE_STATE_PERMISSION,REQUEST_READ_PHONE_STATE);
}
}
private boolean isPermissionGranted(String permission) {
// проверяем разрешение - есть ли оно у нашего приложения
int permissionCheck = ActivityCompat.checkSelfPermission(this, permission);
return permissionCheck == PackageManager.PERMISSION_GRANTED;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
if (requestCode == REQUEST_READ_PHONE_STATE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "Разрешения получены",Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Разрешения не получены",Toast.LENGTH_LONG).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void requestPermission(String permission, int requestCode) {
// запрашиваем разрешение
ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
}
}
|
Если запустить приложение, то получим такой результат:
На первом экране мы запрашиваем разрешение. 2 — успешное их получение. 3 — Разрешение не получено
Задумка с разрешениями сводится к тому, что если пользователь не разрешит приложению доступ к чему-то, то мы должны отключить эту функциональность в приложении и работать с остальным функционалом приложения. А как же быть, если запрашиваемое разрешение является критическим для нашего приложения?
Например, работа со звонками является основой приложения, а пользователь запретил доступ. В этом случае при следующем запуске пользователю следует давать возможность изменить свой выбор, иначе — приложение закрывается. Давайте реализуем эту функциональность в нашем приложении:
Новую функциональность я специально выделил:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
package com.javadevblog.runtimepermissionsapp;
import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_READ_PHONE_STATE = 10001;
// объявляем разрешение, которое нам нужно получить
private static final String READ_PHONE_STATE_PERMISSION =Manifest.permission.READ_PHONE_STATE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// проверяем разрешения: если они уже есть,
// то приложение продолжает работу в нормальном режиме
if (isPermissionGranted(READ_PHONE_STATE_PERMISSION)) {
Toast.makeText(this, "Разрешения есть, можно работать",Toast.LENGTH_SHORT).show();
} else {
// иначе запрашиваем разрешение у пользователя
requestPermission(READ_PHONE_STATE_PERMISSION,REQUEST_READ_PHONE_STATE);
}
}
private boolean isPermissionGranted(String permission) {
// проверяем разрешение - есть ли оно у нашего приложения
int permissionCheck = ActivityCompat.checkSelfPermission(this, permission);
return permissionCheck == PackageManager.PERMISSION_GRANTED;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
if (requestCode == REQUEST_READ_PHONE_STATE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "Разрешения получены",Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Разрешения не получены",Toast.LENGTH_LONG).show();
showPermissionDialog(MainActivity.this);
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void requestPermission(String permission, int requestCode) {
// запрашиваем разрешение
ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
}
private void showPermissionDialog(Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
String title = getResources().getString(R.string.app_name);
builder.setTitle(title);
builder.setMessage(title + " требует разрешение на доступ к звонкам");
String positiveText = "Настройки";
builder.setPositiveButton(positiveText, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
openAppSettings();
}
});
String negativeText = "Выход";
builder.setNegativeButton(negativeText, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
});
AlertDialog dialog = builder.create();
// display dialog
dialog.show();
}
private void openAppSettings() {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_READ_PHONE_STATE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_READ_PHONE_STATE) {
requestApplicationConfig();
}
}
private void requestApplicationConfig() {
if (isPermissionGranted(READ_PHONE_STATE_PERMISSION)) {
Toast.makeText(MainActivity.this, "Теперь уже разрешения получены",Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Пользователь снова не дал нам разрешение",Toast.LENGTH_LONG).show();
requestPermission(READ_PHONE_STATE_PERMISSION,REQUEST_READ_PHONE_STATE);
}
}
}
|
В коде выше мы создали свой AlertDialog, в котором просим пользователя пойти в настройки и все-таки включить нужное разрешение, иначе приложение просто закончит работу.
Запустим приложение на устройстве с Android 6 (API 23) и посмотрим результат:
Результат здесь
Результат здесь
Пользователь отклоняет запрос на получение разрешение, после чего приложение просит его перейти в настройки и все-таки дать разрешения — иначе оно просто закрывается
Исходный код приложения здесь.
Обновляйте свои приложения до API 23 и выше с механизмом Android Runtime Permissions. Подписывайтесь на новые статьи по разработке под Android и Java программированию!
Комментариев нет:
Отправить комментарий