转载地址:http://www.2cto.com/kf/201607/530239.html
-
1.前言
大家都知道Android 6.0的新特性之一就是应用权限的管理。也就是说凡是涉及用户隐私的权限,用户可以自己去设置管理了。然而在6.0以前,我们安装一款APP是默认同意此APP所需的所有权限(比如定位、访问通讯录),不同意就不能安装。当然,国内的一些手机厂商基于Android定制的系统中,可以实现在6.0以前关闭指定的权限。如下图:
2.危险权限列表(Dangerous Permission)
Dangerous Permission一般都是涉及用户隐私的权限。
从上面的图片中可以看到,摄像头、电话、定位等等都是我们平常开发中常用的权限。
3.可以在6.0不适配权限管理吗?
答案是可以,但是不推荐。
首先说怎么不适配,那就是设置targetSdkVersion小于23(Android 6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限,所以如果您APP设置的targetSdkVersion低于23,在运行时也不会崩溃。)
有人一看这不是挺好的嘛,解决问题。那么我想告诉你,首先这不是长久之计,早晚都要面对的。你不可能永远targetSdkVersion低于23。其次,它是有一个前提,那就是用户自己不去操作权限。要知道如果用户是6.0以上的手机,他可以自己在设置中关闭权限,那么到时APP因为没有权限获取数据异常,导致空指针的异常时,APP就会崩溃。
4.怎么适配
首先Android Studio:
在build.gradle中声明targetSdkVersion为23及以上。
Eclipse:
在AndroidManifest.xml中声明targetSdkVersion为23及以上。
这里引用高德定位Demo的CheckPermissionsActivity类,代码如下:
/** * 继承了Activity,实现Android6.0的运行时权限检测 * 需要进行运行时权限检测的Activity可以继承这个类 * * @创建时间:2016年5月27日 下午3:01:31 * @项目名称: AMapLocationDemo * @author hongming.wang * @文件名称:PermissionsChecker.java * @类型名称:PermissionsChecker * @since 2.5.0 */ public class CheckPermissionsActivity extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback { /** * 需要进行检测的权限数组 */ protected String[] needPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE }; private static final int PERMISSON_REQUESTCODE = 0; /** * 判断是否需要检测,防止不停的弹框 */ private boolean isNeedCheck = true; @Override protected void onResume() { super.onResume(); if(isNeedCheck){ checkPermissions(needPermissions); } } /** * * @param needRequestPermissonList * @since 2.5.0 * requestPermissions方法是请求某一权限, */ private void checkPermissions(String... permissions) { List needRequestPermissonList = findDeniedPermissions(permissions); if (null != needRequestPermissonList && needRequestPermissonList.size() > 0) { ActivityCompat.requestPermissions(this, needRequestPermissonList.toArray( new String[needRequestPermissonList.size()]), PERMISSON_REQUESTCODE); } } /** * 获取权限集中需要申请权限的列表 * * @param permissions * @return * @since 2.5.0 * checkSelfPermission方法是在用来判断是否app已经获取到某一个权限 * shouldShowRequestPermissionRationale方法用来判断是否 * 显示申请权限对话框,如果同意了或者不在询问则返回false */ private List findDeniedPermissions(String[] permissions) { List needRequestPermissonList = new ArrayList(); for (String perm : permissions) { if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) { needRequestPermissonList.add(perm); } else { if (ActivityCompat.shouldShowRequestPermissionRationale( this, perm)) { needRequestPermissonList.add(perm); } } } return needRequestPermissonList; } /** * 检测是否所有的权限都已经授权 * @param grantResults * @return * @since 2.5.0 * */ private boolean verifyPermissions(int[] grantResults) { for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } /** * 申请权限结果的回调方法 */ @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] paramArrayOfInt) { if (requestCode == PERMISSON_REQUESTCODE) { if (!verifyPermissions(paramArrayOfInt)) { showMissingPermissionDialog(); isNeedCheck = false; } } } /** * 显示提示信息 * * @since 2.5.0 * */ private void showMissingPermissionDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("提示"); builder.setMessage("当前应用缺少必要权限。请点击\"设置\"-\"权限\"-打开所需权限。"); // 拒绝, 退出应用 builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); builder.setPositiveButton("设置", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startAppSettings(); } }); builder.setCancelable(false); builder.show(); } /** * 启动应用的设置 * * @since 2.5.0 * */ private void startAppSettings() { Intent intent = new Intent( Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK){ this.finish(); return true; } return super.onKeyDown(keyCode, event); } }
我在上面的类中,自己加入了一些注释,大家仔细看就可以明白了。
当然不止上面一种实现方法,github上有许多大神开源的封装库,可以很方便的实现权限适配。我推荐两个库,大家根据需求选择: