Per bug, emphasized that if an app targets SDK 22 or lower, it uses the install-time permissions model even if it's running on M. However, also added the note that an M user can *revoke* an app's permissions after install, which can cause unpredictable behavior. See first comment for doc stage location. bug: 25470298 Change-Id: Ia05a1f784595e75bf7b6835dbfdeffcd458f0022
362 lines
15 KiB
Plaintext
362 lines
15 KiB
Plaintext
page.title=Requesting Permissions at Run Time
|
|
page.tags="runtime permissions",androidm,marshmallow
|
|
page.image=images/permissions_check.png
|
|
page.metaDescription=Learn about runtime permissions and how they make it easier for users to install and upgrade your apps.
|
|
@jd:body
|
|
|
|
<div id="tb-wrapper">
|
|
<div id="tb">
|
|
<h2>This lesson teaches you to</h2>
|
|
|
|
<ul>
|
|
<li>
|
|
<a href="#perm-check">Check For Permissions</a>
|
|
</li>
|
|
<li>
|
|
<a href="#perm-request">Request Permissions</a>
|
|
</li>
|
|
</ul>
|
|
|
|
<h2>Dependencies and Prerequisites</h2>
|
|
|
|
<ul>
|
|
<li>Android 6.0 (API level 23)
|
|
</li>
|
|
</ul>
|
|
|
|
<h2>You should also read</h2>
|
|
|
|
<ul>
|
|
<li>
|
|
<a href=
|
|
"{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
|
|
and Dangerous Permissions</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<p>
|
|
Beginning in Android 6.0 (API level 23), users grant
|
|
permissions to apps while the app is running, not when they install the app.
|
|
This approach streamlines the app
|
|
install process, since the user does not need to grant permissions when they
|
|
install or update the app. It also gives the user more control over the app's
|
|
functionality; for example, a user could choose to give a camera app access
|
|
to the camera but not to the device location. The user can revoke the
|
|
permissions at any time, by going to the app's Settings screen.
|
|
</p>
|
|
|
|
<p>
|
|
System permissions are divided into two categories, <em>normal</em> and
|
|
<em>dangerous:</em>
|
|
</p>
|
|
|
|
<ul>
|
|
<li>Normal permissions do not directly risk the user's privacy. If your app
|
|
lists a normal permission in its manifest, the system grants the permission
|
|
automatically.
|
|
</li>
|
|
|
|
<li>Dangerous permissions can give the app access to the user's confidential
|
|
data. If your app lists a normal permission in its manifest, the system
|
|
grants the permission automatically. If you list a dangerous permission, the
|
|
user has to explicitly give approval to your app.
|
|
</li>
|
|
</ul>
|
|
|
|
<p>
|
|
For more information, see <a href=
|
|
"{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
|
|
and Dangerous Permissions</a>.
|
|
</p>
|
|
|
|
<p>
|
|
On all versions of Android, your app needs to declare both the normal and the
|
|
dangerous permissions it needs in its app manifest, as described in <a href=
|
|
"declaring.html">Declaring Permissions</a>. However, the <em>effect</em> of
|
|
that declaration is different depending on the system version and your
|
|
app's target SDK level:
|
|
</p>
|
|
|
|
<ul>
|
|
<li>If the device is running Android 5.1 or lower, <strong>or</strong> your app's target SDK
|
|
is 22 or lower: If you list a dangerous permission in your manifest, the user
|
|
has to grant the permission when they install the app; if they do not grant
|
|
the permission, the system does not install the app at all.
|
|
</li>
|
|
|
|
<li>If the device is running Android 6.0 or higher, <strong>and</strong> your app's target SDK
|
|
is 23 or higher: The app has to list the permissions in the manifest,
|
|
<em>and</em> it must request each dangerous permission it needs while the app
|
|
is running. The user can grant or deny each permission, and the app can
|
|
continue to run with limited capabilities even if the user denies a
|
|
permission request.
|
|
</li>
|
|
</ul>
|
|
|
|
<p class="note">
|
|
<strong>Note:</strong> Beginning with Android 6.0 (API level 23), users can
|
|
revoke permissions from any app at any time, even if the app targets a lower
|
|
API level. You should test your app to verify that it behaves properly when
|
|
it's missing a needed permission, regardless of what API level your app
|
|
targets.
|
|
</p>
|
|
|
|
<p>
|
|
This lesson describes how to use the Android <a href=
|
|
"{@docRoot}tools/support-library/index.html">Support Library</a> to check
|
|
for, and request, permissions. The Android framework provides similar methods
|
|
as of Android 6.0 (API level 23). However, using the support library is
|
|
simpler, since your app doesn't need to check which version of Android it's
|
|
running on before calling the methods.
|
|
</p>
|
|
|
|
<h2 id="perm-check">Check For Permissions</h2>
|
|
|
|
<p>
|
|
If your app needs a dangerous permission, you must check whether you have
|
|
that permission every time you perform an operation that requires that
|
|
permission. The user is always free to revoke the permission, so even if the
|
|
app used the camera yesterday, it can't assume it still has that permission
|
|
today.
|
|
</p>
|
|
|
|
<p>
|
|
To check if you have a permission, call the {@link
|
|
android.support.v4.content.ContextCompat#checkSelfPermission
|
|
ContextCompat.checkSelfPermission()} method. For example, this snippet shows how to
|
|
check if the activity has permission to write to the calendar:
|
|
</p>
|
|
|
|
<pre>// Assume thisActivity is the current activity
|
|
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
|
|
Manifest.permission.WRITE_CALENDAR);</pre>
|
|
|
|
<p>
|
|
If the app has the permission, the method returns {@link
|
|
android.content.pm.PackageManager#PERMISSION_GRANTED
|
|
PackageManager.PERMISSION_GRANTED}, and the app can proceed with the
|
|
operation. If the app does not have the permission, the method returns {@link
|
|
android.content.pm.PackageManager#PERMISSION_DENIED PERMISSION_DENIED}, and
|
|
the app has to explicitly ask the user for permission.
|
|
</p>
|
|
|
|
<h2 id="perm-request">Request Permissions</h2>
|
|
|
|
<p>
|
|
If your app needs a dangerous permission that was listed in the app manifest,
|
|
it must ask the user to grant the permission. Android provides several
|
|
methods you can use to request a permission. Calling these methods brings up a
|
|
standard Android dialog, which you cannot customize.
|
|
</p>
|
|
<h3 id="explain">Explain why the app needs permissions</h3>
|
|
|
|
<div class="figure" style="width:220px" id="fig-perms-dialog">
|
|
<img src="{@docRoot}images/training/permissions/request_permission_dialog.png"
|
|
srcset="{@docRoot}images/training/permissions/request_permission_dialog.png 1x,
|
|
{@docRoot}images/training/permissions/request_permission_dialog_2x.png 2x"
|
|
alt="" width="220" />
|
|
<p class="img-caption">
|
|
<strong>Figure 1.</strong> System dialog prompting the user to grant or deny
|
|
a permission.
|
|
</p>
|
|
</div>
|
|
|
|
<p>
|
|
In some circumstances, you might want to help the user understand why your
|
|
app needs a permission. For example, if a user launches a photography app,
|
|
the user probably won't be surprised that the app asks for permission to use
|
|
the camera, but the user might not understand why the app wants access to the
|
|
user's location or contacts. Before you request a permission, you should
|
|
consider providing an explanation to the user. Keep in mind that you don't
|
|
want to overwhelm the user with explanations; if you provide too many
|
|
explanations, the user might find the app frustrating and remove it.
|
|
</p>
|
|
|
|
<p>
|
|
One approach you might use is to provide an explanation only if the user has
|
|
already turned down that permission request. If a user keeps trying to use
|
|
functionality that requires a permission, but keeps turning down the
|
|
permission request, that probably shows that the user doesn't understand why
|
|
the app needs the permission to provide that functionality. In a situation
|
|
like that, it's probably a good idea to show an explanation.
|
|
</p>
|
|
|
|
<p>
|
|
To help find situations where the user might need an explanation, Android
|
|
provides a utiltity method, {@link
|
|
android.support.v4.app.ActivityCompat#shouldShowRequestPermissionRationale
|
|
shouldShowRequestPermissionRationale()}. This method returns <code>true</code> if the app
|
|
has requested this permission previously and the user denied the request.
|
|
</p>
|
|
|
|
<p class="note">
|
|
<strong>Note:</strong> If the user turned down the permission request in the
|
|
past and chose the <strong>Don't ask again</strong> option in the permission
|
|
request system dialog, this method returns <code>false</code>. The method
|
|
also returns <code>false</code> if a device policy prohibits the app from
|
|
having that permission.
|
|
</p>
|
|
|
|
<h3 id="make-the-request">Request the permissions you need</h3>
|
|
|
|
<p>
|
|
If your app doesn't already have the permission it needs, the app must call
|
|
one of the {@link android.support.v4.app.ActivityCompat#requestPermissions
|
|
requestPermissions()} methods to request the appropriate
|
|
permissions. Your app passes the permissions it wants, and also
|
|
an integer <em>request code</em> that you specify to identify this permission
|
|
request. This method functions asynchronously: it
|
|
returns right away, and after the user responds to the dialog box, the system
|
|
calls the app's callback method with the results, passing the same request
|
|
code that the app passed to
|
|
{@link android.support.v4.app.ActivityCompat#requestPermissions
|
|
requestPermissions()}.
|
|
</p>
|
|
|
|
<p>
|
|
The following code checks if the app has permission to read the user's
|
|
contacts, and requests the permission if necessary:
|
|
</p>
|
|
|
|
<pre>// Here, thisActivity is the current activity
|
|
if (ContextCompat.checkSelfPermission(thisActivity,
|
|
Manifest.permission.READ_CONTACTS)
|
|
!= PackageManager.PERMISSION_GRANTED) {
|
|
|
|
// Should we show an explanation?
|
|
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
|
|
Manifest.permission.READ_CONTACTS)) {
|
|
|
|
// Show an expanation to the user *asynchronously* -- don't block
|
|
// this thread waiting for the user's response! After the user
|
|
// sees the explanation, try again to request the permission.
|
|
|
|
} else {
|
|
|
|
// No explanation needed, we can request the permission.
|
|
|
|
ActivityCompat.requestPermissions(thisActivity,
|
|
new String[]{Manifest.permission.READ_CONTACTS},
|
|
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
|
|
|
|
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
|
|
// app-defined int constant. The callback method gets the
|
|
// result of the request.
|
|
}
|
|
}</pre>
|
|
|
|
<p class="note">
|
|
<strong>Note:</strong> When your app calls {@link
|
|
android.support.v4.app.ActivityCompat#requestPermissions
|
|
requestPermissions()}, the system shows a standard dialog box to the user.
|
|
Your app <em>cannot</em> configure or alter that dialog box. If you need to
|
|
provide any information or explanation to the user, you should do that before
|
|
you call {@link android.support.v4.app.ActivityCompat#requestPermissions
|
|
requestPermissions()}, as described in <a href="#explain">Explain why the app
|
|
needs permissions</a>.
|
|
</p>
|
|
|
|
<h3 id="handle-response">Handle the permissions request response
|
|
</h3>
|
|
|
|
<p>
|
|
When your app requests permissions, the system presents a dialog box to the
|
|
user. When the user responds, the system invokes your app's {@link
|
|
android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
|
|
onRequestPermissionsResult()} method, passing it the user response. Your app
|
|
has to override that method to find out whether the permission was granted.
|
|
The callback is passed the same request code you passed to
|
|
{@link android.support.v4.app.ActivityCompat#requestPermissions
|
|
requestPermissions()}. For example, if an app requests {@link
|
|
android.Manifest.permission#READ_CONTACTS READ_CONTACTS} access it might have
|
|
the following callback method:
|
|
</p>
|
|
|
|
<pre>@Override
|
|
public void onRequestPermissionsResult(int requestCode,
|
|
String permissions[], int[] grantResults) {
|
|
switch (requestCode) {
|
|
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
|
|
// If request is cancelled, the result arrays are empty.
|
|
if (grantResults.length > 0
|
|
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
|
|
// permission was granted, yay! Do the
|
|
// contacts-related task you need to do.
|
|
|
|
} else {
|
|
|
|
// permission denied, boo! Disable the
|
|
// functionality that depends on this permission.
|
|
}
|
|
return;
|
|
}
|
|
|
|
// other 'case' lines to check for other
|
|
// permissions this app might request
|
|
}
|
|
}</pre>
|
|
|
|
<p>
|
|
The dialog box shown by the system describes the <a href=
|
|
"{@docRoot}guide/topics/security/permissions.html#perm-groups">permission
|
|
group</a> your app needs access to; it does not list the specific permission.
|
|
For example, if you request the {@link
|
|
android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission, the
|
|
system dialog box just says your app needs access to the device's contacts.
|
|
The user only needs to grant permission once for each permission group. If
|
|
your app requests any other permissions in that group (that are listed in
|
|
your app manifest), the system automatically grants them. When you request
|
|
the permission, the system calls your {@link
|
|
android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
|
|
onRequestPermissionsResult()} callback method and passes {@link
|
|
android.content.pm.PackageManager#PERMISSION_GRANTED PERMISSION_GRANTED}, the
|
|
same way it would if the user had explicitly granted your request through the
|
|
system dialog box.
|
|
</p>
|
|
|
|
<p class="note">
|
|
<strong>Note:</strong> Your app still needs to explicitly request every
|
|
permission it needs, even if the user has already granted another permission
|
|
in the same group. In addition, the grouping of permissions into groups may
|
|
change in future Android releases. Your code should not rely
|
|
on the assumption that particular permissions are or are not in the
|
|
same group.
|
|
</p>
|
|
|
|
<p>
|
|
For example, suppose you list both {@link
|
|
android.Manifest.permission#READ_CONTACTS READ_CONTACTS} and {@link
|
|
android.Manifest.permission#WRITE_CONTACTS WRITE_CONTACTS} in your app
|
|
manifest. If you request
|
|
{@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} and the user
|
|
grants the permission, and you then request {@link
|
|
android.Manifest.permission#WRITE_CONTACTS WRITE_CONTACTS}, the system
|
|
immediately grants you that permission without interacting with the user.
|
|
</p>
|
|
|
|
<p>
|
|
If the user denies a permission request, your app should take appropriate
|
|
action. For example, your app might show a dialog explaining why it could not
|
|
perform the user's requested action that needs that permission.
|
|
</p>
|
|
|
|
<p>
|
|
When the system asks the user to grant a permission, the user has the option
|
|
of telling the system not to ask for that permission again. In that case, any
|
|
time an app uses {@link
|
|
android.support.v4.app.ActivityCompat#requestPermissions
|
|
requestPermissions()} to ask for that permission again, the system
|
|
immediately denies the request. The system calls your {@link
|
|
android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
|
|
onRequestPermissionsResult()} callback method and passes {@link
|
|
android.content.pm.PackageManager#PERMISSION_DENIED PERMISSION_DENIED}, the
|
|
same way it would if the user had explicitly rejected your request again.
|
|
This means that when you call {@link
|
|
android.support.v4.app.ActivityCompat#requestPermissions
|
|
requestPermissions()}, you cannot assume that any direct interaction with the
|
|
user has taken place.
|
|
</p>
|