[:ru]В этом уроке мы рассмотрим, что такое запросы разрешений во время исполнения приложения и как с ними работать. Я покажу, как инициировать запрос разрешения, как обрабатывать ответы пользователя, а также что делать, если пользователь отказал в разрешении и установил флаг «больше не спрашивать» в диалоге запроса разрешения.

Кто не в теме, немного теории:

Как вы помните, до версии Android 6.0 все запрашиваемые разрешения отображались пользователю при установке приложения. И если пользователь не предоставлял приложению хотя бы одно разрешение из списка, приложение не устанавливалось.

Теперь все изменилось.

Начиная с Android API 23 разрешения поделили на обычные (normal) и опасные (dangerous).

Обычные разрешения — это те, которые не несут прямой угрозы конфиденциальности пользователя. К ним относятся разрешения на доступ к интернету и сетевым соединениям, доступ к беспроводным модулям, управлению оповещениями, звуком и т.д.

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

Полный список обычных и опасных разрешений можно посмотреть по ссылке.

Во вторых, в связи с этим изменилось поведение приложений при установке, и здесь возможны варианты.

Например, рассмотрим случай, когда устройство работает под управлением Android версии 5.1 или ниже, или целевая версия SDK в файле сборки приложения имеет значение 22 или ниже.

Если же устройство работает под управлением Android 6.0 или выше, или целевая версия SDK установлена на 23 или выше, то приложение может быть установлено без запросов разрешений. Но при этом ему будут предоставлены только обычные, безопасные разрешения.

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

Теперь давайте рассмотрим пример работы с разрешениями на практике.

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

Исходный код этого проекта вы можете посмотреть ниже:

В макете экрана одна кнопка.

activity_main.xml

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version=«1.0»encoding=«utf-8» <android.support.constraint.ConstraintLayout xmlns:android=«http://schemas.android.com/apk/res/android» xmlns:tools=«http://schemas.android.com/tools» android:layout_width=«match_parent» android:layout_height=«match_parent» android:id=«@+id/activity_view» tools:context=«info.fandroid.runtimepermissions.MainActivity»> <Button android:layout_width=«wrap_content» android:id=«@+id/btn» android:text=«make folder» android:layout_height=«wrap_content»/> </android.support.constraint.ConstraintLayout>

Starting from Android 6.0 (API 23), users are not asked for permissions at the time of installation rather developers need to request for the permissions at the run time. Only the permissions that are defined in the manifest file can be requested at run time.

Types of Permissions:

  1. Install-Time Permissions: If the Android 5.1.1 (API 22) or lower, the permission is requested at the installation time at the Google Play Store.

    If the user Accepts the permissions, the app is installed. Else the app installation is cancelled.

  2. Run-Time Permissions: If the Android 6 (API 23) or higher, the permission is requested at the run time during the runnnig of the app.

    If the user Accepts the permissions, then that feature of the app can be used. Else to use the feature, the app requests the permission again.

So, now the permissions are requested at runtime. In this article, we will discuss how to request permissions in an Android Application at run time.

