前言
在 Android 6.0 之后的系统,除了要在 AndroidManifest.xml 文件中声明需要使用的权限,部分危险权限还需要在运行程序的过程中动态向用户申请。
在 AndroidManifest.xml 中申请权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp" >
<uses-permission android:name="android.permission.RECEIVE_SMS" />
...
</manifest>
危险权限列表
Permission Group | Permissions |
---|---|
CALENDAR | READ_CALENDAR \ WRITE_CALENDAR |
CAMERA | CAMERA |
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 |
注意事项
- 危险权限有分组,在申请分组中的其中一个权限后,可以获得该分组中所有权限的使用权。
- 一次可以申请多个不同分组的权限,用户会进行多次授权,假若是同一分组的不同权限,因为如上原因,系统只对同一分组中的第一个权限进行一次用户授权询问。
- 假若用户已经同意该权限,再次申请会继续弹出对话框让用户选择,且假若用户拒绝会导致 Activity 摧毁再恢复,使得在 Fragment 中申请的权限没有系统回调。所以最好在申请前进行判断,以防万一。
运行时权限获取
使用 Activity
Activity#requestPermissions() 方法要求 min API level >= 23 才能使用,因为这是 Android M 才推出的需求,所以可以使用 support-v4 包中的 ActivityCompat#requestPermissions() 方法替代以做到向下兼容。
代码示例:
public static final int REQEST_CODE = 0;
public void example(){
if(Build.VERSION.SDK_INT >= 23){
int checkPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.XXX);
if(checkPermission != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(context,new String[]{Manifest.permission.XXX},REQEST_CODE);
return;
}else{
//do something
}
}else{
// do something
}
}
使用 Fragment
如果使用的是 support-v4 包中的 Fragment,可以直接使用 requestPermissions() 申请权限,否则同上。在这里推荐使用 support 包中的 Fragment 而不使用 SDK 中的,因为 support 包中的 Fragment 会比 SDK 中的功能更多,而且可以自由更新不受系统版本影响。
用户响应后的系统回调
系统会回调 onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
方法。
- requestCode 为申请时传递的值
- permissions 为申请的权限
- grantResults 为对应权限的获取结果,permissions[i] 对应 grantResults[i]
示例代码:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
switch(requestCode){
case REQEST_CODE:{
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
// Permission Granted
}else{
// Permission Denied
}
break;
}
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
需要注意的是,onRequestPermissionsResult() 方法回在 Activity 恢复前调用,所以不可以在该方法中 commit FragmentTransaction,需要使用 commitAllowingStateLoss 替代。
网友评论