每款 Android 应用都在访问受限的沙盒中运行。如果应用需要使用其自己的沙盒外的资源或信息,则必须请求相应权限。 要声明您的应用需要某项权限,您可以在应用清单中列出该权限,然后在运行时请求用户批准每项权限(适用于 Android 6.0 及更高版本)。

本页介绍如何使用 Android 支持库来检查和请求权限。Android 框架从 Android 6.0(API 级别 23)开始提供类似的方法,但如果使用支持库,将会更容易与较低的 Android 版本实现兼容性。

向清单添加权限

对于所有 Android 版本,要声明应用需要某项权限,请在应用清单中添加 <uses-permission> 元素,作为顶级 <manifest> 元素的子项。例如,需要访问互联网的应用需在清单中添加以下代码行:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.snazzyapp"> <uses-permission android:name="android.permission.INTERNET"/>
<!-- other permissions go here --> <application ...>
...
</application>
</manifest>

 

系统在您声明权限之后的行为取决于权限的敏感程度。有些权限被视为“常规”权限,因此系统会在安装应用时立即授予这些权限。还有些则被视为“危险”权限,因此需要用户明确向您的应用授予相应访问权限。如需详细了解不同类型的权限,请参阅保护级别

检查权限

如果应用需要一项危险权限,那么每次执行需要该权限的操作时,您都必须检查自己是否具有该权限。从 Android 6.0(API 级别 23)开始,用户可随时从任何应用撤消权限,即使应用以较低的 API 级别为目标平台也是如此。因此,即使应用昨天使用了相机,也不能认为它今天仍具有该权限。

要检查您是否具有某项权限,请调用 ContextCompat.checkSelfPermission() 方法。例如,以下代码段展示了如何检查 Activity 是否具有向日历写入数据的权限:


   
java代码:

    if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
} kotlin代码: if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
}

  

如果应用具有此权限,该方法将返回 PERMISSION_GRANTED,并且应用可以继续操作。如果应用不具备此权限,该方法将返回 PERMISSION_DENIED,且应用必须明确要求用户授予权限。

请求权限

当您的应用从 checkSelfPermission() 收到 PERMISSION_DENIED 时,您需要提示用户授予该权限。Android 为您提供了几种可用来请求权限的方法(如 requestPermissions()),如下面的代码段所示。调用这些方法时,会显示一个无法自定义的标准 Android 对话框。

如何向用户显示此内容取决于设备的 Android 版本以及应用的目标版本,如权限概览中所述。

解释为什么应用需要权限

在某些情况下,您需要帮助用户理解为什么您的应用需要某项权限。例如,如果用户启动一款摄影应用,用户或许不会对该应用请求使用相机的权限感到惊讶,但用户可能不理解为什么该应用想要访问用户的位置或联系人。在您的应用请求权限之前,不妨考虑向用户提供解释。请注意,您肯定不希望您的解释让用户不胜其烦;如果您提供太多解释,用户可能会觉得这款应用很麻烦,因而将其移除。

您可以使用的一种方法是只在用户之前拒绝过该权限请求的情况下才提供解释。Android 提供了一种实用程序方法,即 shouldShowRequestPermissionRationale()。如果用户之前拒绝了该请求,该方法将返回 true;如果用户之前拒绝了某项权限并且选中了权限请求对话框中的不再询问选项,或者如果设备政策禁止该权限,该方法将返回 false

如果用户不断尝试使用需要某项权限的功能,但一直拒绝权限请求,这或许意味着,用户不理解为什么应用需要该权限才能提供这项功能。在这种情况下,显示解释或许是不错的做法。

应用权限最佳做法中提供了更多建议,指导您如何在请求权限时创造良好的用户体验。

在必要时请求成为默认处理程序

有些应用依赖于访问与通话记录和短信有关的敏感用户信息。如果您想请求特定于通话记录和短信的权限,并将应用发布到 Play 商店,则必须在请求这些运行时权限之前提示用户将应用设置为“默认处理程序”以获得核心系统功能。

如需详细了解默认处理程序(包括有关如何向用户显示默认处理程序提示的指南),请参阅有关仅在默认处理程序中使用的权限的指南

请求您需要的权限

如果您的应用还不具备它需要的权限,那么它必须调用一个 requestPermissions() 方法来请求相应权限。您的应用将传递它想要的权限,以及您指定用于识别此权限请求的整数请求代码。此方法异步运行。它会立即返回结果,并且在用户响应提示后,系统会利用相应结果来调用应用的回调方法,在调用过程中传递的请求代码与应用传递给 requestPermissions() 的请求代码相同。

