Google Play services and runtime permissions
Stay organized with collections
Save and categorize content based on your preferences.
Since Android 6.0 Marshmallow, Android uses a
permissions model that streamlines the app install and
auto-update process. Permissions are requested at runtime instead of before
app installation. Additionally, users can choose to deny specific permissions.
To give users this flexibility, you need to make sure that your app behaves as
expected when a user enables or disables a specific permission.
Google Play services itself has runtime permissions that users can choose to
deny separately from those permissions specifically requested by your app.
Google Play services automatically obtains all permissions it needs to support
its APIs. However, your app should still check and request runtime permissions
as necessary and appropriately handle errors in cases where a user has denied
Google Play services a permission required for an API your app uses.
It's good practice to manage the user's expectations in setting permissions
that the runtime may require. The following best practices will help you avoid
potential issues.
Prerequisites
You'll need to declare permissions in your AndroidManifest.xml
file.
For example:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Guidelines
Verify permissions before calling APIs
Once you've declared the APIs that you want to use in your AndroidManifest.xml
file, verify that you have the required permission before calling an API. This
can be done using the checkSelfPermission
method of
ActivityCompat
or ContextCompat
.
If the call returns false this means the permissions aren't granted and you
should use requestPermissions
to request them. The response to this is
returned in a callback which you will see in the next step.
For example:
Kotlin
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Request Permissions Now
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION_CODE)
} else {
// permission has been granted, continue as usual
val locationResult = LocationServices
.getFusedLocationProviderClient(this /* Context */)
.lastLocation
}
Java
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Request Permissions Now
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION_PERMISSION_CODE);
} else {
// permission has been granted, continue as usual
Task locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation();
}
Implement the request permission callback
If the permission your app needs hasn't been granted by the user, the
requestPermissions
method should be called to ask the
user to grant them. The response from the user is captured in the
onRequestPermissionsResult
callback. Your app should
implement this and always check the return values because the request could be
denied or canceled. You can also request and check for multiple permissions at
once--the following sample only checks for a single permission.
Kotlin
fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array,
grantResults: IntArray
) {
if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
if (grantResults.singleOrNull() == PackageManager.PERMISSION_GRANTED) {
// We can now safely use the API we requested access to
val locationResult: Task = LocationServices
.getFusedLocationProviderClient(this /* Context */)
.lastLocation // Request the last known location.
} else {
// Permission was denied or request was cancelled
}
}
}
Java
public void onRequestPermissionsResult(int requestCode,
String[] permissions,
int[] grantResults) {
if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
if(grantResults.length == 1
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// We can now safely use the API we requested access to
Task locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation(); // Request the last known location.
} else {
// Permission was denied or request was cancelled
}
}
}
Show the permission rationale
If the permissions your app requests are necessary for the core features of the
app and the user has previously denied the permission request, your app should
display an additional explanation before requesting the permission again. Users
are more likely to grant permissions when they understand the why the permission
is needed and the immediate benefit for them.
In this case, before the calling requestPermissions
, you should call
shouldShowRequestPermissionRationale
. If it returns
true, you should create some UI to display additional context for the
permission.
For example, your code might look like this:
Kotlin
private const val REQUEST_LOCATION_PERMISSION_CODE = 2
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Check Permissions Now
if ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) {
// Display UI and wait for user interaction
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION_CODE)
}
} else {
// Permission has already been granted, continue as usual
val locationResult: Task = LocationServices
.getFusedLocationProviderClient(this /* Context */)
.lastLocation
}
Java
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Check Permissions Now
private static final int REQUEST_LOCATION_PERMISSION_CODE = 2;
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Display UI and wait for user interaction
} else {
ActivityCompat.requestPermissions(
this, new String[]{Manifest.permission.LOCATION_FINE},
REQUEST_LOCATION_PERMISSION_CODE);
}
} else {
// permission has been granted, continue as usual
Task locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation();
}
Google Play services API calls will automatically display either a dialog (if
the client is instantiated with an Activity
) or system tray notification (if
the client is instantiated with a Context
) that the user can tap to start the
permissions resolution intent. Calls will be enqueued and retried once the
permission is granted.
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-08-07 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-07 UTC."],[[["\u003cp\u003eThe \u003ccode\u003ePlayers\u003c/code\u003e interface is deprecated and developers should use \u003ccode\u003ePlayersClient\u003c/code\u003e instead for player functionality.\u003c/p\u003e\n"],["\u003cp\u003eIt provides access to player information like the current player's profile and ID.\u003c/p\u003e\n"],["\u003cp\u003eIt allows comparing profiles and searching for players using intents.\u003c/p\u003e\n"],["\u003cp\u003eMethods related to loading connected, invitable, and recently played with players are deprecated due to the removal of Google+ integration.\u003c/p\u003e\n"]]],["Android apps, from version 6.0, manage permissions at runtime. Developers must declare permissions in `AndroidManifest.xml` and verify them using `checkSelfPermission` before API calls. If permissions are not granted, use `requestPermissions`. Handle user responses in `onRequestPermissionsResult`, addressing denials. If permissions are critical and previously denied, show rationale with `shouldShowRequestPermissionRationale`. If `connect()` fails handle it appropriately. Newer API calls automatically prompt users to resolve permission issues.\n"],null,["Since Android 6.0 Marshmallow, Android uses a\n[permissions model](https://developer.android.com/preview/features/runtime-permissions.html) that streamlines the app install and\nauto-update process. Permissions are requested at runtime instead of before\napp installation. Additionally, users can choose to deny specific permissions.\nTo give users this flexibility, you need to make sure that your app behaves as\nexpected when a user enables or disables a specific permission.\n\nGoogle Play services itself has runtime permissions that users can choose to\ndeny separately from those permissions specifically requested by your app.\nGoogle Play services automatically obtains all permissions it needs to support\nits APIs. However, your app should still check and request runtime permissions\nas necessary and appropriately handle errors in cases where a user has denied\nGoogle Play services a permission required for an API your app uses.\n\nIt's good practice to manage the user's expectations in setting permissions\nthat the runtime may require. The following best practices will help you avoid\npotential issues.\n\nPrerequisites\n\nYou'll need to declare permissions in your `AndroidManifest.xml` file.\nFor example: \n\n \u003cuses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/\u003e\n\nGuidelines\n\nVerify permissions before calling APIs\n\nOnce you've declared the APIs that you want to use in your `AndroidManifest.xml`\nfile, verify that you have the required permission before calling an API. This\ncan be done using the `checkSelfPermission` method of\n[`ActivityCompat`](https://developer.android.com/reference/androidx/core/app/ActivityCompat) or [`ContextCompat`](https://developer.android.com/reference/androidx/core/content/ContextCompat).\n\nIf the call returns false this means the permissions aren't granted and you\nshould use `requestPermissions` to request them. The response to this is\nreturned in a callback which you will see in the next step.\n\nFor example: \n\nKotlin \n\n```kotlin\n if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)\n != PackageManager.PERMISSION_GRANTED) {\n // Request Permissions Now\n ActivityCompat.requestPermissions(\n this,\n arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),\n REQUEST_LOCATION_PERMISSION_CODE)\n } else {\n // permission has been granted, continue as usual\n val locationResult = LocationServices\n .getFusedLocationProviderClient(this /* Context */)\n .lastLocation\n }\n```\n\nJava \n\n```java\n if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)\n != PackageManager.PERMISSION_GRANTED) {\n // Request Permissions Now\n ActivityCompat.requestPermissions(\n this,\n new String[]{Manifest.permission.ACCESS_FINE_LOCATION},\n REQUEST_LOCATION_PERMISSION_CODE);\n } else {\n // permission has been granted, continue as usual\n Task locationResult = LocationServices\n .getFusedLocationProviderClient(this /** Context */)\n .getLastLocation();\n }\n```\n\nImplement the request permission callback\n\nIf the permission your app needs hasn't been granted by the user, the\n[`requestPermissions`](https://developer.android.com/reference/androidx/core/app/ActivityCompat#requestPermissions(android.app.Activity,java.lang.String%5B%5D,int)) method should be called to ask the\nuser to grant them. The response from the user is captured in the\n[`onRequestPermissionsResult`](https://developer.android.com/reference/android/app/Activity.html#onRequestPermissionsResult(int,%20java.lang.String%5B%5D,%20int%5B%5D)) callback. Your app should\nimplement this and always check the return values because the request could be\ndenied or canceled. You can also request and check for multiple permissions at\nonce--the following sample only checks for a single permission. \n\nKotlin \n\n```kotlin\n fun onRequestPermissionsResult(\n requestCode: Int,\n permissions: Array,\n grantResults: IntArray\n ) {\n if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {\n if (grantResults.singleOrNull() == PackageManager.PERMISSION_GRANTED) {\n // We can now safely use the API we requested access to\n val locationResult: Task = LocationServices\n .getFusedLocationProviderClient(this /* Context */)\n .lastLocation // Request the last known location.\n } else {\n // Permission was denied or request was cancelled\n }\n }\n }\n```\n\nJava \n\n```java\n public void onRequestPermissionsResult(int requestCode,\n String[] permissions,\n int[] grantResults) {\n if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {\n if(grantResults.length == 1\n && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n // We can now safely use the API we requested access to\n Task locationResult = LocationServices\n .getFusedLocationProviderClient(this /** Context */)\n .getLastLocation(); // Request the last known location.\n } else {\n // Permission was denied or request was cancelled\n }\n }\n }\n```\n\nShow the permission rationale\n\nIf the permissions your app requests are necessary for the core features of the\napp and the user has previously denied the permission request, your app should\ndisplay an additional explanation before requesting the permission again. Users\nare more likely to grant permissions when they understand the why the permission\nis needed and the immediate benefit for them.\n\nIn this case, before the calling `requestPermissions`, you should call\n[`shouldShowRequestPermissionRationale`](https://developer.android.com/reference/androidx/core/app/ActivityCompat#shouldShowRequestPermissionRationale(android.app.Activity,java.lang.String)). If it returns\ntrue, you should create some UI to display additional context for the\npermission.\n\nFor example, your code might look like this: \n\nKotlin \n\n```kotlin\n private const val REQUEST_LOCATION_PERMISSION_CODE = 2\n if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)\n != PackageManager.PERMISSION_GRANTED) {\n // Check Permissions Now\n if ActivityCompat.shouldShowRequestPermissionRationale(\n this,\n Manifest.permission.ACCESS_FINE_LOCATION\n ) {\n // Display UI and wait for user interaction\n } else {\n ActivityCompat.requestPermissions(\n this,\n arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),\n REQUEST_LOCATION_PERMISSION_CODE)\n }\n } else {\n // Permission has already been granted, continue as usual\n val locationResult: Task = LocationServices\n .getFusedLocationProviderClient(this /* Context */)\n .lastLocation\n }\n```\n\nJava \n\n```java\n if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)\n != PackageManager.PERMISSION_GRANTED) {\n // Check Permissions Now\n private static final int REQUEST_LOCATION_PERMISSION_CODE = 2;\n if (ActivityCompat.shouldShowRequestPermissionRationale(this,\n Manifest.permission.ACCESS_FINE_LOCATION)) {\n // Display UI and wait for user interaction\n } else {\n ActivityCompat.requestPermissions(\n this, new String[]{Manifest.permission.LOCATION_FINE},\n REQUEST_LOCATION_PERMISSION_CODE);\n }\n } else {\n // permission has been granted, continue as usual\n Task locationResult = LocationServices\n .getFusedLocationProviderClient(this /** Context */)\n .getLastLocation();\n }\n```\n\nGoogle Play services API calls will automatically display either a dialog (if\nthe client is instantiated with an `Activity`) or system tray notification (if\nthe client is instantiated with a `Context`) that the user can tap to start the\npermissions resolution intent. Calls will be enqueued and retried once the\npermission is granted."]]