权限最佳做法

应用如果一味要求用户提供授权,可能会让用户无所适从。如果用户发现应用难以使用,或者担心应用会滥用其信息,他们可能不愿意使用该应用,甚至会将其完全卸载。以下最佳做法有助于避免此类糟糕的用户体验。

考虑使用 intent

许多情况下,您可以使用以下两种方式之一来让您的应用执行某项任务。您可以将应用设置为要求提供权限才能执行操作。或者,您可以将应用设置为使用 intent,让其他应用来执行任务。

例如,假设应用需要使用设备相机才能够拍摄照片。应用可以请求 CAMERA 权限,以便允许其直接访问相机。然后,应用将使用 Camera API 控制相机并拍摄照片。利用此方法,您的应用能够完全控制摄影过程,并支持您将相机 UI 整合至应用中。

不过,如果您无需此类完全控制,则可以使用 ACTION_IMAGE_CAPTURE intent 来请求图像。发送该 intent 时,系统会提示用户选择相机应用(如果没有默认相机应用)。用户使用选定的相机应用拍摄照片,该相机应用会将照片返回给应用的 onActivityResult() 方法。

同样,如果您需要拨打电话、访问用户的联系人或要执行其他操作,可以通过创建适当的 intent 来完成,或者您也可以请求相应的权限并直接访问相应的对象。每种方法各有优缺点。

如果使用权限:

  • 您的应用可在您执行操作时完全控制用户体验。不过,如此广泛的控制会增加任务的复杂性,因为您需要设计适当的 UI。
  • 系统会在运行或安装应用时各提示用户提供一次权限(具体取决于用户的 Android 版本)。之后,应用即可执行操作,不再需要用户进行其他交互。不过,如果用户不授予权限(或稍后撤销权限),您的应用将根本无法执行操作。

如果使用 intent:

  • 您无需为操作设计 UI。处理 intent 的应用将提供 UI。不过,这意味着您无法控制用户体验。用户可能与您从未见过的应用交互。
  • 如果用户没有适用于操作的默认应用,则系统会提示用户选择一款应用。如果用户未指定默认处理程序,则他们每次执行此操作时都必须处理一个额外对话框。

仅要求您需要的权限

每次您要求权限时,实际上是在强迫用户作出决定。您应尽量减少提出这些请求的次数。如果用户运行的是 Android 6.0(API 级别 23)或更高版本,则每次用户尝试要求提供权限的新应用功能时,应用都必须中断用户的操作并发起权限请求。如果用户运行的是较早版本的 Android,则在安装应用时需要为应用的每一权限请求给予授权;如果列表过长或看起来不合适,用户可能会决定不安装该应用。为此,您应尽量减少应用需要的权限数。

例如,很多情况下应用可以通过使用 intent 来避免请求权限。如果某项功能并非应用的核心功能,不妨考虑将相关工作交给其他应用来执行,如考虑使用 intent 中所述。

不要让用户感到无所适从

如果用户运行的是 Android 6.0(API 级别 23)或更高版本,则用户必须在应用运行时为其授权。如果您的应用一次要求用户提供多项权限,用户可能会感到无所适从并因此退出应用。您应根据需要请求权限。

某些情况下,一项或多项权限可能是应用所必需的。在这种情况下,合理的做法是,在应用启动之后立即要求提供这些权限。例如,如果您运行摄影应用,应用需要访问设备的相机。在用户首次启动应用时,他们不会对提供相机使用权限的要求感到惊讶。但是,如果同一应用还具备与用户联系人共享照片的功能,您不应在应用首次启动时要求用户提供 READ_CONTACTS 权限,而应等到用户尝试使用“共享”功能之后,再要求提供该权限。

如果应用提供了教程,则合理的做法是,在教程结束时请求提供应用的必要权限。

解释需要权限的原因

系统在您调用 requestPermissions() 时显示的权限对话框将说明应用需要的权限,但不会解释为何需要这些权限。某些情况下,用户可能会感到困惑。因此,最好在调用 requestPermissions() 之前向用户解释应用需要相应权限的原因。

例如,摄影应用可能需要使用位置服务,以便能够为照片添加地理标签。通常,用户可能不了解照片能够包含位置信息,并且对摄影应用想要了解具体位置感到不解。因此在这种情况下,应用最好在调用 requestPermissions() 之前告知用户此功能的相关信息。

告知用户的一种办法是将这些请求纳入应用教程。这样,教程可以依次显示应用的每项功能,并在显示每项功能时解释需要哪些相应的权限。例如,摄影应用的教程可以演示其“与您的联系人共享照片”功能,然后告知用户需要为应用授予权限才能查看用户的联系人。然后,应用可以调用 requestPermissions(),要求用户提供该访问权限。当然,并非所有用户都会按照教程操作,因此您仍需在应用的正常操作期间检查和请求权限。

测试两种权限模式

从 Android 6.0(API 级别 23)开始,用户是在运行时而不是在应用安装时授予或撤销应用权限。因此,您应在多种不同条件下测试应用。在低于 Android 6.0 的版本中,您可以认为如果应用得到运行,它就可以得到在应用清单中声明的全部权限。在新的权限模式中,这一推断不再成立。

以下提示可帮助您识别在运行 API 级别 23 或更高级别的设备上与权限有关的代码问题:

  • 识别应用的当前权限和相关的代码路径。
  • 在各种受权限保护的服务和数据中测试用户流程。
  • 使用授予或撤销权限的各种组合进行测试。例如,相机应用可能会在清单中列出 CAMERAREAD_CONTACTSACCESS_FINE_LOCATION。您应在测试应用时逐一打开和关闭这些权限,确保应用可以妥善处理所有权限配置。请记住,自 Android 6.0 起,用户可以打开或关闭任何应用的权限,即使面向 API 级别 22 或更低级别的应用也是如此。
  • 使用 adb 工具从命令行管理权限:
    • 按组列出权限和状态:
      $ adb shell pm list permissions -d -g
    • 授予或撤销一项或多项权限:
      $ adb shell pm [grant|revoke] <permission-name> ...
  • 针对使用权限的服务对应用进行分析。