以下代码将检查应用是否具有读取用户联系人的权限。如果没有该权限,它会检查是否应显示需要该权限的解释,如果不需要解释,它会请求该权限:

java代码:

    // Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) { // Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an explanation 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; 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.
}
} else {
// Permission has already been granted
} kotlin代码: // Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) { // Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an explanation 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,
arrayOf(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.
}
} else {
// Permission has already been granted
}

  

系统显示的提示说明了您的应用需要访问的权限组,而不是具体权限。

注意:当您的应用调用 requestPermissions() 时,系统会向用户显示一个标准对话框。您的应用无法配置或更改该对话框。如果您需要向用户提供任何信息或解释,您应该在调用 requestPermissions() 之前这样做,如解释为什么应用需要权限中所述。

处理权限请求响应

当用户响应您应用的权限请求时,系统会调用您应用的 onRequestPermissionsResult() 方法,在调用过程中向其传递用户响应。您的应用必须替换该方法,以查明是否已向其授予相应权限。在回调过程中传递的请求代码与传递给 requestPermissions() 的请求代码相同。例如,如果应用请求 READ_CONTACTS 访问权限,则它可能采用以下回调方法:

java代码:

    @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.
}
} kotlin代码: override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_READ_CONTACTS -> {
// If request is cancelled, the result arrays are empty.
if ((grantResults.isNotEmpty() && 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
} // Add other 'when' lines to check for other
// permissions this app might request.
else -> {
// Ignore all other requests.
}
}
}

  

 

系统显示的对话框说明了您的应用需要访问的权限组,它不会列出具体权限。例如,如果请求 READ_CONTACTS 权限,系统对话框只会说明您的应用需要访问设备的联系人。用户只需要针对每个权限组授予一次权限。如果您的应用请求该组中的其他任何权限(已在您的应用清单中列出),系统会自动授予这些权限。当您请求权限时,系统会调用您的 onRequestPermissionsResult() 回调方法并传递 PERMISSION_GRANTED,就像用户通过系统对话框明确同意了您的请求时的处理方式一样。

注意:您的应用仍需要明确请求它需要的每项权限,即使用户已授予同一组中的其他权限。此外,权限分组在将来的 Android 版本中可能会发生变化。您的代码不应依赖于特定权限属于或不属于同一组的假设。

例如,假设您在应用清单中同时列出了 READ_CONTACTS 和 WRITE_CONTACTS。如果您请求 READ_CONTACTS 且用户授予了该权限,那么当您随后又请求 WRITE_CONTACTS 时,系统会立即授予您该权限,而无需与用户交互。

如果用户拒绝了权限请求,您的应用应采取适当的措施。例如,您的应用可能会显示一个对话框,解释它为什么无法执行用户请求的需要该权限的操作。

当系统要求用户授予某项权限时,用户可以选择告知系统不要再次请求该权限。在这种情况下,只要应用使用 requestPermissions() 再次请求该权限,系统就会立即拒绝请求。系统会调用您的 onRequestPermissionsResult() 回调方法并传递 PERMISSION_DENIED,就像用户再次明确拒绝了您的请求时的处理方式一样。如果设备政策禁止应用具有该权限,该方法也会返回 false。这意味着,当您调用 requestPermissions() 时,您不能假定已经发生与用户的任何直接交互。

要在请求应用权限时提供最佳用户体验,另请参阅应用权限最佳做法

按 API 级别声明权限

要仅在支持运行时权限的设备(即运行 Android 6.0(API 级别 23)或更高版本的设备)上声明某项权限,请添加 uses- permission-sdk-23 标记,而不是 uses-permission 标记。

使用这些标记中的任意一个时,您均可设置 maxSdkVersion 属性,以指定在运行更高版本的设备上不需要特定权限。

