Android permission denial reading

Android permissions

Операционная система 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. Потому что вы явно не запрашивали это разрешение, и пользователь его не подтверждал.

Читайте также:  Android 10 системные требования память

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

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

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

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

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

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

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

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

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

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

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

Проверяем, что 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

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

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

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

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

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

Источник

Android: Permission denial reading #14

Comments

ghost commented Jul 8, 2016

Hi,
on my android testphone — were it worked until now — i get this exception:

Permissions are not added to AndroidManifest.xml, if i add them by hand i still get the same error.

The text was updated successfully, but these errors were encountered:

ghost commented Jul 8, 2016

Building with AndroidStudio gave a better hint @firescript:

Warning:The file: /home/mre/PROJECTS/test/node_modules/nativescript-contacts/platforms/android/AndroidManifest.xml is depricated, you can read more about what will be the expected plugin structure here: https://www.nativescript.org/blog/migrating-n-android-plugins-from-version-1.7-to-2.0

PeterStaev commented Jul 8, 2016

Hey @einicher , although CLI throws this warning, it is a false one, as it was decided to keep AndroidManifest for plugins. You can read more here.

Have you installed the plugin using tns install nativescript-contacts ? Also can you try to clean your android platforms and then building your project again:

ghost commented Jul 8, 2016

i did several times.

same outcome, it shows me the contact selection dialog, but when i pick a contact i get the permission denied exception.

ghost commented Jul 8, 2016

is it possible it has something to with

i suddenly have to do this everytime i start a new project or else i get the error “app.js not found”

sitefinitysteve commented Jul 8, 2016

It’s this android 6?
On Jul 8, 2016 9:45 AM, «Markus René Einicher» notifications@github.com
wrote:

rm -rf node_modules platforms
tns platform add android
tns run android

same outcome, it shows me the contact selection dialog, but when i pick a
contact i get the permission denied exception.

ghost commented Jul 8, 2016

sitefinitysteve commented Jul 8, 2016

ghost commented Jul 8, 2016

@sitefinitysteve “Woo Hoo, I have the power”
it works.
Very important contribution, I would have nver thought about that, I thought it asks by itself, like qr-plugin does.
thx!!

sitefinitysteve commented Jul 8, 2016

I’ll see what i can do, or at least document it
On Jul 8, 2016 10:23 AM, «Markus René Einicher» notifications@github.com
wrote:

@sitefinitysteve https://github.com/sitefinitysteve “Woo Hoo, I have
the power”
it works.
Very important contribution, I would have nver thought about that, I
thought it asks by itself, like qr-plugin does.
thx!!

koganalon commented May 11, 2017

You’ll need a Runtime permission.
with or without placing the permission in your manifest, You will need to request that permission from the User on-the-fly.

if( getApplicationContext().checkSelfPermission( Manifest.permission.READ_CONTACTS ) != PackageManager.PERMISSION_GRANTED )
ActivityCompat.requestPermissions(activity, new String[], resultValue);

only then after the approval you will be able to query the contacts phone number/name etc.

Читайте также:  Наложение поверх других окон android что это такое

jzgoda commented Apr 18, 2019

Docs have been updated to avoid this issue.

hinalt commented Nov 17, 2020

I still get this error. Can you please paste an working example to explain this?

You can’t perform that action at this time.

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

Источник

java.lang.SecurityException: Permission Denial #9

Comments

BYVoid commented Mar 5, 2020

I added androidx.core.content.FileProvider and provider_paths.xml , but still encountered such an error:

The text was updated successfully, but these errors were encountered:

lubritto commented Mar 31, 2020

Are you still getting this error?

JenniferJesuraj commented Apr 6, 2020

@lubritto I’m seeing this exception on the console, but the functionality seems to work fine. Is this something that has to be fixed on the plugin side?

longravuth commented Apr 14, 2020

I get it too on Android 10

BYVoid commented Apr 15, 2020

marcLeeroy commented Jun 3, 2020

I have the same issue but the feature works, i can share no problem but i get that warning in the console.

vertis commented Jun 23, 2020

I am seeing the same error:

For reference I found:

Specifically, the stackoverflow solution involves adding:

I am going to create a fork and see if this solves the problem. Will open a pull request if it does.

vertis commented Jun 23, 2020 •

If anyone is interested in using this bugfix until it is merged you can do so by adding the following to pubspec.yaml :

Just make sure to change it back once it’s merged. I do not intend to keep my fork updated.

rjaylwar commented Jul 2, 2020

mobabur94 commented Jul 3, 2020

I see the error logged in the console as well, although the feature seems to work. Would like for the fix to be merged in

LokeshNakka commented Dec 21, 2020 •

VivekThummar52 commented Jun 10, 2021

I get it too on Android 10

i got it on Android 11 , not on Android 10

shubhamnandanwar commented Jul 16, 2021

I am getting in Android 10 and Android 12. (Not checked for Android 11)

manwithsteelnerves commented Aug 9, 2021

VivekThummar52 commented Aug 9, 2021 •

@manwithsteelnerves
As of i know and i have tried, given solution worked for me, please try this :

And tell me if this will work for you or not..

manwithsteelnerves commented Aug 9, 2021 •

Even I’m granting the read uri permission but not working for multiple files

It started working after adding the uri permission flag on the intent chooser too for all the attachments (uris).

VivekThummar52 commented Aug 10, 2021

@manwithsteelnerves
in line — intent.putExtra(Intent.EXTRA_STREAM, uri); , i think you can also set list of String or Uri , you have tried it or not??

manwithsteelnerves commented Aug 10, 2021

@manwithsteelnerves
in line — intent.putExtra(Intent.EXTRA_STREAM, uri); , i think you can also set list of String or Uri , you have tried it or not??

Yes. I’m currently setting the array of streams(uri) only. But still it expects me to add the read permission flags on «chooser» intent by going through all of the matching packages (note you may need to add QUERY_ALL_PACKAGES or tag if >= API 30 is your target api)

shubhamnandanwar commented Aug 10, 2021 •

I was using scoped storage and I figured it’s impossible for me to share that particular image (please correct me if I am wrong). I found a thread in which the developer was creating a cache image in the scoped folder and was sharing the cached image. The developer also hardcoded the image name, so whenever a user shares a new image, the previous cache image gets overwritten. Unfortunately, I couldn’t find that thread again but here’s the code —

I have tested it in Android 12 and 10 and it’s working fine.

Источник

Оцените статью