在运行时请求权限
从Android 6.0(API级别23)开始,用户权限授予应用程序在应用程序运行时,当他们安装程序。这种方法简化了应用程序的安装过程,因为用户不需要安装或更新应用程序时授予权限。这也给了用户更多的控制应用程序的功能;例如,一个用户可以选择给相机应用程序访问相机而不是设备的位置。用户可以随时撤销权限,通过将应用程序的设置屏幕。
系统权限分为两类,普通和危险:
- 正常的权限不直接用户的隐私风险。如果你的应用程序清单列出了一个正常的权限,系统自动授予许可。
- 危险的权限可以给应用程序访问用户的机密数据。如果你的应用程序清单列出了一个正常的权限,系统自动授予许可。如果你列出一个危险的许可,用户必须显式地给应用程序审批。
在所有版本的Android系统,您的应用程序需要申报的正常和危险的权限需要在其应用程序清单,如声明中所述的权限。然而,宣言的影响是不同的根据系统版本和SDK应用程序的目标水平:
- 如果设备运行Android 5.1或更低,或应用程序的目标SDK是22或更低:如果你在清单列表一个危险的许可,用户授予权限安装应用程序时,如果他们不授予权限,系统没有安装应用程序。
- 如果设备运行Android 6.0或更高版本,和你的应用程序的目标SDK是23或更高:应用列表的权限清单,它必须要求每个危险的权限需要在应用程序运行时。用户可以授予或拒绝每一个权限,应用程序可以继续运行能力有限,即使用户拒绝权限请求。
注意:从Android 6.0(API级别23),用户可以在任何时候从任何应用程序撤销权限,即使应用程序API级别较低的目标。你应该测试你的应用程序,以确认它正确行为的时候丢失了一个需要许可,无论什么API级别应用程序的目标。
这节课描述了如何使用Android支持库检查,和请求,权限。Android 6.0的Android框架提供了类似的方法(API级别23)。然而,使用支持库比较简单,因为应用程序不需要检查哪个版本的Android上运行之前调用的方法。
检查权限
如果你的应用需要一个危险的许可,你必须检查你是否有权限每次执行一个操作,要求许可。用户总是可以撤销许可,所以即使相机昨天使用的应用程序,它不能假设它今天仍有该权限。
检查如果你有权限,调用ContextCompat.checkSelfPermission()方法。例如,这个代码片段展示了如何检查活动日历上写权限:
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
如果应用程序许可,该方法返回PackageManager。PERMISSION_GRANTED,应用程序可以继续运行。如果应用程序没有许可,方法返回PERMISSION_DENIED,应用程序必须显式地要求用户许可。
请求的权限
如果你的应用需要一个应用程序清单中列出的危险的许可,它必须要求用户授予权限。Android提供了几种方法可用于请求许可。调用这些方法提出一个标准的Android对话框中,您不能定制。
解释为什么这个应用程序需要的权限
在某些情况下,您可能想要帮助用户理解为什么你的应用需要一个许可。摄影为例,如果一个用户启动一个应用程序,用户可能不会感到惊讶,允许应用程序要求使用相机,但是用户可能不理解为什么这个应用程序要访问用户的位置或联系人。在请求许可之前,你应该考虑为用户提供一个解释。记住,你不想淹没用户提供解释,如果你提供太多的解释,用户可能会发现应用令人沮丧和删除它。
您可以使用的一种方法是提供一个解释只有在用户已经拒绝了该权限的请求。如果用户一直试图使用功能需要一个许可,但一直拒绝许可的要求,这可能表明用户不理解为什么允许应用程序需要提供该功能。在这样的情况下,它可能是一个好主意给一个解释。
帮助找到的情况下,用户可能需要一个解释,Android提供了一种utiltity方法,shouldShowRequestPermissionRationale()。这个方法返回true,如果应用程序要求这个许可之前,用户拒绝请求。
注意:如果用户拒绝许可请求过去,再次选择了不要问选项允许请求系统对话框中,这个方法返回false。该方法还返回false如果设备政策禁止应用程序拥有该权限。
请求所需要的权限
如果应用程序已经不允许它的需求,应用程序必须调用一个requestPermissions()方法来请求适当的权限。应用程序通过它想要的权限,以及一个整数要求您指定识别这个许可请求的代码。这种方法异步函数:它返回,用户响应对话框之后,系统调用应用程序的回调方法对结果的影响,通过相同的请求代码,应用程序传递给requestPermissions()。
下面的代码检查应用程序允许读取用户的联系,必要时请求许可:
// 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.
}
}
注意:当您的应用程序调用requestPermissions(),系统显示一个标准对话框给用户。应用程序不能配置或改变对话框。如果需要提供任何信息或向用户解释,你应该这样做之前你叫requestPermissions(),解释为什么所述应用程序需要的权限。
处理权限请求响应
当应用程序请求权限,系统向用户提供了一个对话框。当用户响应,系统调用应用程序的onRequestPermissionsResult()方法,传递用户响应。你的应用必须覆盖那个方法来找出是否被授予许可。回调传递相同的请求代码传递给requestPermissions()。例如,如果一个应用程序请求READ_CONTACTS访问它可能回调方法如下:
@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
}
}
所示的对话框,系统描述了允许组织你的应用程序需要访问;它不特定的权限列表。举个例子,如果你请求READ_CONTACTS许可,该系统对话框只是说你的应用程序需要访问设备的联系人。一旦为每个用户只需要许可权限组。如果你的应用程序请求的任何其他权限组(应用程序清单中列出),系统自动赋予他们。请求许可时,系统调用你onRequestPermissionsResult()回调方法和通过PERMISSION_GRANTED,以同样的方式将如果用户有明确授予你的要求通过系统对话框。
注意:应用程序仍然需要每个许可需要显式地请求,即使用户已经允许另一个在同一组。此外,权限分组的分组可能改变未来的Android版本。你的代码不应该依赖于假设特定的权限或不在同一组。
例如,假设您在应用程序列表READ_CONTACTS和WRITE_CONTACTS清单。如果你请求READ_CONTACTS和用户授予权限,然后你请求WRITE_CONTACTS,系统立即授予许可没有与用户交互。
如果用户拒绝权限请求,应用程序应该采取适当的措施。例如,您的应用程序可能会显示一个对话框解释为什么它不能执行用户所请求的操作,需要许可。
当系统要求用户授予权限,用户可以选择告诉系统不要求许可了。在这种情况下,任何时候一个应用程序使用requestPermissions()要求权限,系统立即否认了这一请求。系统调用你onRequestPermissionsResult()回调方法和通过PERMISSION_DENIED,以同样的方式将如果用户已经明确拒绝了你的请求。这意味着当你叫requestPermissions(),你不能假设任何直接与用户交互。