Runtime Permissions без боли. Mini HOWTO
При создании новых приложении утомляет каждый раз писать код для запроса runtime permissions у пользователя. Недавно нашел удобную библиотеку, уменьшающую бойлерплейт до пары строк, и решил написать шпаргалку.
Рассказ будет о библиотеке https://permissions-dispatcher.github.io/PermissionsDispatcher/
Исходная задача такая: в MainActivity нужно вызывать метод start()
, предварительно запросив
разрешение на определение точного местоположения.
class MainActivity : AppCompatActivity() {
....
fun start() {
Snackbar.make(fab, "Visa-Visa-Fly-Fly", Snackbar.LENGTH_LONG).show()
}
}
Итак. Все разрешения, даже запрашиваемые явно, должны быть в AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Если еще не включен процессор аннтоаций kapt, то не забыаем включить его в build.gradle:
apply plugin: 'kotlin-kapt'
Там же подключаем библиотеку, на момент последнего редактирования статьи permissionsDispatcher = "3.2.1"
(в момент написания была 3.1.0
).
dependencies {
....
implementation("com.github.hotchemi:permissionsdispatcher:${permissionsDispatcher}") {
// if you don't use android.app.Fragment you can exclude support for them
exclude module: "support-v13"
}
kapt "com.github.hotchemi:permissionsdispatcher-processor:${permissionsDispatcher}"
}
Добавляем аннотацию к MainActivity и делаем Rebuild Project:
@RuntimePermissions
class MainActivity : AppCompatActivity() {
....
}
После этого будет автоматически создан файл MainActivityPermissionsDispatcher.kt с расширениями для MainActivity.
Теперь нужно в MainActivity переопределить унаследованный метод onRequestPermissionsResult()
и добавить в него
вызов сгенерированной функции с тем же названием. Сгенерированный код никак не влияет на поведение
самой Activity, вызов мы должны обеспечить сами.
@SuppressLint("NeedOnRequestPermissionsResult")
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
onRequestPermissionsResult(requestCode, grantResults)
}
Выглядит как “масло маслянное”, конечно. Чтобы не запутаться, обратите внимание на количество параметров у разных
onRequestPermissionsResult()
, и из любопытства можете сделать Go to declaration на обоих, сразу станет все понятно.
Ко всем методам, вызов который требует проверки и запроса разрешений, нужно добавить аннотацию со списком требуемых разрешений (и опять не забыть Rebuild Project):
@NeedsPermission(Manifest.permission.ACCESS_FINE_LOCATION)
fun start() {
....
}
Для всех методов с аннотацией @NeedsPermission
будет создан метод-близнец, запрашивающий разрешения (это тоже
расширение, не поленитесь заглянуть в исходник). Его нужно вызывать вместо исходного метода в нужный нам момент:
fab.setOnClickListener { view ->
startWithPermissionCheck()
}
Программа-минимум выполнена. Запускаем, наслаждаемся.
Также можно аннотациями объявить функции, которые будут вызваны перед запросом разрешения (обычно для того, чтобы объяснить пользователю необходимость предоставить это разрешение), и в случае, если пользователь разрешение дать отказался (чтобы объяснить необходимость еще раз). Подробности в документации.