您的位置:首页 > 移动开发 > Android开发

Android6.0权限管理

2016-12-03 11:36 87 查看


运行时权限(Runtime permission)

android的权限系统一直是首要的安全概念,因为这些权限只在安装的时候被询问一次。一旦安装了,app可以在用户毫不知晓的情况下访问权限内的所有东西。

这是极其危险的事情

所以,在Android M 权限请求设计改版了,有点类似iOS的权限请求



1461651981945.jpg

在android6.0棉花糖,app将不会在安装的时候授予权限。取而代之的是,app不得不在运行时一个一个询问用户授予权限。

注意权限询问对话框不会自己弹出来。开发者不得不自己调用。如果开发者要调用的一些函数需要某权限而用户又拒绝授权的话,函数将抛出异常甚至导致程序崩溃.


旧版兼容

为了与旧版本兼容,比如你的
build.gradle 中的
targetSdkVersion 设置为
23 之前,比如22.

也能在Android6.0 的手机上面跑,并且权限请求机制使用6.0之前的
安装时请求 的模式.

吐槽一下: Excuse Me? 这到底是兼容还是漏洞... targetSdkVersion 设置为23以前,不让跑6.0不是更合理?

可能处于市场应用的API版本考虑,不兼容估计大部分应用都不能跑6.0
所以,如果你觉得运行时弹出权限框让用户勾选很不友好,那么就取巧使用targetSdkVersion <23 吧,但这绝对不是长久之计...(丑陋...)

