在Android6.0之前只需在AndroidManifest.xml文件写明权限即可。但是在Android6.0之后也就是SDK>=23的时候,一些隐私权限需要动态申请,而且在用户同意授权之后App才能拥有该权限。虽然不难,但写下来代码工作量也不少,而且几乎每个应用都需要用到。所以一个简单简洁优雅的处理方式是非常重要的。
思路:
如果在每个用到权限的地方去申请,有点繁琐,所以做法是直接在每个Activity界面显示前就把该界面所需的权限全部申请允许了,再进入正常的流程。如果有权限未被允许,开发者可以在接口中自己处理,可以直接提示并退出,或者提示权限的作用后重新发起权限申请。
使用系统提供的API:
动态权限的核心工作流程:checkSelfPermission检查是否已被授予——>requestPermissions申请权限——>自动回调onRequestPermissionsResult——shouldShowRequestPermissionRationale。无论什么框架变出花来都离不开这个基本的流程。
ContextCompat.checkSelfPermission(): 检查权限是否已经授权
ActivityCompat.requestPermissions():动态申请权限,并弹出对话框。
onRequestPermissionsResult():在activity里面重写该方法该方法是权限申请之后的回调方法。shouldShowRequestPermissionRationale() :当应用首次申请权限时,如果用户点击拒绝,下次再申请权限,Android允许你提示用户,你为什么需要这个权限,更好引导用户是否授权,其中在Android原生系统中:如果应用之前请求过此权限但用户拒绝了请求,此方法将返回true;如果用户在过去拒绝了权限请求且在权限请求系统对话框中选择了 Don't ask again 选项将返回 false;如果第一次申请权限也返回false;如果设备规范禁止应用具有该权限,此方法也会返回 false,返回false则不在显示提示对话框,返回true则会显示对话框。
下面先看下申请动态权限时的运行效果图:
1.初次进入界面时,申请所需的全部权限:
2.点击打电话按钮申请单个权限时:
3.拒绝授予权限,且勾选了不再提示:
4.拒绝权限并不再提示,告知用户该权限的作用:
5.提示用户开启权限:
点击“立即开启”跳到权限设置页面:
使用方式:
先从Activity的使用开始。
/**
* Created by YuShuangPing on 2018/11/1.
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener, PermissionInterface {
private int requestCode = 10000;
private Button btn_phone;//打电话
private Button btn_camera;//打开相机
private PermissionHelper mPermissionHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_phone = findViewById(R.id.btn_phone);
btn_camera = findViewById(R.id.btn_camera);
btn_phone.setOnClickListener(this);
btn_camera.setOnClickListener(this);
//初始化
mPermissionHelper = new PermissionHelper(this, this);
//发起权限申请
mPermissionHelper.requestPermissions(new String[]{Manifest.permission.CALL_PHONE,
Manifest.permission.CAMERA});
}
//点击监听
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_phone://打电话
requestCode = 0;
mPermissionHelper.requestPermissions(new String[]{Manifest.permission.CALL_PHONE});
break;
case R.id.btn_camera://打开相机
requestCode = 1;
mPermissionHelper.requestPermissions(new String[]{Manifest.permission.CAMERA});
break;
}
}
/**
* 可设置请求权限请求码
*/
@Override
public int getPermissionsRequestCode() {
//设置权限请求requestCode,只有不跟onRequestPermissionsResult方法中的其他请求码冲突即可。
return requestCode;
}
/**
* 请求权限成功回调
*/
@Override
public void requestPermissionsSuccess() {
//权限请求用户已经全部允许
if (requestCode == 10000) {
} else if (requestCode == 0) {
Intent intent = new Intent(Intent.ACTION_DIAL);
Uri data = Uri.parse("tel:" + 10086);
intent.setData(data);
startActivity(intent);
} else if (requestCode == 1) {
Intent intent1 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent1, 0);
}
}
/**
* 请求权限失败回调
*/
@TargetApi(Build.VERSION_CODES.M)
@Override
public void requestPermissionsFail() {
//权限请求不被用户允许。可以提示并退出或者提示权限的用途并重新发起权限申请。
if (requestCode==10000){
}else if (requestCode == 0) {
//如果拒绝授予权限,且勾选了再也不提醒
if (!shouldShowRequestPermissionRationale(Manifest.permission.CALL_PHONE)) {
DialogUtil.showSelectDialog(this, "说明", "需要使用电话权限,进行电话测试", "取消", "确定", new DialogUtil.DialogClickListener() {
@Override
public void confirm() {
//用于在用户勾选“不再提示”并且拒绝时,再次提示用户
DialogUtil.showSelectDialog(MainActivity.this, "电话权限不可用", "请在-应用设置-权限中,允许APP使用电话权限来测试", "取消", "立即开启", new DialogUtil.DialogClickListener() {
@Override
public void confirm() {
goToAppSetting();
}
@Override
public void cancel() {
}
}).show();
}
@Override
public void cancel() {
}
}).show();
} else {
DialogUtil.showSelectDialog(MainActivity.this, "电话权限不可用", "请在-应用设置-权限中,允许APP使用电话权限来测试", "取消", "立即开启", new DialogUtil.DialogClickListener() {
@Override
public void confirm() {
goToAppSetting();
}
@Override
public void cancel() {
}
}).show();
}
}else if (requestCode==1){
//如果拒绝授予权限,且勾选了再也不提醒
if (!shouldShowRequestPermissionRationale(Manifest.permission.CALL_PHONE)) {
DialogUtil.showSelectDialog(this, "说明", "需要使用相机权限,进行相机测试", "取消", "确定", new DialogUtil.DialogClickListener() {
@Override
public void confirm() {
//用于在用户勾选“不再提示”并且拒绝时,再次提示用户
DialogUtil.showSelectDialog(MainActivity.this, "相机权限不可用", "请在-应用设置-权限中,允许APP使用相机权限来测试", "取消", "立即开启", new DialogUtil.DialogClickListener() {
@Override
public void confirm() {
goToAppSetting();
}
@Override
public void cancel() {
}
}).show();
}
@Override
public void cancel() {
}
}).show();
} else {
DialogUtil.showSelectDialog(MainActivity.this, "相机权限不可用", "请在-应用设置-权限中,允许APP使用相机权限来测试", "取消", "立即开启", new DialogUtil.DialogClickListener() {
@Override
public void confirm() {
goToAppSetting();
}
@Override
public void cancel() {
}
}).show();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (mPermissionHelper.requestPermissionsResult(requestCode, permissions, grantResults)) {
//权限请求结果,并已经处理了该回调
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
/**
* 打开Setting
*/
private void goToAppSetting() {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, 123);
}
}
2.Dialog工具类:
/**
* Created by YuShuangPing on 2018/11/5.
*/
public class DialogUtil {
/**
* 创建一个选择对话框
*
* @param context
* @param pContent 提示消息
* @param dialogClickListener 点击监听
* @return
*/
public static Dialog showSelectDialog(Context context, String title, String pContent, String pLeftBtnStr,
String pRightBtnStr,
final DialogClickListener dialogClickListener) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
AlertDialog dialog = builder.setTitle(title)
.setMessage(pContent)
.setPositiveButton(pRightBtnStr, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialogClickListener.confirm();
dialog.dismiss();
}
})
.setNegativeButton(pLeftBtnStr, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialogClickListener.cancel();
dialog.dismiss();
// return;
}
})
.create();
return dialog;
}
public interface DialogClickListener {
public abstract void confirm();
public abstract void cancel();
}
}
权限的接口类:
/**
* 权限请求接口
* Created by YuShuangPing on 2018/11/1.
*/
public interface PermissionInterface {
/**
* 可得到请求权限请求码
*/
int getPermissionsRequestCode();
/**
* 请求权限成功回调
*/
void requestPermissionsSuccess();
/**
* 请求权限失败回调
*/
void requestPermissionsFail();
}
权限的帮助类:
/**
* 动态权限帮助类
* Created by YuShuangPing on 2018/11/1.
*/
public class PermissionHelper {
private Activity mActivity;
private PermissionInterface mPermissionInterface;
public PermissionHelper(@NonNull Activity activity, @NonNull PermissionInterface permissionInterface) {
mActivity = activity;
mPermissionInterface = permissionInterface;
}
/**
* 开始请求权限。
* 方法内部已经对Android M 或以上版本进行了判断,外部使用不再需要重复判断。
* 如果设备还不是M或以上版本,则也会回调到requestPermissionsSuccess方法。
*/
public void requestPermissions(String[] permissions) {
String[] deniedPermissions = PermissionUtil.getDeniedPermissions(mActivity, permissions);
if (deniedPermissions != null && deniedPermissions.length > 0) {
PermissionUtil.requestPermissions(mActivity, deniedPermissions, mPermissionInterface.getPermissionsRequestCode());
} else {
mPermissionInterface.requestPermissionsSuccess();
}
}
/**
* 在Activity中的onRequestPermissionsResult中调用
* @param requestCode
* @param permissions
* @param grantResults
* @return true 代表对该requestCode感兴趣,并已经处理掉了。false 对该requestCode不感兴趣,不处理。
*/
public boolean requestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == mPermissionInterface.getPermissionsRequestCode()) {
boolean isAllGranted = true;//是否全部权限已授权
for(int result : grantResults){
if(result == PackageManager.PERMISSION_DENIED){
isAllGranted = false;
break;
}
}
if(isAllGranted){
//已全部授权
mPermissionInterface.requestPermissionsSuccess();
}else{
//权限有缺失
mPermissionInterface.requestPermissionsFail();
}
return true;
}
return false;
}
}
权限的工具类:
/**
* 动态权限工具类
* Created by YuShuangPing on 2018/11/1.
*/
public class PermissionUtil {
/**
* 弹出对话框请求权限
* @param activity
* @param permissions
* @param requestCode
*/
public static void requestPermissions(Activity activity, String[] permissions, int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity.requestPermissions(permissions, requestCode);
}
}
/**
* 返回缺失的权限
* @param context
* @param permissions
* @return 返回缺少的权限,null 意味着没有缺少权限
*/
public static String[] getDeniedPermissions(Context context, String[] permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ArrayList<String> deniedPermissionList = new ArrayList<>();
for (String permission : permissions) {
if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
deniedPermissionList.add(permission);
}
}
int size = deniedPermissionList.size();
if (size > 0) {
return deniedPermissionList.toArray(new String[deniedPermissionList.size()]);
}
}
return null;
}
}
在需要权限的界面进行调用就可以了,如果想看具体的效果可以下载demo,导入AndroidStudio