Google在Android 6.0 上开始原生支持应用权限管理,再不是安装应用时的一刀切,很多权限需要在需要时实时请求,如果你的应用还没有做好6.0以上权限的适配,那么需要先限制targetSdkVersion在22及以下
当你做好处理, 就可以设置到22以上了,那么需要做哪些处理呢,首先我们得知道,哪些权限需要实时请求
Android的权限分为三类:
- 普通权限(Normal Permissions)
- 危险权限(Dangerous Permissions)
- 特殊权限(Special Permissions)
权限组 | 权限 |
---|---|
android.permission-group.CALENDAR(日历数据) |
|
android.permission-group.CAMERA(相机) |
|
android.permission-group.CONTACTS(联系人) |
|
android.permission-group.LOCATION(位置) |
|
android.permission-group.MICROPHONE(麦克风) |
|
android.permission-group.PHONE(电话) |
|
android.permission-group.SENSORS(传感器) |
|
android.permission-group.SMS(短信) |
|
android.permission-group.STORAGE(存储) |
|
比如,在应用中申请READ_EXTERNAL_STORAGE
权限,用户同意授权后,则应用同时具有READ_EXTERNAL_STORAGE
和 WRITE_EXTERNAL_STORAGE
权限
切记,危险权限除了需要动态申请,也还是需要在Manifest中声明的
特殊权限
Special Permissions |
---|
SYSTEM_ALERT_WINDOW 设置悬浮窗 |
WRITE_SETTINGS 修改系统设置 |
看权限名就知道特殊权限比危险权限更危险,特殊权限
需要在manifest中申请并且通过发送Intent让用户在设置界面进行勾选.
特殊权限申请方式:
SYSTEM_ALERT_WINDOW
|
|
WRITE_SETTINGS
|
|
如果永远不将targetSdkVersion设置到22以上是不是就没事了?错,如果用户去权限中心禁用了(当然一般用户不会去这么做),他会让你运行到对应代码时直接崩溃
更何况有很多手机会在应用运行时一个个权限弹出来帮你申请,用户手一滑或者无法理解时一禁用,你就杯具了,所以还是得处理
如何开始动态申请权限
首先我们得知道有哪些方法
ContextCompat.checkSelfPermission(Context context,String permission) //判断权限是否具有某项权限
ActivityCompat.requestPermissions(Activity activity,String[] permissions,int requestCode)//申请权限
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)//申请权限回调方法,在Activity或Fragment重写
ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission)//是否要提示用户申请该权限的缘由
有了这几个方法之后,我们需要整理一下我们对权限申请的流程是个什么样子的安排
你说请求权限时的不再提示是否要处理?不用了,用户第一次拒绝了之后就可以给用户提示了,为什么要等第二次
那么流程有了之后就是代码了
首先是对权限检查以及申请的工具类
PermissionUtil
/**
* Created by yangjh on 2017/3/10.
* 这个类用于6.0以上权限的处理
*/
public class PermissionUtil {
private final String TAG = "PermissionUtil";
private int REQUEST_CODE_PERMISSION = 0x00099;
/**
* 请求权限
*
* @param permissions 请求的权限
* @param requestCode 请求权限的请求码
*/
public boolean requestPermission(String[] permissions, int requestCode,Activity activity) {
this.REQUEST_CODE_PERMISSION = requestCode;
//检查是否具有一些权限
if (checkPermissions(permissions,activity)) {
permissionSuccess(REQUEST_CODE_PERMISSION);
return true;
} else {//发现有权限未申请到,则准备发出申请
//获取未申请到的权限列表
List<String> needPermissions = getDeniedPermissions(permissions,activity);
//发出权限申请
ActivityCompat.requestPermissions(activity, needPermissions.toArray(new String[needPermissions.size()]), REQUEST_CODE_PERMISSION);
return false;
}
}
/**
* 系统请求权限回调,返回TRUE表示权限都通过了不需要处理
* 返回FALSE表示有未通过的需要提示处理
*
* @param requestCode
* @param permissions
* @param grantResults
*/
public boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE_PERMISSION) {
//确认所有权限是否都已授权
if (verifyPermissions(grantResults)) {
permissionSuccess(REQUEST_CODE_PERMISSION);
return true;
} else {//发现有没有授权的
permissionFail(REQUEST_CODE_PERMISSION);
// showTipsDialog();
return false;
}
}
return true;
}
/**
* 检测所有的权限是否都已授权
*
* @param permissions
* @return
*/
private boolean checkPermissions(String[] permissions,Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(activity, permission) !=
PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 确认所有的权限是否都已授权
*
* @param grantResults
* @return
*/
private boolean verifyPermissions(int[] grantResults) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 获取需要申请权限的列表
*
* @param permissions
* @return
*/
private List<String> getDeniedPermissions(String[] permissions,Activity activity) {
List<String> needRequestPermissionList = new ArrayList<>();
for (String permission : permissions) {
//发现这条权限没有获取到权限,或者系统认为需要提示用户申请该权限的缘由时
if (ContextCompat.checkSelfPermission(activity, permission) !=
PackageManager.PERMISSION_GRANTED ||
ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
//添加需要提示的权限进集合
needRequestPermissionList.add(permission);
}
}
return needRequestPermissionList;
}
/**
* 获取权限成功
*
* @param requestCode
*/
public void permissionSuccess(int requestCode) {
Log.d(TAG, "获取权限成功=" + requestCode);
}
/**
* 权限获取失败
* @param requestCode
*/
public void permissionFail(int requestCode) {
Log.d(TAG, "获取权限失败=" + requestCode);
}
}
然后是对权限申请的逻辑的组织类:
PermissionApply
/**
* Created by yangjh on 2017/3/10.
* 权限申请的入口类,负责申请对应的权限以及权限申请成功时候后的处理
* 这里有一种情况目前没有处理,就是比如:
* 先申请电话权限,然后在还没得到结果时又申请SD卡权限,此时会导致检查权限申请状况时,电话权限检查不到,所以不要这样申请
*/
public class PermissionApply {
private PermissionUtil permissionUtil;
private Activity mActivity;
HashMap<Integer,OnPermissResponse> permissionResponses = new HashMap<Integer,OnPermissResponse>();
public PermissionApply(Activity activity){
mActivity = activity;
permissionUtil = new PermissionUtil();
}
/**
* 请求电话权限
*/
public void requestPhonePermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_CALL_PHONE,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_CALL_PHONE}, REQUEST_CALL_PHONE,mActivity)){
callBack(REQUEST_CALL_PHONE);
}
}
/**
* 请求SD卡权限
*/
public void requestSDCardPermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_WRITE_EXTERNAL_STORAGE,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE,mActivity)){
callBack(REQUEST_WRITE_EXTERNAL_STORAGE);
}
}
/**
* 请求相机权限
*/
public void requestCameraPermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_CAMERA,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_CAMERA}, REQUEST_CAMERA,mActivity)){
callBack(REQUEST_CAMERA);
}
}
/**
* 请求联系人权限
*/
public void requestContactsPermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_CONTACTS,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_CONTACTS}, REQUEST_CONTACTS,mActivity)){
callBack(REQUEST_CONTACTS);
}
}
/**
* 请求日历权限
*/
public void requestCalendarPermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_CALENDAR,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_CALENDAR}, REQUEST_CALENDAR,mActivity)){
callBack(REQUEST_CALENDAR);
}
}
/**
* 请求地理(GPS)权限
*/
public void requestLocationPermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_LOCATION,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_LOCATION}, REQUEST_LOCATION,mActivity)){
callBack(REQUEST_LOCATION);
}
}
/**
* 请求麦克风权限
*/
public void requestMicrophonePermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_MICROPHONE,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_MICROPHONE}, REQUEST_MICROPHONE,mActivity)){
callBack(REQUEST_MICROPHONE);
}
}
/**
* 请求传感器权限
*/
public void requestSensorsPermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_SENSORS,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_SENSORS}, REQUEST_SENSORS,mActivity)){
callBack(REQUEST_SENSORS);
}
}
/**
* 请求短信权限
*/
public void requestSmsPermission(OnPermissResponse permissionRes){
permissionResponses.put(REQUEST_SMS,permissionRes);
if(permissionUtil.requestPermission(new String[]{PERMISSION_SMS}, REQUEST_SMS,mActivity)){
callBack(REQUEST_SMS);
}
}
/**
* 接收权限请求的结果
* @param requestCode
* @param permissions
* @param grantResults
*/
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){
boolean success = permissionUtil.onRequestPermissionsResult(requestCode,permissions,grantResults);
if(!success){//没有成功就打开设置页面
showTipsDialog();
}else{
callBack(requestCode);
}
}
private void callBack(int requestCode){
OnPermissResponse response = permissionResponses.get(requestCode);
if(null != response){
response.onPermissionSuccess();
}
}
/**
* 显示提示对话框
*/
private void showTipsDialog() {
new AlertDialog.Builder(mActivity)
.setTitle("提示信息")
.setMessage("当前应用缺少必要权限,该功能暂时无法使用。如若需要,请单击【确定】按钮前往设置中心进行权限授权。")
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startAppSettings();
}
}).show();
}
/**
* 启动当前应用设置页面
*/
private void startAppSettings() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + mActivity.getPackageName()));
mActivity.startActivity(intent);
}
public interface OnPermissResponse{
public abstract void onPermissionSuccess();
}
//请求电话方面的权限
private static final String PERMISSION_CALL_PHONE = Manifest.permission.CALL_PHONE;
private static final int REQUEST_CALL_PHONE = 0x0001;
//SD卡读取写入权限
private static final String PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;
private static final int REQUEST_WRITE_EXTERNAL_STORAGE = 0x0002;
//相机
private static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;
private static final int REQUEST_CAMERA = 0x0003;
//读取联系人
private static final String PERMISSION_CONTACTS = Manifest.permission.READ_CONTACTS;
private static final int REQUEST_CONTACTS = 0x0004;
//日历
private static final String PERMISSION_CALENDAR = Manifest.permission.READ_CALENDAR;
private static final int REQUEST_CALENDAR = 0x0005;
//GPS
private static final String PERMISSION_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
private static final int REQUEST_LOCATION = 0x0006;
//麦克风
private static final String PERMISSION_MICROPHONE = Manifest.permission.RECORD_AUDIO;
private static final int REQUEST_MICROPHONE = 0x0007;
//传感器
private static final String PERMISSION_SENSORS = Manifest.permission.BODY_SENSORS;
private static final int REQUEST_SENSORS = 0x0008;
//短信
private static final String PERMISSION_SMS = Manifest.permission.READ_SMS;
private static final int REQUEST_SMS = 0x0009;
}
这两个类就足够了,然后是调用的示例:
/**
* Created by yangjh on 2017/3/9.
*/
public class ActivityS extends Activity {
PermissionApply apply;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main2);
apply = new PermissionApply(this);
ImageView img1 = (ImageView)findViewById(R.id.img1);
img1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
apply.requestPhonePermission(new PermissionApply.OnPermissResponse() {
@Override
public void onPermissionSuccess() {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:10086"));
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(callIntent);
}
});
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
apply.onRequestPermissionsResult(requestCode,permissions,grantResults);
}
}
至此,权限的封装就结束了