需求来源
Android M(6.0)以后Google添加了动态权限的区分,将权限分为了普通权限和危险权限。当应用功能涉及到危险权限时需要动态向用户申请,且用户授权后方可使用。
普通权限
极少数给用户带来隐私信息风险的权限。该类权限可直接在 AndroidManifest 文件中注册,运行时系统自动给予。
危险权限
涉及到用户隐私信息的权限,例如:联系人,录音等等。该类权限不仅要在 AndroidManifest 文件中注册,还需使用代码动态向用户申请。需要注意的是:动态权限以组划分,若用户授权其中的一个权限,则整组权限都将被授予。
工具类
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
/**
* 检查 & 申请权限帮助类
*
* @author JokerCats
*/
public class PermissionHelper {
private final int mRequestCode = 100;// 权限请求码
private boolean mShowSystemSetting = true;// 若用户存在未授权情况,默认显示系统设置
private PermissionHelper() {
}
private static PermissionHelper sHelper;
public static PermissionHelper getInstance() {
if (sHelper == null) {
sHelper = new PermissionHelper();
}
return sHelper;
}
private PermissionResult mResult;
/**
* 引导用户进入系统设置的弹窗
*/
private AlertDialog mDialog;
/**
* 检查权限
*
* @param ctx 上下文
* @param permissions 待请求权限组
* @param result 请求结果回调
*/
public void checkPermissions(Activity ctx, String[] permissions, @NonNull PermissionResult result) {
mResult = result;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
mResult.passPermissions();// Android 6.0不需要动态申请权限
return;
}
// 创建未授予权限数组
ArrayList<String> unauthorizedList = new ArrayList<>();
// 检查权限
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(ctx, permission) != PackageManager.PERMISSION_GRANTED) {
unauthorizedList.add(permission);// 添加未授予权限
}
}
if (unauthorizedList.size() > 0) {
// 申请未授权权限
ActivityCompat.requestPermissions(ctx, permissions, mRequestCode);
} else {
mResult.passPermissions();
}
}
/**
* 请求权限结果回调
*
* @param ctx 上下文
* @param requestCode 请求码
* @param permissions 待请求权限组
* @param grantResults 授权标识数组(长度与待请求数组一致)数据 0 为允许权限;数据 -1 为禁止权限
*/
public void onRequestPermissionResult(Activity ctx, int requestCode,
@NonNull String[] permissions, @NonNull int[] grantResults) {
// 授权结果假想值
boolean allPass = true;
if (requestCode == mRequestCode) {
// 遍历标识数组,重置授权结果
for (int result : grantResults) {
if (result == PackageManager.PERMISSION_DENIED) {
allPass = false;
}
}
}
if (allPass) {
mResult.passPermissions();
} else {
if (mShowSystemSetting) {
showSettingDialog(ctx);
} else {
mResult.forbidPermissions();
}
}
}
/**
* 当权限缺失时是否显示系统设置弹窗
*
* @param show 是否显示
*/
public void showDialogWhenForbid(boolean show) {
mShowSystemSetting = show;
}
/**
* 显示系统设置弹窗
*
* @param ctx 上下文
*/
private void showSettingDialog(Activity ctx) {
if (mDialog == null) {
mDialog = new AlertDialog.Builder(ctx)
.setMessage("权限已禁用,为避免功能缺失请到设置重新开启")
.setPositiveButton("设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
cancelSettingDialog();
Uri packageURI = Uri.parse("package:" + ctx.getPackageName());
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
ctx.startActivity(intent);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
cancelSettingDialog();
mResult.forbidPermissions();
}
})
.setCancelable(false)
.create();
}
mDialog.show();
}
private void cancelSettingDialog() {
if (mDialog != null) {
mDialog.cancel();
mDialog = null;
}
}
public interface PermissionResult {
// 通过的权限
void passPermissions();
// 禁止的权限
void forbidPermissions();
}
}
/*
Danger permission:
同组若一个权限被授予,则组内其他权限自动授予
group:android.permission-group.CONTACTS(联系人)
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
group:android.permission-group.PHONE(电话)
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR(日历)
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
group:android.permission-group.CAMERA(相机)
permission:android.permission.CAMERA
group:android.permission-group.SENSORS(传感器)
permission:android.permission.BODY_SENSORS
group:android.permission-group.LOCATION(位置)
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
group:android.permission-group.STORAGE(存储卡)
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
group:android.permission-group.MICROPHONE(麦克风)
permission:android.permission.RECORD_AUDIO
group:android.permission-group.SMS(短信)
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS
*/
使用示例
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO
};
PermissionHelper.getInstance().checkPermissions(activity, PERMISSIONS_STORAGE, new PermissionHelper.PermissionResult() {
@Override
public void passPermissions() {
Toast.makeText(activity, "权限已授权 为所欲为模式启动", Toast.LENGTH_SHORT).show();
}
@Override
public void forbidPermissions() {
Toast.makeText(activity, "权限意识满分!!", Toast.LENGTH_SHORT).show();
}
});
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionHelper.getInstance().onRequestPermissionResult(this, requestCode, permissions, grantResults);
}
Tips
帮助类中列出了危险权限及对应功能,方便程序查找辨别。
想对权限这部分更加深入的同学可以移步 官方文档
当然很多优秀的开源框架也是不容错过的 RxPermissions (ฅ´ω`ฅ)
至此一个Android原生的权限帮助类就完成了,希望可以帮助到有需要的同学。
<script>alert("baka大姐头");</script>
alert("baka姐姐");
alert("baka姐姐");