Android复习(四)权限—>请求应用权限的更多相关文章

  1. Xamarin Android权限请求

    Xamarin Android权限请求   Android权限规定了App是否可以访问特定的资源,如网络.电话和短信.在原有API 6.0之前,App在安全的时候,会请求一次权限.一旦安装后,App就 ...

  2. android 学习十四 探索安全性和权限

    1.部署安全性:应用程序必须使用数字证书才能安装到设备上. 2.执行期间的安全性:    2.1 使用独立进程    2.2 使用固定唯一用户ID    2.3  申明性权限模型   3数字证书   ...

  3. Android 6.0 权限请求

    在申请权限之前一定要在清单配置文件中添加该权限private static final int MY_PERMISSIONS_REQUEST_RECORD_AUDIO = 1; //随便定义 publ ...

  4. android请求root权限

    应用获取Root权限的原理:让应用的代码执行目录获取最高权限.在Linux中通过chmod 777 [代码执行目录] //请求root权限    public static boolean upgra ...

  5. 【朝花夕拾】Android安全之(一)权限篇

    前言        从Android6.0开始,Android系统对权限的处理产生了很大的变化.如果APP运行的设备系统版本为Android6.0或更高,并且target在23或更高,那么danger ...

  6. 运行时权限请求框架easypermissions

    前言 之前使用过AndPermission权限申请库,当开发者执行有权限的代码发生异常时,AndPermission会抓到异常并回调到失败中,这里要注意的是会抓到任何异常,不仅仅是没有权限时的异常. ...

  7. Android自定义权限和使用权限

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 自定义权限,主要用于保护被赋予权限的组件.如无权限与有权限,正如public与private的对类保 ...

  8. Android M新的运行时权限开发者需要知道的一切

    android M 的名字官方刚发布不久,最终正式版即将来临!android在不断发展,最近的更新 M 非常不同,一些主要的变化例如运行时权限将有颠覆性影响.惊讶的是android社区鲜有谈论这事儿, ...

  9. Android 6.0的运行时权限

    原文  http://droidyue.com/blog/2016/01/17/understanding-marshmallow-runtime-permission/ 主题 安卓开发   Andr ...

  10. Android 开发技巧 - Android 6.0 以上权限大坑和权限检查基类封装

    简单介绍 关于运行时权限的说法,早在Google发布android 6.0的时候,大家也听得蛮多的.从用户的角度来讲,用户是受益方,更好的保护用户的意思,而对于开发者来说,无疑增加了工作量. 对于6. ...

随机推荐

  1. 【MongoDB】Re03 索引

    MongoDB的索引种类 单属性索引 MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index). 对于单个字段索引和排序操作,索引键的排 ...

  2. 【IDEA】找不到类资源

    报错问题描述: 找不到这个实例调用的方法或者方法缺失重载 找不到这个声明的类资源 解决情况一 import声明缺失,IDEA智能导包提示可以解决 注意,如果存在了重名的类资源,导入了错误的资源,实例引 ...

  3. 利用强化学习算法解释人类脑对高维状态的抽象表示:how humans can map high-dimensional sensory inputs in actions

    论文: <Using deep reinforcement learning to reveal how the brain encodes abstract state-space repre ...

  4. 人工智能Python代码的补全利器 Kite 安装

    代码补全应用kite主要对Python代码进行补全,或者说kite是针对现在的人工智能Python代码(pytorch.tensorflow)等做补全的,而且在Python代码补全上kite可以说是现 ...

  5. 英特尔Movidius神经计算棒的介绍

    手上有一款英特尔Movidius神经计算棒,本打算疫情结束返回学校,突然得到非官方的通知告诉我只能等到9月份返校了,于是就想起这个被闲置的计算棒了,手上的是1代的计算棒,不过1代的和二代的使用起来方法 ...

  6. 多线程之park()与interrupt()的理解

    1.背景 其他不多说,很多时候面试会问 2.代码 package com.ldp.demo01; import com.common.MyThreadUtil; import lombok.exter ...

  7. Leetcode: 586. Customer Placing the Largest Number of Orders

    题目要求如下: 给出的例子如下: 简单地说就是要找出表中订单最多客户的ID. 使用如下的代码进行实现: import pandas as pd def largest_orders(orders: p ...

  8. 金融、支付行业的开发者不得不知道的float、double计算误差问题

    为什么浮点数 float 或 double 运算的时候会有精度丢失的风险呢? <阿里巴巴 Java 开发手册>中提到:"浮点数之间的等值判断,基本数据类型不能用 == 来比较,包 ...

  9. PySide6/PyQt开发经验总结(2) - 设置快捷键

    Qt设置快捷键 本文仅供本人知识总结使用,所以内容会比较浅显,不喜勿喷. 目录 Qt设置快捷键 一.需要的类 QShortcut 函数: 二.设置快捷键 官方文档原文翻译: 我的理解: 一.需要的类 ...

  10. 如何使用 Shebang

    什么是 Shebang? 简单来说,就是你在脚本开头看到的这个: #!/usr/bin/bash Shebang(也称为 hash-bang.pound-bang 或者 bang)是一个作为脚本文件中 ...