# 1-概览\[Overview]

原文：<https://developer.android.com/guide/topics/permissions/overview>

本文为节选

## 0x00、 权限概述

权限的目的是保护 Android 用户的隐私。 App 在访问用户私有数据(例如短信和电话)和某系系统功能(例如照相机和网络)之前必须请求用户授权。 根据 app 使用功能的不同，有些操作系统会直接自动授予权限，另外的则需要用户亲自授予。

这篇文字提供了 Android 权限机制的工作概述，包括：

* 如何向用户展示应用所需要的权限
* 安装时授权和运行时授权的区别
* 如何强制执行权限
* 权限的类型和分类

如果你仅仅希望了解如何使用权限请阅读 [Request App Permission](https://developer.android.com/training/permissions/requesting.html)

## 0x01、 批准权限

App 必须在 manifest 文件中使用 `<uses-permission>` 公开声明自己所需要的权限。 例如，一个 App 需要发送短信的权限：

```markup
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.snazzyapp">

    <uses-permission android:name="android.permission.SEND_SMS"/>

    <application ...>
        ...
    </application>
</manifest>
```

如果你的 app 在 manifest 中列出的为一般权限(normal permission，用户隐私和设备操作不存在极大风险的权限)，系统将会自动将这些权限授予 App 。

如果你的 app 在 manifest 中列出的为危险权限(dangersou permission,通过这写权限可能影响用户隐私和设备常规操作)，例如 `SEND_SMS` ，用户必须明确的授予该权限 app 才能使用。

有关于此的更多信息请阅读 [Protection levels](https://developer.android.com/guide/topics/permissions/overview#normal-dangerous)

### 1.1、 危险权限的请求提示

只有危险权限需要用户授权。 Android OS 对用户的权限询问是基于 Android 自身版本和 app 的目标版本而决定的。

#### 1.1.1、 运行时请求(Android 6.0 及更高版本)

如果正在运行的设备是 Android 6.0(API level 23) 或者更高版本，并且 app 的 targetSdkVersion >= 23,在安装应用的时候不会被提示 app 的任何权限要求。 而作为 app 来说，必须在运行时请求用户授予危险权限。 当你的 app 想用户申请权限的时候，用户看到的界面如图(左)(通知用户 app 正在尝试访问哪一个权限组)。 提示框包含统一和拒绝两个按钮。

如果用户拒绝了授予权限，你的 app 在下次请求权限的时候对话框中会包含一个 checkbox 如图(右) ，如果勾选了 checkbox ，意味着用户不希望再次被询问是否授予该权限。

* ![permission dialog](https://367934832-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LDeXfeEQtIhAnhzIOAV%2F-LR70oZlg6uHIwNshnIX%2F-LR70qA6RM1vWcXvL4Tw%2F2018-10-11_permission_dialog.png?generation=1542027964364582\&alt=media)

如果用户勾选了不在询问按钮并且未授予权限，那么 app 在后续请求使用相同权限的时候系统将不再询问用户，直接不授予该权限。

甚至如果用户授予了你权限，你也不能太过依赖该权限。 因为用户随时可以到设置中取消对应用的任何授权。 你应该总是在使用权限之前检查应用是否具有该权限。

有关于此的更多信息请查看 [Request App Permission](https://developer.android.com/training/permissions/requesting.html)

#### 1.1.2、 安装时请求(Android 5.1.1 及更低版本)

如果设备运行于 Android 5.1.1 (API level 22) 或者更低版本，或者 targetSdkVersion <= 22 ,系统将会在安装 App 的时候自动询问用户是否授予应用所需要的所有权限。如图：

* ![permission dialog](https://367934832-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LDeXfeEQtIhAnhzIOAV%2F-LR70oZlg6uHIwNshnIX%2F-LR70qA8vYiLgmOW5POZ%2F2018-10-11_install_time_permissions_dialog_2x.png?generation=1542027964691330\&alt=media)

如果用户点击 Accept,所有 app 请求的权限都会被授予。 如果用户拒绝权限请求系统将会停止安装该应用。

如果一个 app 的更新包中包含了新的权限，在更新之前需要先得到用户的确认。

要了解受推崇的权限请求模式请阅读：[App Permission Best Practices](https://developer.android.com/training/permissions/usage-notes.html)

要了解如何检查和请求权限请阅读： [Request App Permissions](https://developer.android.com/training/permissions/requesting.html)

## 0x02、 操作硬件功能的权限

要操作某些硬件(例如蓝牙和相机)需要应用权限。 然而，不是所有的 Android 设备都需要硬件功能。 所以如果你的 app 请求 CAMERA 权限，一件重要的事是你需要在 manifest 文件中用 `<uses-feature>` 节点声明这个功能你是否你应用必要的需求。例如：

```markup
<uses-feature android:name="android.hardware.camera" android:required="false" />
```

如果你声明 `android:required-"false"` ,Google Play 将允许你的应用被安装到不支持对应功能的设备上。 这种情况下，你必须在运行时通过调用 `PackageManager.hasSystemFeature()` 进行权限检查，如果请求的功能不可用可以优雅的做出回应。

如果你没有提供 `<uses-feature>` 标签， Google Play 看到你响应的权限标签会认为你的应用需要这个权限。 所以它会过滤你的 app 在目标设备之外，和你声明了 `<uses-feature>` 并且 `android:required="true"` 的效果相同。

更多信息请查阅 [Google Play and feature-based filtering](https://developer.android.com/guide/topics/manifest/uses-feature-element.html#market-feature-filtering)

## 0x03、 强制权限

权限不仅仅想系统申请。 提供服务的应用也可以自定义权限去限制它们的使用者。 关于此的更多信息请查阅 [Define a Custom App Permission.](https://developer.android.com/guide/topics/permissions/defining.html)

### 3.1、 Activity 强制权限

manifest 文件中 `<activity>` 节点中的 `android:permisssion` 属性决定了谁能启动这个 activity 。 在调用 Context.startActivity() 和 Activity.startActivityForResult() 的时候被调用者会检查调用者是否具有足够的权限。 如果调用者没有足够的权限会抛出 SecurityException 异常。

### 3.2、 Service 强制权限

manifest 文件中 `<service>` 节点中的 `android:permisssion` 属性决定了谁能启动这个 Service 。 在调用 Context.startService(), Context.stopService() 和 Context.bindService() 的时候被调用者会检查调用者是否具有足够的权限。 如果调用者没有足够的权限会抛出 SecurityException 异常。

### 3.3、 Broadcase 强制权限

manifest 文件中 `<receiver>` 节点中的 `android:permisssion` 属性决定了谁能向这个 BroadcastReceiver 发送广播 。 在调用 Context.sendBroadcast() 之后，权限被检查并被 return ，因为系统试图将广播传递给特定的接收者。 因此如果没有足够的权限，调用者不会抛出异常，只是它的意图(Intent)无法传递给需要权限的 BroadcastReceiver 。

本小节其余：略……

### 3.4、 Content Provider 强制权限

略……

### 3.5、 URI 权限

### 3.6、 其他强制权限

在调用服务的时候可以强制授予任何权限。 这通过 Context.checkCallPermission() 方法完成。 携带期望的权限字段调用该方法可以得到一个用于判断某一个进程所期望的权限是否被授予的 int 标识。 注意，这只用于跨进程调用，通常通过 IDL 接口叫用接口个或者其他方式跨进程调用。

这里有一些其他的方式检查权限授予情况。 如果你有另一个进程的 ID(PID),你能调用 Context.checkPermission() 方法检查针对该 PID 的权限。 如果你有另一个 app 的包名，你能通过 PackageManager.checkPermission() 方法判断目标 app 是否已经被授予特定权限。
