Skip to content

Most visited

Recently visited

navigation

应用权限最佳做法

权限请求可以保护设备中的敏感信息,并且仅应在应用为正常行使功能而必须访问这些信息时使用。利用本文档提供的技巧,您无需访问此类信息即可实现相同(或更好的)功能;但本文不会详细讨论权限在 Android 操作系统中的工作方式。

有关 Android 权限的一般信息,请参阅权限和用户数据。如需了解有关如何在您的代码中使用权限的详情,请参阅使用系统权限。有关使用唯一标识符的最佳做法,请参阅唯一标识符最佳做法

使用 Android 权限的原则

使用 Android 权限时,我们建议遵循以下原则:

#1: 仅使用您的应用正常工作所需的权限。根据您使用权限的方式,您可以通过其他方式执行您需要的操作(系统 intent、标识符、电话的后台处理),无需依赖敏感信息访问权限。

#2: 请注意库所需的权限。添加某个库时,您也会继承它的权限要求。您应了解您正在添加的库、它们需要的权限以及这些权限的用途。

#3:公开透明。进行权限请求时,请明确您正在访问的内容以及访问原因,以便用户可以做出明智的决定。在进行权限请求时(包括安装、运行时或更新权限对话框)提供这些信息。

#4:让系统以显式方式访问。在访问敏感功能(例如,相机或麦克风)时提供连续指示,让用户知道您在收集数据,避免让他们认为您偷偷地收集数据。

本指南剩下的部分将以开发 Android 应用为背景详细介绍这些规则。

Android 6.0+ 中的权限

Android 6.0 Marshmallow 引入了一个全新的权限模式,此模式让应用可以在运行时而不是在安装之前向用户请求权限。支持这个新模式的应用会在应用确实需要相关服务或这些服务保护的数据时请求权限。尽管这不会(不一定)改变整体应用行为,但它确实会使处理敏感用户数据的方式产生一些变化:

增加情境背景:如需获得访问这些权限组所涵盖功能的权限,则运行时在应用的背景中提示用户。用户将对请求权限的背景更加敏感,如果您请求的权限和您的应用用途不匹配,则一定要向用户详细解释您为什么请求此权限;您应尽可能在请求权限时以及后续对话框中(如果用户拒绝请求)提供请求权限的原因。

在授予权限时更加灵活用户可以在收到请求时可以在设置中拒绝访问具体权限的请求,但功能因此中断仍会让他们感到诧异。最好可以监控有多少用户拒绝权限请求(例如,使用 Google Analytics(分析)),以便您重构应用,从而避免依赖该权限,或更好地解释您的应用需要此权限才能正常工作的原因。您也应确保您的应用可以处理用户拒绝权限请求或在设置中关闭权限时产生的异常。

增加事务负担:系统将要求用户单独授予权限组的访问权限,而不是以集合的形式授予。这样一来,最大程度降低请求的权限数量就变得非常重要,因为数量多会增加用户授予权限的负担,并增大了至少有一个请求被拒绝的概率。

避免请求不必要的权限

此部分提供了常见用例的替代方法,有助于限制您请求的权限数量。由于向用户显示请求的权限数量和类型会影响下载量(与其他请求较少权限的类似应用相比),最好避免为不必要的功能请求权限。

通过实时用户请求访问相机/联系人

在这种情况下,您需要偶尔访问设备的相机或联系信息,并且不介意每次需要访问时都向用户要求权限。

如果您很少需要访问用户数据,换句话说,用户可以接受在您每次需要访问数据时向其显示运行时对话框,那么您可以使用一个基于 intent 的请求。Android 提供了一些应用无需请求权限即可使用的系统 intent,因为在系统发出基于 intent 的请求时用户选择了与应用共享的内容(如果有需要共享的内容)。

例如,您可以使用 MediaStore.ACTION_IMAGE_CAPTUREMediaStore.ACTION_VIDEO_CAPTURE 的 intent 操作类型采集图像或视频,无需直接使用 Camera 对象(或请求权限)。在这种情况下,每次采集图像时系统 intent 将代表您向用户要求权限。

丢失音频焦点后在后台运行

在此情况下,当用户接听来电时您的应用需要转入后台,并且仅在来电停止时重新聚焦。

出现此类情况(例如,媒体播放器在手机来电期间静音或暂停)时,通常采用的方法是使用 PhoneStateListener 或侦听 android.intent.action.PHONE_STATE 的广播,以此侦听来电状态有无变化。这种解决方法的问题是它需要 READ_PHONE_STATE 权限,这将强制用户授予广泛的敏感数据(如用户的设备和 SIM 硬件 ID 以及来电的电话号码)访问权限。

