liubobuzhidao

android之动态权限

​ android系统自M版本开始后使用了新的权限策略—-动态权限管理,App使用到的权限不再是在安装时就进行,而是在运行时才申请。

​ 谷歌将权限分为两类:普通权限、危险权限。普通权限和之前的用法一样,直接在清单文件中添加就行,而危险权限则需要在使用的时候得到了用户的授权后才能使用。

普通权限如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
FLASHLIGHT
GET_PACKAGE_SIZE
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
SET_ALARM
INSTALL_SHORTCUT
UNINSTALL_SHORTCUT

可以看出上述权限都是和手机本身有关的功能,而用户数据的权限都是危险权限(例如读写sd卡的权限),

机制发生改变对应的功能也就发生了改变,在API23中新增了一个和权限有关的接口,第一个是用于检查权限的接口,该接口可以通过ContextCompat调用,也可以在当前的activity里直接调用。

1
ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);

该接口的返回值代表权限查询的结果,PackageManager.PERMISSION_GRANTED表示用户已授权,PackageManager.PERMISSION_DENIED表示用户还没有授权,这时需要另外一个接口申请权限,这个方法在使用时不需要再判断系统版本,因为方法内部会区分版本 ,如果是API23以下的会直接通过检查清单文件的方式进行。

1
requestPermissions(Activity activity,String[] permissions,int requestCode)

参数说明:activity说明权限申请必须放在主线程中进行,第二个字符串数组是需要申请的权限组 ,第三个是请求码用以标识是哪个权限的返回码,一般来讲在一个界面里面会申请一个权限,申请以后会有个回调接口来确定究竟是否得到权限,

1
重写Activity里面的onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)方法

参数说明:requestCode申请权限时携带的那个值,grantResults记录了每个权限申请的结果,

使用的过程中会发现还有好几个API,checkPermissioncheckCallingPermissioncheckCallingOrSelfPermission 等。

1
2
3
public int checkPermission(String permission, int pid, int uid) // 检查某个uid和pid是否有permission 权限
public int checkCallingPermission(String permission) // 检查调用者是否有 permission 权限,如果调用者是自己那么返回 PackageManager.PERMISSION_DENIED
public int checkCallingOrSelfPermission(String permission) // 检查自己或者其它调用者是否有 permission 权限

检查某个 pid 和 uid 的 package 是否拥有 uri 的读写权限,返回值表示是否被 granted 。

1
2
3
4
5
6
7
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags)
public int checkCallingUriPermission(Uri uri, int modeFlags)
public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags)
public int checkUriPermission(Uri uri, String readPermission,String writePermission, int pid, int uid, int modeFlags)

参考文章

​ 为了安全也要考虑用户体验,为了防止用户过多的打扰,API23还提出了permission_group权限组概念,即把权限分组,用户只要授权了某个组里的某一个权限,那么该组的其他权限就不需要再次授权了,

权限组 权限
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

注:

如果用户之前拒绝了这个权限,包括已经勾选了不再提示的,这种情况下,可能需要进行提示,告诉这个权限app用来做什么。那么就需要另外一个api:shouldShowRequestPermissionRationale,如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。如果用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了 Don’t ask again 选项,此方法将返回 false。如果设备规范禁止应用具有该权限,此方法也会返回 false

1
if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)) {}

打开直接进入指定App的管理页面,

1
2
3
4
5
6
public static void startAppSettings(Context context){
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse("package" + context.getPackageName()));
context.startActivity(intent);
}