android { 

compileSdkVersion 23 

buildToolsVersion "23.0.2" 

 

defaultConfig { 

minSdkVersion 8 

targetSdkVersion22 

versionCode 1 

versionName "1.0" 



buildTypes { 

release { 

minifyEnabled false 

proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro' 









1461662965441.jpg


6.0权限弹框的两种模式

1.初次请求,弹出对话框叫你勾选



1461654947945.jpg

2,第二次请求之后,弹出对话框,出现不再提醒字样



1461655014689.jpg

当用户点击了不再提醒,你再次请求权限的时候,就不会弹出对话框,所以这时,你需要根据需求另做处理

下面会如何处理


6.0之后的权限分类

分为两类
Normal permissions 和
Dangerous permissions


Normal permissions(普通权限)

只需要在xml中申请就可以了,与6.0之前没什么区别

包括的权限有

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS 

android.permission.ACCESS_NETWORK_STATE 

android.permission.ACCESS_NOTIFICATION_POLICY 

android.permission.ACCESS_WIFI_STATE 

android.permission.ACCESS_WIMAX_STATE 

android.permission.BLUETOOTH 

android.permission.BLUETOOTH_ADMIN 

android.permission.BROADCAST_STICKY 

android.permission.CHANGE_NETWORK_STATE 

android.permission.CHANGE_WIFI_MULTICAST_STATE 

android.permission.CHANGE_WIFI_STATE 

android.permission.CHANGE_WIMAX_STATE 

android.permission.DISABLE_KEYGUARD 

android.permission.EXPAND_STATUS_BAR 

android.permission.FLASHLIGHT 

android.permission.GET_ACCOUNTS 

android.permission.GET_PACKAGE_SIZE 

android.permission.INTERNET 

android.permission.KILL_BACKGROUND_PROCESSES 

android.permission.MODIFY_AUDIO_SETTINGS 

android.permission.NFC 

android.permission.READ_SYNC_SETTINGS 

android.permission.READ_SYNC_STATS 

android.permission.RECEIVE_BOOT_COMPLETED 

android.permission.REORDER_TASKS 

android.permission.REQUEST_INSTALL_PACKAGES 

android.permission.SET_TIME_ZONE 

android.permission.SET_WALLPAPER 

android.permission.SET_WALLPAPER_HINTS 

android.permission.SUBSCRIBED_FEEDS_READ 

android.permission.TRANSMIT_IR 

android.permission.USE_FINGERPRINT 

android.permission.VIBRATE 

android.permission.WAKE_LOCK 

android.permission.WRITE_SYNC_SETTINGS 

com.android.alarm.permission.SET_ALARM 

com.android.launcher.permission.INSTALL_SHORTCUT 

com.android.launcher.permission.UNINSTALL_SHORTCUT 

其实不需要记,记住哪些是危险权限就是了


Dangerous permissions(危险权限)

危险权限,需要在运行时请求.
注意: 危险权限是按组来分的,所以,当你申请了多个同组的危险权限时,运行时只需要申请一个就行

例如:

<!-- 电话 --> 

<uses-permissionandroid:name="android.permission.READ_CALL_LOG"
/> 

<uses-permissionandroid:name="android.permission.READ_PHONE_STATE"
/> 

<uses-permissionandroid:name="android.permission.CALL_PHONE"
/> 

<uses-permissionandroid:name="android.permission.WRITE_CALL_LOG"
/> 

<uses-permissionandroid:name="android.permission.USE_SIP"
/> 

<uses-permissionandroid:name="android.permission.PROCESS_OUTGOING_CALLS"
/> 

<uses-permissionandroid:name="com.android.voicemail.permission.ADD_VOICEMAIL"
/> 

你申请了关于电话的那么多权限,在动态申请的时候,它只会弹出



1461654947945.jpg

这一个权限框
所以,这是一个权限组的概念,运行时选择你申请的同组权限的一个就行

目前所有的危险权限组集合

<!-- Dangerous Permissions. --> 

<!-- 联系人 --> 

<uses-permissionandroid:name="android.permission.WRITE_CONTACTS"
/> 

<uses-permissionandroid:name="android.permission.GET_ACCOUNTS"
/> 

<uses-permissionandroid:name="android.permission.READ_CONTACTS"
/> 

 

<!-- 录音 --> 

<uses-permissionandroid:name="android.permission.RECORD_AUDIO"
/> 

 

<!-- 电话 --> 

<uses-permissionandroid:name="android.permission.READ_CALL_LOG"
/> 

<uses-permissionandroid:name="android.permission.READ_PHONE_STATE"
/> 

<uses-permissionandroid:name="android.permission.CALL_PHONE"
/> 

<uses-permissionandroid:name="android.permission.WRITE_CALL_LOG"
/> 

<uses-permissionandroid:name="android.permission.USE_SIP"
/> 

<uses-permissionandroid:name="android.permission.PROCESS_OUTGOING_CALLS"
/> 

<uses-permissionandroid:name="com.android.voicemail.permission.ADD_VOICEMAIL"
/> 

 

<!-- 日历 --> 

<uses-permissionandroid:name="android.permission.READ_CALENDAR"
/> 

<uses-permissionandroid:name="android.permission.WRITE_CALENDAR"
/> 

 

<!-- 相机 --> 

<uses-permissionandroid:name="android.permission.CAMERA"
/> 

 

<!-- 传感器 --> 

<uses-permissionandroid:name="android.permission.BODY_SENSORS"
/> 

 

<!-- 定位 --> 

<uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"
/> 

<uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION"
/> 

 

<!-- 存储 --> 

<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"
/> 

<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"
/> 

 

<!-- 短信 --> 

<uses-permissionandroid:name="android.permission.READ_SMS"
/> 

<uses-permissionandroid:name="android.permission.RECEIVE_WAP_PUSH"
/> 

<uses-permissionandroid:name="android.permission.RECEIVE_MMS"
/> 

<uses-permissionandroid:name="android.permission.RECEIVE_SMS"
/> 

<uses-permissionandroid:name="android.permission.SEND_SMS"
/> 

对应的java code

// 联系人 

Manifest.permission.WRITE_CONTACTS, 

Manifest.permission.GET_ACCOUNTS, 

Manifest.permission.READ_CONTACTS, 

 

// 电话 

Manifest.permission.READ_CALL_LOG, 

Manifest.permission.READ_PHONE_STATE, 

Manifest.permission.CALL_PHONE, 

Manifest.permission.WRITE_CALL_LOG, 

Manifest.permission.USE_SIP, 

Manifest.permission.PROCESS_OUTGOING_CALLS, 

Manifest.permission.ADD_VOICEMAIL, 

 

// 日历 

Manifest.permission.READ_CALENDAR, 

Manifest.permission.WRITE_CALENDAR, 

 

// 相机 

Manifest.permission.CAMERA, 

 

// 传感器 

Manifest.permission.BODY_SENSORS, 

 

// 定位 

Manifest.permission.ACCESS_FINE_LOCATION, 

Manifest.permission.ACCESS_COARSE_LOCATION, 

 

// 存储 

Manifest.permission.READ_EXTERNAL_STORAGE, 

Manifest.permission.WRITE_EXTERNAL_STORAGE, 

 

// 录音 

Manifest.permission.RECORD_AUDIO, 

 

// 短信 

Manifest.permission.READ_SMS, 

Manifest.permission.RECEIVE_WAP_PUSH, 

Manifest.permission.RECEIVE_MMS, 

Manifest.permission.RECEIVE_SMS, 

Manifest.permission.SEND_SMS, 


运行时权限请求的基本步骤

1.在xml中注册

2. 运行时请求权限


以下是权限检查的帮助类

/** 

* 检查权限是否已请求到 (6.0) 

*/ 

publicvoid
checkPermissions(String... permissions){ 

// 版本兼容 

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 

// 判断缺失哪些必要权限 

&& lacksPermissions(permissions)) { 

// 如果缺失,则申请 

requestPermissions(permissions); 





 

/** 

* 判断是否缺失权限集合中的权限 

*/ 

privateboolean
lacksPermissions(String... permissions){ 

for (String permission : permissions) { 

if (lacksPermission(permission)) { 

return
true; 





return
false; 



 

/** 

* 判断是否缺少某个权限 

*/ 

privateboolean
lacksPermission(String permission){ 

return ContextCompat.checkSelfPermission(context, permission) == 

PackageManager.PERMISSION_DENIED; 



 

/** 

* 请求权限 

*/ 

privatevoid
requestPermissions(String... permissions){ 

ActivityCompat.requestPermissions(context, permissions, PERMISSION_REQUEST_CODE); 



 

/** 

* 启动应用的设置,进入手动配置权限页面 

*/ 

privatevoid
startAppSettings()


Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 

Uri uri = Uri.fromParts("package", context.getPackageName(),null); 

intent.setData(uri); 

context.startActivity(intent); 



注意: 其中的requestPermissions
方法,它会弹出权限提示框( 没有点击不再提醒的话 ),然后调用public void onRequestPermissionsResult(int
requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 方法,该方法在Activity或者Fragment中回调

3.在onRequestPermissionsResult回调中处理


public void onRequestPermissionsResult() 方法中,你可以捕获到用于是点击了
不再提醒 还是
拒绝 ,然后做出不同的操作..

@Override 

publicvoid
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNullint[]
grantResults){ 

// 版本兼容 

if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M || 

requestCode != PermissionsChecker.PERMISSION_REQUEST_CODE) 

return; 

 

for (int i =0, len = permissions.length; i < len; i++) { 

String permission = permissions[i]; 

// 缺失的权限 

if (grantResults[i] == PackageManager.PERMISSION_DENIED) { 

boolean showRationale = shouldShowRequestPermissionRationale(permission); 

if (!showRationale) { 

// 用户点击不再提醒 

// TODO 

break; 

} else {  

// 用户点击了取消... 

// possibly check more permissions... 










权限请求策略

下面提供一种我认为还不错的策略

在需要某权限的Activity的
onStrart() 中去请求权限


onRequestPermissionsResult 回调中,如果用户点击了拒绝,则继续请求权限

如果用户点击了不再提醒,则弹出自定义对话框,引导用户手动去开启权限,如果用户不授权,则退出当前页面
注意:适用于没有权限就无法使用该功能的情况



1461661615410.jpg

Activity代码

public
class
BaseActivity extendsAppCompatActivity


private
static final String TAG ="BaseActivity"; 

private PermissionsChecker checker; 

 

@Override 

protectedvoid
onCreate(@Nullable Bundle savedInstanceState){ 

super.onCreate(savedInstanceState); 

checker = new PermissionsChecker(this); 



 

public PermissionsCheckergetChecker(){ 

return checker; 



 

/** 

* 在该声明周期,检查权限申请情况 

*/ 

@Override 

protectedvoid
onStart()


super.onStart(); 

checker.checkPermissions(PermissionsChecker.PERMISSIONS); 



 

/** 

* 请求权限检查完后回调的结果 



* @param requestCode . 

* @param permissions 所请求的权限 

* @param grantResults . 

*/ 

@TargetApi(Build.VERSION_CODES.M) 

@Override 

publicvoid
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNullint[]
grantResults){ 

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || 

requestCode != PermissionsChecker.PERMISSION_REQUEST_CODE) 

return; 

 

 

for (int i =0, len = permissions.length; i < len; i++) { 

String permission = permissions[i]; 

if (grantResults[i] == PackageManager.PERMISSION_DENIED) { 

boolean showRationale = shouldShowRequestPermissionRationale(permission); 

if (!showRationale) { 

// 用户点击不再提醒,弹出权限框,引导其手动开启权限 

checker.showMissingPermissionDialog(); 

break; 

} else { 

// 用户点击取消,继续提示 

checker.checkPermissions(PermissionsChecker.PERMISSIONS); 

break; 











 

Fragment中运行时权限的特殊处理

在Fragment中申请权限,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的onRequestPermissionsResult

如果在Fragment中嵌套Fragment,在子Fragment中使用requestPermissions方法,onRequestPermissionsResult不会回调回来,建议使用getParentFragment().requestPermissions方法,

这个方法会回调到父Fragment中的onRequestPermissionsResult,加入以下代码可以把回调透传到子Fragment

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
List<Fragment> fragments = getChildFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment != null) {
fragment.onRequestPermissionsResult(requestCode,permissions,grantResults);
}
}
}
}

相关开源项目

PermissionsDispatcher

使用标注的方式,动态生成类处理运行时权限,目前还不支持嵌套Fragment。

:https://github.com/hotchemi/PermissionsDispatcher

RxPermissions

基于RxJava的运行时权限检测框架

:https://github.com/tbruyelle/RxPermissions

Grant

简化运行时权限的处理,比较灵活
https://github.com/anthonycr/Grant
android-RuntimePermissions

Google官方的例子
https://github.com/googlesamples/android-RuntimePermissions

附录

以下权限只需要在AndroidManifest.xml中声明即可使用

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

转载自:http://www.cnblogs.com/onespieces/p/5435852.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android6.0权限