前言
随着Android版本的升级,Android系统也越来越完善,在Android 6.0版本(SdkVersion 23),Android为我们带来了全新的权限申请机制,对于部分高危权限应用必须动态申请才能继续操作
下面,我就来详细介绍下Android 6.0动态权限的那些事。
简单的说明
在Android 6.0之前:对于应用权限管理是在应用安装的时候以列表的形式展示给用户,用户选择安装则表示同意了这些权限,如果不同意就只能选择取消安装(部分国产ROM可以在这个阶段选择给与或者拒绝)。
这样就带来一个安全问题,如果用户没有详细看权限列表直接安装了,这样恶意应用就可能获取到很多危险权限。比如读取通讯录等。
Android 6.0及以后:如果你的应用targetSdkVersion < 23,那么权限管理机制与Android 6.0之前的操作一样,这样的目的是为了防止旧app在Android 6.0上面因为权限机制的变化崩溃。如果你的应用targetSdkVersion >= 23,那么你就必须动态申请高危权限,否则app会直接崩溃。
那么是不是只要在开发的时候将targetSdkVersion设置的比23小那么就一切ok呢?
如果暂时还不想适配6.0运行时权限,但是又想要app可以在6.0及以上机型运行,那我们可以将目标版本改为23以下,如:targetSdkVersion 22。但是由于6.0机型在设置中可以进行权限管理,用户可以取消该应用的某个权限,但是app并不知道该权限被取消,此时app会崩溃(合理的try可以避免)。
权限的分类
Android 6.0将权限分为一般权限和危险权限两种,一般权限跟以前一样在AndroidManifest直接声明即可,危险权限需要开发者不仅需要声明而且在代码中还要动态申请权限。
Normal Permissions
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
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
Dangerous Permissions
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
group:android.permission-group.PHONE
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
group:android.permission-group.CAMERA
permission:android.permission.CAMERA
group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS
group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO
group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS
看到上面的dangerous permissions,我们可以发现,危险权限都是一组一组的,如果app运行在Android 6.x的机器上,如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。
不过需要注意的是,不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化。
相关API
检查是否拥有某权限:ActivityCompat.checkSelfPermission(@NonNull Context context, @NonNull String permission)
申请权限:ActivityCompat.requestPermissions(final @NonNull Activity activity,final @NonNull String[] permissions, final int requestCode)
申请权限结果回调:覆写Activity中的onRequestPermissionsResult方法。
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
}
检查用户拒绝权限的时候是否点击了不在提醒:ActivityCompat.shouldShowRequestPermissionRationale(@NonNull Activity activity,@NonNull String permission)
最佳实战
doBackUp()是一个备份联系人的方法,由于读取联系人是高危权限,所以必须先验证是否拥有权限,如果没有权限则申请权限以后继续操作,当用户拒绝权限以后通过ActivityCompat.shouldShowRequestPermissionRationale方法验证是否选择了不再提示然互进行相应操作。
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == 10) {
//用户授予了权限
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mContactOperate.doBackup(ContactsUtil.queryAllContacts(getContentResolver()));
} else {
//权限被用户拒绝了,但是并没有选择不再提示,也就是说还可以继续申请
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) {
//提示用户必须给与权限才能继续操作
Snackbar snackbar = Snackbar.make(mDrawerLayout, "需要授予权限才能继续操作", Snackbar.LENGTH_LONG);
snackbar.setAction("重试", new View.OnClickListener() {
@Override
public void onClick(View v) {
//继续申请权限
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 10);
}
});
snackbar.show();
} else {
//用户拒绝并选择了不在提示,这里可以提示用户然后打开权限设置界面
ToastUtil.show(this, R.string.no_permission_read_contacts);
}
}
}
}
安卓都已经出到 8 了。。。你还在讨论 6
@Leridy_Lei 你要知道目前8.0的市场占有率不到百分之一