Android6.0以前
所有权限都在安装应用时显示给用户,用户选择安装则表示接受这些权限,之后无法撤销授权。
Android6.0开始
在安装应用时,部分危险权限会展示给用户,默认不勾选,用户可选择授权,并可以在安装之后进入设置撤销授权。
Dangerous permissions:
- CALENDAR
- READ_CALENDAR
- WRITE_CALENDAR
- CAMERA
- READ_CALENDAR
- WRITE_CALENDAR
- CONTACTS
- READ_CONTACTS
- WRITE_CONTACTS
- GET_ACCOUNTS
- LOCATION
- ACCESS_FINE_LOCATION
- ACCESS_COARSE_LOCATION
- MICROPHONE
- RECORD_AUDIO
- PHONE
- READ_PHONE_STATE
- CALL_PHONE
- READ_CALL_LOG
- WRITE_CALL_LOG
- ADD_VOICEMAIL
- USE_SIP
- PROCESS_OUTGOING_CALLS
- SENSORS
- BODY_SENSORS
- SMS
- SEND_SMS
- RECEIVE_SMS
- READ_SMS
- RECEIVE_WAP_PUSH
- RECEIVE_MMS
- STORAGE
- READ_EXTERNAL_STORAGE
- WRITE_EXTERNAL_STORAGE
权限详细信息查看
想要查看所有dangerous的权限, 也可以用命令:adb shell pm list permissions -g -d
Guides里面的原文:
- If the device is running Android 6.0 (API level 23) or higher, and the app’s targetSdkVersion is 23 or higher, the app requests permissions from the user at run-time. The user can revoke the permissions at any time, so the app needs to check whether it has the permissions every time it runs. For more information about requesting permissions in your app, see the Working with System Permissions training guide.
- If the device is running Android 5.1 (API level 22) or lower, or the app’s targetSdkVersion is 22 or lower, the system asks the user to grant the permissions when the user installs the app. If you add a new permission to an updated version of the app, the system asks the user to grant that permission when the user updates the app. Once the user installs the app, the only way they can revoke the permission is by uninstalling the app.
只有满足targetSdkVersion和实际使用设备的版本都在23及以上的时候,才会采用新的动态权限机制. 其他情况, 跟之前一样, 在安装和升级应用的时候就授权了所有的权限.
如果targetSdkVersion小于23,即被认为是Android 6.0发布之前开发的应用, 还没有兼容6.0.
这种应用即便是被装在Android 6.0的机器上,也是采用原来的安装即授予权限逻辑, 所有权限在应用安装时全部被授权.
在Android 6.0的设备上安装targetSdkVersion小于23的应用之后, 可以在应用的设置中查看,发现所有的dangerous权限状态都是打开.
但是用户仍然可以在系统设置中禁用权限
因为权限动态检查相关的API是Android 6.0才加入的, 所以minSdkVersion不是23时,推荐使用SupportLibrary来实现,好处是: 程序里不必加if来判断当前设备的版本.support的包必须是23以上才可以.
下面来讲讲代码中如何适配这种新的权限机制:
1.检查权限状态
如果在执行操作需要一个dangerous permission,那么每次执行操作都必须检查是否有这个权限,因为用户可以随意更改授权,所以必须每次都进行检查,比如我这里需要选择照片就需要加如下代码:
2.动态请求权限
如果上面的判断没有权限,那么就需要显式的请求这个权限,Android提供了方法来动态请求权限,调用这些方法会弹出标准的dialog,目前这个dialog不能被定制。
2.1有时候可能需要解释为什么需要这个权限
一种方式是,当用户拒绝过这个权限,但是又用到了这个功能, 那么很可能用户不是很明白为什么app需要这个权限, 这时候就可以先向用户解释一下.
为了发现这种用户可能需要解释的情形, Android提供了一个工具类方法: shouldShowRequestPermissionRationale()
如果app之前请求过该权限,被用户拒绝, 这个方法就会返回true.
如果用户之前拒绝权限的时候勾选了对话框中”Don’t ask again”的选项,那么这个方法会返回false.
如果设备策略禁止应用拥有这条权限, 这个方法也返回false.
具体解释原因的这个dialog需要自己实现, 系统没有提供.
|
|
2.2请求权限
请求权限的方法分两种
一种是在Activity里面请求使用如下方法
requestPermissions(final @NonNull Activity activity,
final @NonNull String[] permissions, final int requestCode)
传入一个Activity, 一个permission名字的数组, 和一个整型的request code.
这个方法是异步的,它会立即返回, 当用户和dialog交互完成之后,系统会调用回调方法,传回用户的选择结果和对应的request code.
示例代码:
一种是在Fragment里面请求
requestPermissions(@NonNull String[] permissions, int requestCode)
少一个Activity参数,其他一样,但是回调需要特别说明,还有fragment嵌套fragment的回调处理情况,下面会单独说明。
2.3处理请求权限的响应
当用户对请求权限的dialog做出响应之后,系统会调用onRequestPermissionsResult() 方法,传回用户的选择结果和request code.
这个回调中request code即为调用requestPermissions()时传入的参数,是app自定义的一个整型值.
如果请求取消,返回的数组将会为空.
代码如下:
在Fragment中申请权限,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的 onRequestPermissionsResult
如果在Fragment中嵌套Fragment,在子Fragment中使用requestPermissions方 法,onRequestPermissionsResult不会回调回来,建议使用 getParentFragment().requestPermissions方法,这个方法会回调到父Fragment中的onRequestPermissionsResult,加入以下代码可以把回调透传到子Fragment
|
|