Steps for Requesting permissions at run time :

  1. Declare the permission in Android Manifest file: In Android permissions are declared in AndroidManifest.xml file using the uses-permission tag.

    Here we are declaring storage and camera permission.

  2. Modify activity_main.xml file to Add two buttons to request permission on button click: Permission will be checked and requested on button click. Open activity_main.xml file and add two buttons in it.
  3. Check whether permission is already granted or not. If permission isn’t already granted, request user for the permission: In order to use any service or feature, the permissions are required. Hence we have to ensure that the permissions are given for that. If not, then the permissions are requested.

    Check for permissions: Beginning with Android 6.0 (API level 23), the user has the right to revoke permissions from any app at any time, even if the app targets a lower API level. So to use the service, the app needs to check for permissions every time.

    Syntax:

      if(ContextCompat.checkSelfPermission(thisActivity,                        Manifest.permission.WRITE_CALENDAR)     != PackageManager.PERMISSION_GRANTED)   {      // Permission is not granted  }  

    Request Permissions: When PERMISSION_DENIED is returned from the checkSelfPermission() method in the above syntax, we need to prompt the user for that permission. Android provides several methods that can be used to request permission, such as requestPermissions().

    Syntax:

      ActivityCompat.requestPermissions(MainActivity.this,                                     permissionArray,                                     requestCode);    Here permissionArray is an array of type String.  

    Example:

    publicvoidcheckPermission(String permission, intrequestCode) {             if(ContextCompat.checkSelfPermission(             MainActivity.this,             permission)         == PackageManager.PERMISSION_DENIED) {         ActivityCompat             .requestPermissions(                 MainActivity.this,                 newString[] { permission },                 requestCode);     }     else{         Toast             .makeText(MainActivity.this,                       "Permission already granted",                       Toast.LENGTH_SHORT)             .show();     } }

    This function will show a toast message if permission is already granted otherwise prompt user for permission.

  4. Override onRequestPermissionsResult() method:onRequestPermissionsResult() is called when user grant or decline the permission. RequestCode is one of the parameteres of this function which is used to check user action for corresponding request. Here a toast message is shown indicating the permission and user action.

    Example:

       @Override publicvoidonRequestPermissionsResult(intrequestCode,                                        @NonNullString[] permissions,                                        @NonNullint[] grantResults) {     super         .onRequestPermissionsResult(requestCode,                                     permissions,                                     grantResults);        if(requestCode == CAMERA_PERMISSION_CODE) {                     if(grantResults.length >             && grantResults[] == PackageManager.PERMISSION_GRANTED) {                             Toast.makeText(MainActivity.this,                            "Camera Permission Granted",                            Toast.LENGTH_SHORT)                 .show();         }         else{             Toast.makeText(MainActivity.this,                            "Camera Permission Denied",                            Toast.LENGTH_SHORT)                 .show();         }     }     elseif(requestCode == STORAGE_PERMISSION_CODE) {         if(grantResults.length >             && grantResults[] == PackageManager.PERMISSION_GRANTED) {             Toast.makeText(MainActivity.this,                            "Storage Permission Granted",                            Toast.LENGTH_SHORT)                 .show();         }         else{             Toast.makeText(MainActivity.this,                            "Storage Permission Denied",                            Toast.LENGTH_SHORT)                 .show();         }     } }

Below is the complete code of this application:

Output:

    On starting the application:
  • On clicking camera button for first time:
  • On Granting the permission:
  • On clicking camera button again:

My Personal Notesarrow_drop_up

Recommended Posts:

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the «Improve Article» button below.

Операционная система Android устроена таким образом, что для выполнения некоторых операций или доступа к определенным ресурсам, приложение должно иметь разрешение на это.

Разрешения могут быть двух типов: normal и dangerous. Отличие между ними в том, что dangerous разрешения опасны, т.к. могут быть использованы для получения ваших личных данных или информации о вас, или еще каким-то способом могут навредить вам. Примеры dangerous разрешений — это доступ к контактам или смс.

Полный список существующих разрешений можно посмотреть здесь. Характеристика Protection level подскажет насколько опасно это разрешение. А здесь можно сразу просмотреть весь список normal разрешений.

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

Вот пример манифеста с разрешениями:

Здесь мы указываем, что приложению понадобятся разрешения на работу с интернет, контактами, bluetooth, локацией, камерой и смс. Пользователю необходимо будет подтвердить, что он предоставляет приложению эти разрешения.

В этом материале мы подробно рассмотрим, как происходит это подтверждение.

До Android 6

До выхода Android 6 все было просто и легко. Когда пользователь устанавливал приложение с манифестом, который мы рассмотрели чуть выше, то он видел такой экран:

Система показывает разрешения, которые были прописаны в манифесте. Сначала те, которые могут быть опасными с точки зрения приватности (отправка смс, доступ к камере/местоположению/контактам), а затем — обычные (интернет, bluetooth).

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

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

Если же в манифесте не указать разрешение READ_CONTACTS, то его не будет и в списке тех разрешений, которые подтверждает пользователь. Соответственно, система не предоставит этому приложению доступ к контактам. И при попытке получить список контактов, будет ошибка:java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2

Android 6

С выходом Android 6 механизм подтверждения поменялся. Теперь при установке приложения пользователь больше не видит списка запрашиваемых разрешений. Приложение автоматически получает все требуемые normal разрешения, а dangerous разрешения необходимо будет программно запрашивать в процессе работы приложения.

Т.е. теперь недостаточно просто указать в манифесте, что вам нужен, например, доступ к контактам. Когда вы в коде попытаетесь запросить список контактов, то получите ошибку SecurityException: Permission Denial. Потому что вы явно не запрашивали это разрешение, и пользователь его не подтверждал.

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

Давайте посмотрим, как это выглядит на практике.

Проверка текущего статуса разрешения выполняется методом checkSelfPermission

int permissionStatus = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);

