Permissions
To use some Android features like access to location, the app must have permission from user.
Declare necessary permissions in the AndroidManifest.xml.
<manifest ... >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
...
</manifest>
Since API 23+ you must request the dangerous permissions at runtime. If you don't declare any dangerous permissions, or if your app is installed on a device that runs Android 5.1 (API level 22) or lower, the permissions are automatically granted.
To request the dangerous permissions at runtime follow these steps.
1. Check whether the user has already granted the runtime permission that your app requires. If no, show education ui or request the runtime permission.
if(ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED) {
// all ok
doStuff()
}
// within context, for example activity
if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED){
doStuff()
}
if(checkPermission(Manifest.permission.ACCESS_FINE_LOCATION,
Process.myPid(), Process.myUid())
== PackageManager.PERMISSION_GRANTED){
doStuff()
}
2. Optionally check whether your app should show a rationale. Explain to the user why your app requires this permission. In this UI, include a "cancel" or "no thanks" button that allows the user to continue using your app without granting the permission.
// within activity
if(shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){
showEducationUi()
}
3. Request the runtime permission in activity. System displays a runtime permission prompt.
val REQUEST_LOCATION_PERMISSION_CODE = 1
...
requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION_CODE
)
4. Override onRequestPermissionsResult() method of activity to handle user choice.
If the user denies a permission request, your app should help users understand the implications of denying the permission.
Best practices:
- Highlight a specific part of your app's UI where there's limited functionality because your app doesn't have the necessary permission.
- Be specific. Don't display a generic message; instead, mention which features are unavailable because your app doesn't have the necessary permission.
- Don't block the user interface. In other words, don't display a full-screen warning message that prevents users from continuing to use your app at all.
system managing
With Activity Result Api you can allow system to manage the request code that's associated with a permissions request.
Add necessary dependencies
dependencies {
val activity_version = "1.2.3"
// Java language implementation
implementation("androidx.activity:activity:$activity_version")
// Kotlin
implementation("androidx.activity:activity-ktx:$activity_version")
val fragment_version = "1.3.4"
// Java language implementation
implementation("androidx.fragment:fragment:$fragment_version")
// Kotlin
implementation("androidx.fragment:fragment-ktx:$fragment_version")
}
Create a permission launcher with the permissions callback
val requestPermissionLauncher
= registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
// permission is granted
doStuff()
} else {
// Explain to the user that the feature is unavailable because the
// features requires a permission that the user has denied.
showEducationUI()
}
}
Request permission via permission launcher.
when {
ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED -> {
doStuff()
}
shouldShowRequestPermissionRationale(
Manifest.permission.ACCESS_FINE_LOCATION) -> {
showEducationUI()
}
else -> {
// The registered ActivityResultCallback gets the result of this request.
requestPermissionLauncher.launch(
Manifest.permission.ACCESS_FINE_LOCATION)
}
}
multiple permissions
You can check multiple permissions in cycle.
// method in activity
fun hasPermissions( vararg permissions: String): Boolean = permissions.all {
ActivityCompat.checkSelfPermission(this, it) ==
PackageManager.PERMISSION_GRANTED
}
Use RequestMultiplePermissions class to register permission launcher.
val requestPermissionLauncher
= registerForActivityResult(RequestMultiplePermissions()) { map->
map.entries.forEach {
val permission = it.key
val isGranted = it.value
//...
}
// ...
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
if(hasPermissions(*permissions)) {
// all ok
doStuff()
} else {
requestPermissionLauncher.launch(permissions)
}
// ...
}