如需查看具体项目例子,可以去各大应用市场下载“萌萌鸡”app。体验功能!
android 6.0之前,我们的App需要权限,只需在manifest中申明即可,用户安装后,完全不用管权限什事情。但是android 6.0出现以后,把权限管理做了加强处理,隐私更加强,在manifest申明了,在使用到相关功能时,还需重新授权方可使用,但也不是所有的权限都需要判断,因为分了普通权限和危险权限。相信大家对权限的分类有过一点了解,这里就不详细解析了
两个建议:
1.严肃对待新权限事件,因为很多细节需要处理
2.如果你代码没支持新权限,不要设置targetSdkVersion 23 ,因为可以节省大把时间。这篇文章就不需要看了
我之前就是设置targetSdkVersion 19 面对6.0的系统,毫无压力, 后来新的SDK 出现了很多新的功能,而且网络请求也是从httpclient换成了okHttp, 必须targetSdkVersion 要大于23 ,以及为了与时俱进,换成了23,那么就要严肃对待这个问题了。
我们直接来写代码:创建一个基类,BaseActivity 需要继承 AppCompatActivity 而不能继承Activity, AppCompatActivity是在appcompat-v7中,如果app里面没有appcompat-v7 ,可以在 项目build.gradle文件中添加引用
compile 'com.android.support:appcompat-v7:23.1.1'
版本当然越高越好
Activity相信大家都会封装一个baseActivity ,在里面添加以下判断权限的方法
/**
* 判断是否是6.0以上的系统.很多的权限都不能自动或者提示开启. 功能可能需要多个权限,需要遍历判断
*
* 萌萌鸡APP需要权限判断的地方(首页图灵聊天,个人中心AR扫描,修改头像, 设置祝福语音,视频,设置手机号码通讯录,AR,)
*
* @param dataPermission 需要的权限 ,数组
* @return
*/
public void selfPermissionGranted(Context context, PermissionCallback runnable, String[] dataPermission) {
MyLog.i(TAG, "selfPermissionGranted");
this.permissionRunnable = runnable;
int targetSdkVersion = 0;
try {
final PackageInfo info = context.getPackageManager().getPackageInfo(getPackageName(), 0);
targetSdkVersion = info.applicationInfo.targetSdkVersion;//获取应用的Target版本
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
boolean resultAll = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//Build.VERSION.SDK_INT是获取当前手机版本 Build.VERSION_CODES.M为6.0系统
MyLog.i(TAG, "Build.VERSION.SDK_INT=" + Build.VERSION.SDK_INT);
MyLog.i(TAG, "targetSdkVersion=" + targetSdkVersion);
MyLog.i(TAG, "Build.VERSION_CODES.M=" + Build.VERSION_CODES.M);
//如果系统>=6.0
if (targetSdkVersion >= Build.VERSION_CODES.M && checkPermissionGranted(context,dataPermission)) {//如果有权限
if (permissionRunnable != null) {
permissionRunnable.hasPermission();
permissionRunnable = null;
}
} else {
MyLog.i(TAG, "!checkPermissionGranted");
//如果没有权限,请求
//判断用户是否已经拒绝过,直接去请求权限,而不管用户是否勾选了"不再询问",我们需要用户开启权限,没有权限就没有办法玩了
// if (context.shouldShowRequestPermissionRationale(dataPermission[i])) {
// context.requestPermissions(dataPermission, Constans.REQUEST_PERMISSION);//
// MyLog.i(TAG, i + "+shouldShowRequestPermissionRationale=true" );//(1)只有"不在询问"才会到这一步
// } else {
// MyLog.i(TAG, i + "+shouldShowRequestPermissionRationale=false" );//(1)第一次原生进入 false (2)拒绝后,再次进入,还是提示false
// isPermissionType(context, dataPermission[i]);
// }
requestPermissions(dataPermission, Constans.REQUEST_PERMISSION);
}
} else {
MyLog.i(TAG, "Build.VERSION.SDK_INT<6.0");
if (permissionRunnable != null) {
permissionRunnable.hasPermission();
permissionRunnable = null;
}
}
}
/**
*创建一个回调,方便判断权限的处理
*/
private PermissionCallback permissionRunnable;
public interface PermissionCallback {
void hasPermission();
void noPermission();
}
/**
* 检测是否开启了权限 只要有一个权限没有打开,就返回false
*
* @param permissions
* @return
*/
@TargetApi(Build.VERSION_CODES.M)//这里需要用23
public boolean checkPermissionGranted(Context context, String[] permissions) {
MyLog.i(TAG, "checkPermissionGranted");
boolean flag = true;
for (String p : permissions) {
MyLog.i(TAG, "permissions=" + p.toString());
if (context.checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED) {
flag = false;
break;
}
}
return flag;
}
/**
* 是否已经验证了权限
*
* @param grantResults
* @return
*/
public boolean verifyPermissions(int[] grantResults) {
// At least one result must be checked.
if (grantResults.length < 1) {
return false;
}
// Verify that each required permission has been granted, otherwise return false.
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 检测权限的回调,是否开启了权限
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == Constans.REQUEST_PERMISSION) {
for (int i = 0; i < permissions.length; i++) {//可能需要多个权限,需要遍历判断
MyLog.i(TAG, "Permission=i=" + permissions[i] + "grantResults=" + grantResults.length);
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {//如果点击开启权限
if (verifyPermissions(grantResults))
if (permissionRunnable != null) {
permissionRunnable.hasPermission();
permissionRunnable = null;
}
} else {
MyLog.i(TAG, "Permission=" + permissions[i]);
isPermissionType(this, permissions[i]);//我在回调的地方,弹出自定义对话框,引导用户去开启权限
break;
}
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
/**
* 权限的提示,不同权限的提示不同
*
* @param context
* @param permission
*/
public void isPermissionType(Activity context, String permission) {
switch (permission) {
case "android.permission.CAMERA"://相机权限
showPermissionDialogs(context, context.getResources().getString(R.string.hint_camera_only), false);
break;
case "android.permission.WRITE_EXTERNAL_STORAGE"://写入sd卡权限
Tools.showPermissionDialogs(context, context.getResources().getString(R.string.hint_sd_write), false);
break;
case "android.permission.RECORD_AUDIO"://录音权限
Tools.showPermissionDialogs(context, context.getResources().getString(R.string.hint_record), false);
break;
case "android.permission.READ_CONTACTS"://通讯录权限
Tools.showPermissionDialogs(context, context.getResources().getString(R.string.hint_contacts_only), false);
break;
default:
break;
}
}
/**
* 开启应用权限打开提示对话框
*
* @param permissionHint 权限的提示文字
* @param isFinishActivity 点击"确定""取消"的时候,是否finish当前页面
*/
public void showPermissionDialogs(final Activity context, String permissionHint, final boolean isFinishActivity) {
final Dialog dialog = new Dialog(context, R.style.dialog);
if (!dialog.isShowing()) {
dialog.show();
}
MyLog.i(TAG, "show_dialog");
dialog.setCanceledOnTouchOutside(false);// 设置点击屏幕Dialog不消失
View localView = LayoutInflater.from(context).inflate(
R.layout.dialog_hint_camera, null);
dialog.setContentView(localView);
TextView tvPermissionHint = (TextView) localView.findViewById(R.id.tvPermissionHint);
TextView tvPermissionSure = (TextView) localView.findViewById(R.id.tvPermissionSure);
TextView tvPermissionCancel = (TextView) localView.findViewById(R.id.tvPermissionCancel);
tvPermissionHint.setText(permissionHint);
tvPermissionSure.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (dialog.isShowing()) {
dialog.cancel();
}
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
context.getPackageName(), null);
intent.setData(uri);
context.startActivity(intent);
if (isFinishActivity) context.finish();
}
});
tvPermissionCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (dialog.isShowing()) {dialog.cancel();
}
if (isFinishActivity) context.finish();
}
});
}
Activity中,就在你需要权限判断的地方加下面一段代码
selfPermissionGranted(this,new BaseActivity.PermissionCallback() {
@Override
public void hasPermission() {
openTuling();//已经开启了权限,进入处理
}
@Override
public void noPermission() {
//没有权限的处理
}
},"android.permission.RECORD_AUDIO","android.permission.CALL_PHONE");//填写需要请求的权限,可能是多个
如果在Fragment中使用,直接在自己的BaseFragment写个方法调用此Activity的方法即可。
/**
* Android M运行时权限请求封装
* @param runnable 请求权限回调
* @param permissions 请求的权限(数组类型),直接从Manifest中读取相应的值,比如Manifest.permission.WRITE_CONTACTS
*/
public void selfPermissionGranted(Context context,BaseActivity.PermissionCallback runnable, String... permissions){
MyLog.i(TAG,"selfPermissionGranted");
if(context!=null && context instanceof BaseActivity){
MyLog.i(TAG,"getActivity()!=null");
((BaseActivity) getActivity()).selfPermissionGranted(context,runnable,permissions);
}
}
最后,你在编写代码的时候,可能会遇到以下问题
(1).你之前用到了appcompat-v4,appcompat-v13而不是appcompat-v7 这里需要换到appcompat-v7,appcompat-v7中自定义属性命名不能是常用关键字(heght.width,color..)
(2)如果你baseActivity的父类是Activity换成了AppcompatActivity,那么主题同样需要换成的AppCompat主题
(3)如果你在fragment中调用,记得fragment要的父类不能用FragmentActivity而是用BaseActivity,因为AppCompatActivity extends FragmentActivity
最后我把代码封装了一个新的库:compile 'com.apeng:EsayPermissions:1.0.0'
非常方便,欢迎体验 项目地址