На вход метод требует Context и название разрешения. Он вернет константу PackageManager.PERMISSION_GRANTED (если разрешение есть) или PackageManager.PERMISSION_DENIED (если разрешения нет).

Если разрешение есть, значит мы ранее его уже запрашивали, и пользователь подтвердил его. Можем получать список контактов, система даст нам доступ.

Если разрешения нет, то нам надо его запросить. Это выполняется методом requestPermissions. Схема его работы похожа на метод startActivityForResult. Мы вызываем метод, передаем ему данные и request code, а ответ потом получаем в определенном onResult методе.

Добавим запрос разрешения к уже имеющейся проверке.

int permissionStatus = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);    if (permissionStatus == PackageManager.PERMISSION_GRANTED) {     readContacts();  } else {     ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_CONTACTS},             REQUEST_CODE_PERMISSION_READ_CONTACTS);  }

Проверяем разрешение READ_CONTACTS. Если оно есть, то читаем контакты. Иначе запрашиваем разрешение READ_CONTACTS методом requestPermissions. На вход метод требует Activity, список требуемых разрешений, и request code. Обратите внимание, что для разрешений используется массив. Т.е. вы можете запросить сразу несколько разрешений.

После вызова метода requestPermissions система покажет следующий диалог

Здесь будет отображено разрешение, которое мы запросили методом requestPermissions. Пользователь может либо подтвердить его (ALLOW), либо отказать (DENY). Если будет запрошено сразу несколько разрешений, то на каждое из них будет показан отдельный диалог. И пользователь может какие-то разрешения подтвердить, а какие-то нет.

Решение пользователя мы получим в методе onRequestPermissionsResult

