一,序言
从 Android 6.0(API 级别 23)开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予。此方法可以简化应用安装过程,因为用户在安装或更新应用时不需要授予权限。它还让用户可以对应用的功能进行更多控制;例如,用户可以选择为相机应用提供相机访问权限,而不提供设备位置的访问权限。
二、权限的分类
系统权限分为两类:正常权限和危险权限:
1、正常权限:涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。
例如,设置时区的权限就是正常权限。如果应用声明其需要正常权限,系统会自动向应用授予该权限。
1 ACCESS_LOCATION_EXTRA_COMMANDS 2 ACCESS_NETWORK_STATE 3 ACCESS_NOTIFICATION_POLICY 4 ACCESS_WIFI_STATE 5 BLUETOOTH 6 BLUETOOTH_ADMIN 7 BROADCAST_STICKY 8 CHANGE_NETWORK_STATE 9 CHANGE_WIFI_MULTICAST_STATE 10 CHANGE_WIFI_STATE 11 DISABLE_KEYGUARD 12 EXPAND_STATUS_BAR 13 GET_PACKAGE_SIZE 14 INSTALL_SHORTCUT 15 INTERNET 16 KILL_BACKGROUND_PROCESSES 17 MODIFY_AUDIO_SETTINGS 18 NFC 19 READ_SYNC_SETTINGS 20 READ_SYNC_STATS 21 RECEIVE_BOOT_COMPLETED 22 REORDER_TASKS 23 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 24 REQUEST_INSTALL_PACKAGES 25 SET_ALARM 26 SET_TIME_ZONE 27 SET_WALLPAPER 28 SET_WALLPAPER_HINTS 29 TRANSMIT_IR 30 UNINSTALL_SHORTCUT 31 USE_FINGERPRINT 32 VIBRATE 33 WAKE_LOCK 34 WRITE_SYNC_SETTINGS
正常权限
2、危险权限:涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。
例如,能够读取用户的联系人属于危险权限。如果应用声明其需要危险权限,则用户必须明确向应用授予该权限。
3、权限组
所有危险的 Android 系统权限都属于权限组。
I、如果应用请求其清单中列出的危险权限,而应用目前在权限组中没有任何权限,则系统会向用户显示一个对话框,描述应用要访问的权限组。对话框不描述该组内的具体权限。例如,如果应用请求 READ_CONTACTS 权限,系统对话框只说明该应用需要访问设备的联系信息。如果用户批准,系统将向应用授予其请求的权限。
II、如果应用请求其清单中列出的危险权限,而应用在同一权限组中已有另一项危险权限,则系统会立即授予该权限,而无需与用户进行任何交互。例如,如果某应用已经请求并且被授予了 READ_CONTACTS 权限,然后它又请求 WRITE_CONTACTS,系统将立即授予该权限。
任何权限都可属于一个权限组,包括正常权限和应用定义的权限。但权限组仅当权限危险时才影响用户体验。可以忽略正常权限的权限组。
1 group:android.permission-group.CONTACTS 2 permission:android.permission.WRITE_CONTACTS 3 permission:android.permission.GET_ACCOUNTS 4 permission:android.permission.READ_CONTACTS 5 6 group:android.permission-group.PHONE 7 permission:android.permission.READ_CALL_LOG 8 permission:android.permission.READ_PHONE_STATE 9 permission:android.permission.CALL_PHONE 10 permission:android.permission.WRITE_CALL_LOG 11 permission:android.permission.USE_SIP 12 permission:android.permission.PROCESS_OUTGOING_CALLS 13 permission:com.android.voicemail.permission.ADD_VOICEMAIL 14 15 group:android.permission-group.CALENDAR 16 permission:android.permission.READ_CALENDAR 17 permission:android.permission.WRITE_CALENDAR 18 19 group:android.permission-group.CAMERA 20 permission:android.permission.CAMERA 21 22 group:android.permission-group.SENSORS 23 permission:android.permission.BODY_SENSORS 24 25 group:android.permission-group.LOCATION 26 permission:android.permission.ACCESS_FINE_LOCATION 27 permission:android.permission.ACCESS_COARSE_LOCATION 28 29 group:android.permission-group.STORAGE 30 permission:android.permission.READ_EXTERNAL_STORAGE 31 permission:android.permission.WRITE_EXTERNAL_STORAGE 32 33 group:android.permission-group.MICROPHONE 34 permission:android.permission.RECORD_AUDIO 35 36 group:android.permission-group.SMS 37 permission:android.permission.READ_SMS 38 permission:android.permission.RECEIVE_WAP_PUSH 39 permission:android.permission.RECEIVE_MMS 40 permission:android.permission.RECEIVE_SMS 41 permission:android.permission.SEND_SMS 42 permission:android.permission.READ_CELL_BROADCASTS
权限组
四、检查权限
如果您的应用需要危险权限,则每次执行需要这一权限的操作时您都必须检查自己是否具有该权限。用户始终可以自由调用此权限,因此,即使应用昨天使用了相机,它不能假设自己今天仍具有该权限。
要检查您是否具有某项权限,请调用 ContextCompat.checkSelfPermission() 方法。例如,以下代码段显示了如何检查 Activity 是否具有在日历中进行写入的权限:
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);
如果应用具有此权限,方法将返回 PackageManager.PERMISSION_GRANTED,并且应用可以继续操作。
如果应用不具有此权限,方法将返回 PERMISSION_DENIED,且应用必须明确向用户要求权限。
五、解释为什么需要权限
例如,如果用户启动一个摄影应用,用户对应用要求使用相机的权限可能不会感到吃惊,但用户可能无法理解为什么此应用想要访问用户的位置或联系人。在请求权限之前,不妨为用户提供一个解释。
为了帮助查找用户可能需要解释的情形,Android 提供了一个实用程序方法,即 shouldShowRequestPermissionRationale()。如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。
注:如果用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了 Don‘t ask again 选项,此方法将返回 false。
如果设备规范禁止应用具有该权限,此方法也会返回 false。
六、请求权限
如果应用尚无所需的权限,则应用必须调用一个 requestPermissions() 方法,以请求适当的权限。应用将传递其所需的权限,以及您指定用于识别此权限请求的整型请求代码。此方法异步运行:它会立即返回,并且在用户响应对话框之后,系统会使用结果调用应用的回调方法,将应用传递的相同请求代码传递到 requestPermissions()。
以下代码可以检查应用是否具备读取用户联系人的权限,并根据需要请求该权限:
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) {//显示为啥需要权限的理由 } else {//不需要解释,直接请求 ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); } }
七、处理权限请求的响应
当应用请求权限时,系统将向用户显示一个对话框。当用户响应时,系统将调用应用的 onRequestPermissionsResult() 方法,向其传递用户响应。您的应用必须替换该方法,以了解是否已获得相应权限。回调会将您传递的相同请求代码传递给 requestPermissions()。例如,如果应用请求 READ_CONTACTS 访问权限,则它可能采用以下回调方法:
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {//授权成功 } else {//授权被拒 } return; } } }