一、前提须知:
Android现在将所有的权限归为了两类,一类是普通权限,一类是危险权限。对于普通权限,系统会自动帮我们进行授权,不需要手动操作。对于危险权限,必须要由用户手动进行点击授权才可以,否则程序无法完成相应的功能。
Android 6.0系统中加入了运行时权限功能,在使用过程中再对危险权限进行授权。罗列Android中所有的危险权限,一共是9组24个权限,如图:
二、第三方库EasyPermissions使用步骤:
EasyPermissions库是一个方便开发者为App高效处理危险权限的库,可用于在Android M或者更高版本上
第一步:依赖:implementation 'pub.devrel:easypermissions:2.0.1'
第二步:在清单文件里注册的权限:
a <!--外部存储的读取权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--外部存储的写入权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
b <uses-permission android:name="android.permission.CAMERA" />
c <!-- Android6.0 蓝牙扫描也需要 允许一个程序访问WiFi或移动基站的方式来获取粗略的位置-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--Android6.0 蓝牙扫描也需要 允许一个程序访问精良位置(如GPS)-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
等等权限(需要其他的再添加)。
第三步:检测权限的工具类及方法
public final class CheckPermissionUtils {
private CheckPermissionUtils() {
}
//需要申请的权限
private static String[] permissions = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.BLUETOOTH,
Manifest.permission.ACCESS_COARSE_LOCATION ,
Manifest.permission.ACCESS_FINE_LOCATION
};
//检测权限
public static String[] checkPermission(Context context){
List<String> data = new ArrayList<>();//存储未申请的权限
for (String permission : permissions) {
//Android自带的检测权限的方法:checkSelfPermission()
int checkSelfPermission = ContextCompat.checkSelfPermission(context, permission);
if(checkSelfPermission == PackageManager.PERMISSION_DENIED){//未申请
data.add(permission);
}
}
return data.toArray(new String[data.size()]);
}
}
第四步:检测权限:
//1.1检查权限
String[] permissions = CheckPermissionUtils.checkPermission(this);
第五步:申请权限
if (permissions.length == 0) {
//权限都申请了
//做接下来其他的事,比如是否登录
} else {
//1.2申请权限 第2个参数 : 一些系列的权限; 第3个参数:这次请求权限的唯一标示。
ActivityCompat.requestPermissions(this, permissions, 100);
Log.i("ningc", "1.2申请权限requestPermissions:" );
}
第六步:实现EasyPermissions.PermissionCallbacks接口,重写请求权限方法
//1.3.1 实现EasyPermissions.PermissionCallbacks接口,重写请求权限成功方法
/**
* 请求权限成功。
* 可以弹窗显示结果,也可执行具体需要的逻辑操作
* @param requestCode
* @param perms
*/
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
Toast.makeText(this, "执行onPermissionsGranted()...", Toast.LENGTH_SHORT).show();
Log.i("ningc", "1.3.1onPermissionsGranted" );
}
//1.3.1 实现EasyPermissions.PermissionCallbacks接口,重写请求权限失败方法
/**
* 请求权限失败
* @param requestCode
* @param perms
*/
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
Toast.makeText(this, "执行onPermissionsDenied()...", Toast.LENGTH_SHORT).show();
Log.i("ningc", "1.3.1onPermissionsDenied:请求权限失败" );
/**
* 1.5.1 若是在权限弹窗中,用户勾选了“不再询问(NEVER ASK AGAIN.)”或者“不在提示”,且拒绝权限。
* 这时候,需要跳转到设置界面去,让用户手动开启,没勾选则不会跳转到设置界面。
*/
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this)
.setTitle("权限申请")
.setRationale("当前App需要申请camera权限,需要打开设置页面么?")
.setPositiveButton("确认")
.setNegativeButton("取消")
.setRequestCode(REQUEST_CAMERA_PERM)
.build()
.show();
Log.i("ningc", "1.5.1 跳转到设置界面去,让用户手动开启" );
}
}
第七步:重写onRequestPermissionsResult,用于接受请求结果
//1.3.2 重写onRequestPermissionsResult,用于接受请求结果
/**
* 重写onRequestPermissionsResult,用于接受请求结果
* 在1.2请求后,弹出系统权限弹窗,剩下是用户是否授权操作。权限结果是回调在Activity
* 或者Fragment中的重写的onRequestPermissionsResult()方法中。
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//将请求结果传递EasyPermission库处理
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
Log.i("ningc", "1.3.2重写onRequestPermissionsResult,用于接受请求结果" );
}
第八步:(可选则实现或者不实现)@AfterPermissionGranted注解
//1.4 @AfterPermissionGranted注解
@AfterPermissionGranted(REQUEST_CAMERA_PERM)
public void cameraTask(int viewId) {
Log.i("ningc", "1.4cameraTask" );
if (EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA)) {
// Have permission, do the thing!
// performClick(viewId);
} else {
// Ask for one permission
EasyPermissions.requestPermissions(this, "需要请求camera权限",
REQUEST_CAMERA_PERM, Manifest.permission.CAMERA);
}
}
第九步:若是在权限弹窗中,用户勾选了“不再询问(NEVER ASK AGAIN.)”或者“不在提示”,且拒绝权限。 这时候,需要跳转到设置界面去,让用户手动开启,没勾选则不会跳转到设置界面。
/**
* 1.5.1 若是在权限弹窗中,用户勾选了“不再询问(NEVER ASK AGAIN.)”或者“不在提示”,且拒绝权限。
* 这时候,需要跳转到设置界面去,让用户手动开启,没勾选则不会跳转到设置界面。
*/
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this)
.setTitle("权限申请")
.setRationale("当前App需要申请camera权限,需要打开设置页面么?")
.setPositiveButton("确认")
.setNegativeButton("取消")
.setRequestCode(REQUEST_CAMERA_PERM)
.build()
.show();
Log.i("ningc", "1.5.1 跳转到设置界面去,让用户手动开启" );
}
第十步:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CAMERA_PERM) {
//1.5.2从设置页面处理权限后返回(可能勾选对应权限,也可没勾选上)
Toast.makeText(this, "从设置页面返回...", Toast.LENGTH_SHORT).show();
Log.i("ningc", "1.5.2requestCode:"+requestCode );
Log.i("ningc", "1.5.2从设置页面处理权限后返回" );
}
}
三、代码执行流程:(此处不再附加,日志打印可看)