@Override  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {     switch (requestCode) {         case REQUEST_CODE_PERMISSION_READ_CONTACTS:             if (grantResults.length > 0                     && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                 // permission granted                 readContacts();             } else {                 // permission denied             }             return;     }  }  

Проверяем, что requestСode тот же, что мы указывали в requestPermissions. В массиве permissions придут название разрешений, которые мы запрашивали. В массиве grantResults придут ответы пользователя на запросы разрешений.

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

Далее поговорим про некоторые дополнительные возможности, нюансы и прочие мелочи.

Манифест

При использовании новой схемы разрешений вам все равно необходимо указывать разрешение в манифесте. Если его там не указать и сделать запрос на это разрешение, то вам просто сразу придет отказ без всякого диалога.

Всегда проверяйте разрешение

Каждый раз (а не только первый) перед выполнением операции, требующей определенного разрешения, необходимо проверять, что это разрешение есть. Потому что, даже если пользователь уже давал это разрешение, он всегда может зайти в настройки приложения и отменить его. И если вы после этого не выполните проверку, то получите ошибку при выполнении операции.

Don’t ask again

Когда вы первый раз делаете запрос на какое-либо разрешение, пользователь может отказать. При последующих запросах этого же разрешения, в диалоге появится чекбокс Don’t ask again

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

Объяснение для пользователя

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

Диалог, который показывается при запросе разрешения, — системный, вы не можете менять его содержимое и добавлять туда свой текст. Но вы можете сделать свой диалог или что-то подобное и показать его перед тем, как будете делать запрос разрешения.

Есть метод shouldShowRequestPermissionRationale, который может быть полезен в данной ситуации. Передаете ему название разрешения, а он вам в виде boolean ответит, надо ли показывать объяснение для пользователя.

Т.е. вы сначала проверяете наличие разрешения. Если его нет, то вызываете shouldShowRequestPermissionRationale, чтобы решить, надо ли показывать объяснение пользователю. Если не надо, то делаете запрос разрешения. А если надо, то показываете ваш диалог с объяснением, а после этого диалога делаете запрос разрешения.

Алгоритм работы метода shouldShowRequestPermissionRationale прост.

Если вы еще ни разу не запрашивали это разрешение, то он вернет false. Т.е. перед первым запросом разрешения ничего объяснять не надо.

Если вы ранее уже запрашивали это разрешение и пользователь отказал, то метод вернет true. Т.е. пользователь не понимает, почему он должен давать это разрешение, и надо ему это объяснить.

Если пользователь ставил галку Don’t ask again, то метод вернет false. Запрос полномочий все равно не будет выполнен. Объяснять что-то не имеет смысла.

Разумеется, вы можете показывать дополнительную информацию согласно вашим правилам и не использовать метод shouldShowRequestPermissionRationale.

Группы

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

Например, разрешения READ_CONTACTS и WRITE_CONTACTS принадлежат группе CONTACTS. И если пользователь уже подтверждал разрешение на READ_CONTACTS, то при проверке WRITE_CONTACTS вы получите PERMISSION_GRANTED.

Android 6 и targetSdkVersion 23

Схема работы разрешений зависит от версии Android, на которой запущено приложение и от параметра targetSdkVersion приложения.

Новая схема будет работать, если версия Android >= 6 И targetSdkVersion >= 23.

В остальных случаях, т.е. когда targetSdkVersion < 23 ИЛИ версия Android < 6, разрешения будут работать по старому. Т.е. пользователь будет подтверждать их сразу все при установке. Если в приложении есть код, который проверяет разрешения, то он будет получать PERMISSION_GRANTED.

Но учитывайте, что в Android версии 6 и выше, пользователь может отменить разрешения в настройках приложения.

Intent

Не забывайте, что иногда для работы с контактами, камерой и т.п., вы можете использовать Intent и уже установленные приложения. В этом случае вам не придется писать лишний код и запрашивать разрешения для работы с этими ресурсами.

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование 

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме 

Asked3 years, 7 months ago Active1 year, 5 months ago Viewed 67k times 69

Which permissions need for requesting permissions at run time of API 23?

|improve this question

2 Answers 2

active oldest votes 143

As of API level 23, the following permissions are classified as PROTECTION_NORMAL:

ACCESS_LOCATION_EXTRA_COMMANDS ACCESS_NETWORK_STATE ACCESS_NOTIFICATION_POLICY ACCESS_WIFI_STATE BLUETOOTH BLUETOOTH_ADMIN BROADCAST_STICKY CHANGE_NETWORK_STATE CHANGE_WIFI_MULTICAST_STATE CHANGE_WIFI_STATE DISABLE_KEYGUARD EXPAND_STATUS_BAR GET_PACKAGE_SIZE INSTALL_SHORTCUT INTERNET KILL_BACKGROUND_PROCESSES MODIFY_AUDIO_SETTINGS NFC READ_SYNC_SETTINGS READ_SYNC_STATS RECEIVE_BOOT_COMPLETED REORDER_TASKS REQUEST_IGNORE_BATTERY_OPTIMIZATIONS REQUEST_INSTALL_PACKAGES SET_ALARM SET_TIME_ZONE SET_WALLPAPER SET_WALLPAPER_HINTS TRANSMIT_IR UNINSTALL_SHORTCUT USE_FINGERPRINT VIBRATE WAKE_LOCK WRITE_SYNC_SETTINGS 

and

Dangerous permissions :

READ_CALENDAR WRITE_CALENDAR CAMERA READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION RECORD_AUDIO READ_PHONE_STATE READ_PHONE_NUMBERS  CALL_PHONE ANSWER_PHONE_CALLS  READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS BODY_SENSORS SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE 

Android 6.0 multiple request permissions More info

Source https://developer.android.com/guide/topics/permissions/requesting.html#normal-dangerous

|improve this answer 4

The Normal permissions do not directly affect the user’s privacy. If application lists a normal permission in its manifest, then these permissions will be automatically granted by the system upon installation. Some of the most common normal permissions are given below.

Check and change data connection: Include network state, Wi-Fi State, Bluetooth, Internet, etc.

Example:

Source: https://vmokshagroup.com/blog/android-runtime-permissions/

|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.

default

ОСТАВЬТЕ ОТВЕТ

Please enter your name here
Please enter your comment!