从 Android 6.0 Marshmallow 开始,Android 使用 权限模型,可以简化应用安装和 自动更新过程系统会在运行时(而不是之前)请求权限 应用安装。此外,用户可以选择拒绝特定权限。 为了给用户提供这种灵活性,您需要确保应用的行为 在用户启用或停用特定权限时触发。
Google Play 服务本身具有运行时权限,用户可以选择 拒绝由您授予的权限之外, 应用。Google Play 服务会自动获取所需的所有权限 来支持其 API不过,您的应用仍应检查并请求运行时 必要时权限,并妥善处理用户 已向 Google Play 服务拒绝了应用使用的 API 所需的权限。
最好管理用户在设置权限时的期望 运行时可能需要的所有资源以下最佳做法有助于避免 潜在问题
前提条件
您需要在 AndroidManifest.xml
文件中声明权限。
例如:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
指南
在调用 API 之前验证权限
声明了要在代码中使用的 API 后,
AndroidManifest.xml
文件,请确保您拥有所需的权限
然后再调用 API。您可以使用 checkSelfPermission
方法完成此操作
(共 ActivityCompat
或 ContextCompat
)。
如果调用返回 false,则表示未授予权限,并且
应使用 requestPermissions
发出请求。其响应为
在回调中返回,您将在下一步中看到。
例如:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Check Permissions Now
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION);
} else {
// permission has been granted, continue as usual
Task<Location> locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation();
}
实现请求权限回调
如果用户尚未授予应用所需的权限,
应调用 requestPermissions
方法来询问
授予它们的权限。系统会从 Google Analytics
onRequestPermissionsResult
回调。您的应用应
实施此方法并始终检查返回值
遭拒或取消。您还可以通过以下方式请求和检查多项权限:
以下示例仅检查一项权限。
public void onRequestPermissionsResult(int requestCode,
String[] permissions,
int[] grantResults) {
if (requestCode == REQUEST_LOCATION) {
if(grantResults.length == 1
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// We can now safely use the API we requested access to
Task<Location> locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation();
} else {
// Permission was denied or request was cancelled
}
}
}
显示权限理由
如果您的应用请求的权限对于 应用,并且用户之前已拒绝权限请求,您的应用应 在再次请求权限之前显示附加说明。用户 当用户了解相关权限的原因时,就更有可能授予权限 以及为他们带来的直接利益。
在这种情况下,在调用 requestPermissions
之前,您应该先调用
shouldShowRequestPermissionRationale
。如果返回
true,那么您应该创建一些界面,以便显示
权限。
例如,您的代码可能如下所示:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Check Permissions Now
private static final int REQUEST_LOCATION = 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},
ACCESS_FINE_LOCATION);
}
} else {
// permission has been granted, continue as usual
Task<Location> locationResult = LocationServices
.getFusedLocationProviderClient(this /** Context */)
.getLastLocation();
}
处理连接故障
如果您的应用使用已废弃的 GoogleApiClient
,在您调用
connect()
,Google Play 服务会验证其是否已获取所有
需要必要的权限。如果有任何权限组,connect()
会失败
缺少 Google Play 服务本身所需的工具。
如果对 connect()
的调用失败,请确保您的应用会处理
正确。如果 Google Play 服务
本身缺少权限,您可以调用 startResolutionForResult()
来
启动用户体验流程来解决这些问题
例如:
@Override
public void onConnectionFailed(ConnectionResult result) {
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
showErrorDialog(result.getErrorCode());
mResolvingError = true;
}
}
较新的基于 GoogleApi
的 API 调用会自动显示一个对话框(如果
客户端通过 Activity
)或系统任务栏通知(如果
客户端通过 Context
进行了实例化),用户只需点按该按钮即可启动
权限解析 intent。调用将加入队列并重新进行,
权限。