众所周知,在Android 6.0之后,Android对一些用户的敏感权限进行了进一步加强,需要用户去动态授予权限。
在API23之前,只要在AndroidManifest.xml中注册过的权限,程序运行时都会自动获取到。但是到了23及更高,危险的权限就需要我们自己来动态的申请了,而此时用户也就有了拒绝我们需要的权限的权力,这当然会导致我们程序的运行不正常,甚至是造成程序的崩溃。所以我们就需要尽可能的提示用户同意我们的权限申请。
系统权限分为几个保护级别。需要了解的两个最重要保护级别是正常权限和危险权限。 首先,你必须得知道哪些是需要动态申请的权限,也就是我前面所提到的危险权限,并且危险权限也分组,所以到底哪些是危险权限呢?
这里我们涉及到9大组危险权限,但是可喜可贺的是我们只需要申请每组中的一个权限,就能获取到全组权限的授权。
1、关于日历的权限:
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
2、关于相机的权限:
<uses-permission android:name="android.permission.CAMERA"/>
3、关于联系人的权限:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.GET_CONTACTS"/>
4、关于位置的权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
5、关于电话的权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<uses-permission android:name="android.permission.USE_SIP"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
6、关于传感器的权限:
<uses-permission android:name="android.permission.BODY_SENSORS"/>
7、关于短信的权限:
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
<uses-permission android:name="android.permission.READ_CELL_BROADCASTS"/>
8、关于SD卡的权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
9、关于录音的权限
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
这里我们通过一个打电话的案例进行说明
第一步:在清单文件中申明打电话权限:
<uses-permission android:name="android.permission.CALL_PHONE"/>
第二步:
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + mPhoneNumber);
intent.setData(data);
startActivity(intent);
之前这两步就可以实现一个打电话的功能,但是现在不行了,现在回程序运行会崩溃,因为你没有动态申请用户打电话权限。
现在我们需要去检测该权限有没有背用户授予过,如果没有则需要申请打电话权限,如果有授予过可以直接拨打电话。
ContextCompat.checkSelfPermission:检测权限
ActivityCompat.requestPermissions:申请权限
第一步:检测用户用没有授权打电话,如果没有就需要申请权限
findViewById(R.id.btn_call).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission
.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
// 没有该权限 申请打电话权限
// Context ,
// 第二个参数是用户需要申请的权限字符串数组,
// 第三个参数是请求码 主要用来处理用户选择的返回结果
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, CALL_PHONE_REQUEST_CODE);
} else {
callPhone();
}
}
});
是的,就是这么简单。不过,如果你就这样子用在了你的项目里,会有坑!!!
如果你本身就是Android用户,细心的你一定会发现,App在向你申请权限的时候,你会有几个选项:
1.允许
2.拒绝
3.还可以拒绝并不再提示!(坑就出现在这里了)
如果按上面的代码,你会永远得到一个答案:用户拒绝!!(如果用户是不小心点错,或者出于好奇心尝试,那很容易就懵逼了)
所以我们还需要对第一步做个调整
findViewById(R.id.btn_call).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission
.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
// 没有该权限 申请打电话权限
// Context ,
// 第二个参数是用户需要申请的权限字符串数组,
// 第三个参数是请求码 主要用来处理用户选择的返回结果
// 1、此时还没有权限!
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.CALL_PHONE)) {
// 2、用户还没选择或选择了但没选择拒绝并不再提示
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, CALL_PHONE_REQUEST_CODE);
} else {
// 3、用户点选了不再提示
//(正经的告诉用户这个功能必须给权限啊,求权限啊!最好告诉他怎么去设置!)
showTipsDialog(MainActivity.this);
}
} else {
// 有权限了,去做该做的事情吧!
callPhone();
}
}
});
优化部分:还可以拒绝并不再提示!,我们添加了一个可以让用户设置的跳转
/**
* 显示提示对话框(这个提示款适用于点击按钮请求权限的问题)
* 如果需要强制获取权限,需要自定义对话框
*/
public static void showTipsDialog(final Context context) {
new AlertDialog.Builder(context)
.setTitle("提示信息")
.setMessage("当前应用缺少必要权限,该功能暂时无法使用。如若需要,请单击【确定】按钮前往设置中心进行权限授权。")
.setNegativeButton("取消", null)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startAppSettings(context);
}
}).show();
}
/**
* 启动当前应用设置页面
*/
private static void startAppSettings(Context context) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
}
第二步: 处理回调 如果用户同意或是拒绝那么会回调onRequestPermissionsResult()
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if(requestCode == CALL_PHONE_REQUEST_CODE){
if (grantResults !=null&&grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted 通过 打电话
callPhone();
} else {
// Permission Denied 被拒绝
Toast.makeText(this,"权限被拒绝了",Toast.LENGTH_SHORT).show();
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
至此,这个功能算是可用了!!!但是,还不完美!!!必须稍微封装一下让自己用起来更方便嘛!那么接下来就带大家来一个更加完美的封装。
源码下载