您可以通过为应用请求 AudioFocus 避免这个问题,该功能不需要显式权限(因为它不访问敏感信息)。只需在 onAudioFocusChange() 事件处理程序中将所需代码放入音频后台,当操作系统转换其音频焦点时它将自动运行。有关如何执行此操作的更详细文档,请参阅此处

确定正在运行实例的设备

在此情况下,您需要一个唯一标识符来确定您的应用实例正在哪个设备上运行。

应用可能具有设备特定的首选项或消息(例如,在云中为用户保存设备特定的播放列表,以便他们在车上和家里可以有不同的播放列表)。常见的解决方法是有效利用设备标识符,例如 Device IMEI,但这需要 Device ID and call information 权限组(M+ 中的 PHONE)。它还使用一个无法重置的标识符,并在所有应用中共享。

下面两种方法可以替代使用这些类型的标识符:

  1. 使用 com.google.android.gms.iid InstanceID API。getInstance(Context context).getID() 将为您的应用实例返回一个唯一设备标识符。结果得到一个应用实例作用域标识符,在存储与应用有关的信息时可以将该标识符用作密钥,在用户重新安装应用时此标识符将重置。
  2. 使用 randomUUID() 之类的基本系统函数创建您自己的标识符,其作用域仅限于应用存储空间。

为广告或用户分析创建唯一标识符

在此情况下,您需要一个唯一标识符,以便为没有登录您的应用的用户构建配置文件(例如,针对广告定位或测量转化率)。

为广告和用户分析构建配置文件有时需要一个与其他应用共享的标识符。此问题的常见解决方法包括有效利用设备标识符(例如 Device IMEI),设备标识符需要 Device ID and call information 权限组(API 级别 23+ 中的 PHONE),并且无法由用户重置。如果出现上述任何情况,除了使用不可重置的标识符并请求用户可能认为不寻常的权限外,还会违反 Play 开发者计划政策

遗憾的是,由于 ID 可能需要在各个应用中共享,在这些情况下使用 com.google.android.gms.iid InstanceID API 或系统函数创建应用作用域 ID 并不是适当的解决方法。一种替代解决方法是使用通过 getId() 方法从 AdvertisingIdClient.Info 类中获取的 Advertising Identifier。您可以使用 getAdvertisingIdInfo(Context) 方法创建一个 AdvertisingIdClient.Info 对象,并调用 getId() 方法来使用标识符。请注意,此方法正在冻结,因此,您不应从主线程调用它;有关此方法的详细说明请查看此处

了解您正在使用的库

有时,您在应用中使用的库需要一些权限。例如,广告和分析库可能要求访问 LocationIdentity 权限组以实现必需的功能。但从用户角度来说,权限请求来自于您的应用,而不是库。

由于用户会选择使用较少权限即可实现相同功能的应用,开发者应检查他们的库,并选择不使用非必要权限的第三方 SDK。例如,尽量避免使用需要 Identity 权限组的库,除非可以清楚地向用户解释应用为什么需要这些权限。具体而言,对于提供位置功能的库,请确保您不需要请求 FINE_LOCATION 权限,除非您正在使用基于位置的定位功能。

公开透明

您应通知用户您要访问的内容以及为什么要访问。研究显示,如果用户知道应用为什么需要相关权限,他们对权限请求的反感程度就会减弱。用户研究显示:

...用户是否愿意为给定移动应用授予既定权限在很大程度上受此类权限关联用途的影响。例如,用户是否愿意授予访问其位置的权限取决于该权限请求是否为支持应用的核心功能所必需,或者应用是否将与广告网络或分析公司分享此信息。1

卡内基梅隆大学 (CMU) 的 Jason Hong 教授基于他小组的研究得出一个总体结论:

...与只是告诉用户应用正在使用其位置相比,如果用户知道应用为什么使用位置等敏感信息(例如定向广告),那么,用户会更容易接受。1

因此,如果您仅使用归入权限组的一小部分 API 调用,明确列出您使用哪些权限以及使用原因会非常有用。例如:

在特定条件下,让用户实时了解您的应用对敏感数据的访问也是非常有益的。例如,如果您要访问相机或麦克风,通常最好在应用中的某个位置或在通知托盘中(如果应用正在后台运行)使用通知图标通知用户,从而不会让您看上去是在偷偷地收集数据。

最后,如果您需要请求权限以便在您的应用中运行某项功能,但用户不清楚原因,则需要找到一种方法让用户知道您为什么需要最敏感的权限。

参考

[1] Modeling Users’ Mobile App Privacy Preferences:Restoring Usability in a Sea of Permission Settings,作者:J. Lin B. Liu、N. Sadeh 和 J. Hong。SOUPS 2014 会议记录。

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)