Android6.0权限适配


Google在Android 6.0 上开始原生支持应用权限管理,再不是安装应用时的一刀切,很多权限需要在需要时实时请求,如果你的应用还没有做好6.0以上权限的适配,那么需要先限制targetSdkVersion在22及以下


当你做好处理, 就可以设置到22以上了,那么需要做哪些处理呢,首先我们得知道,哪些权限需要实时请求


Android的权限分为三类:

  • 普通权限(Normal Permissions)
  • 危险权限(Dangerous Permissions)
  • 特殊权限(Special Permissions)
普通权限

普通权限不会对用户的隐私和安全产生太大的风险,所以只需要在AndroidManifest.xml中声明即可.


危险权限

权限组 权限
android.permission-group.CALENDAR(日历数据)
  • android.permission.READ_CALENDAR
  • android.permission.WRITE_CALENDAR
android.permission-group.CAMERA(相机)
  • android.permission.CAMERA
android.permission-group.CONTACTS(联系人)
  • android.permission.READ_CONTACTS
  • android.permission.WRITE_CONTACTS
  • android.permission.GET_ACCOUNTS
android.permission-group.LOCATION(位置)
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
android.permission-group.MICROPHONE(麦克风)
  • android.permission.RECORD_AUDIO
android.permission-group.PHONE(电话)
  • android.permission.READ_PHONE_STATE
  • android.permission.CALL_PHONE
  • android.permission.READ_CALL_LOG
  • android.permission.WRITE_CALL_LOG
  • com.android.voicemail.permission.ADD_VOICEMAIL
  • android.permission.USE_SIP
  • android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS(传感器)
  • android.permission.BODY_SENSORS
android.permission-group.SMS(短信)
  • android.permission.SEND_SMS
  • android.permission.RECEIVE_SMS
  • android.permission.READ_SMS
  • android.permission.RECEIVE_WAP_PUSH
  • android.permission.RECEIVE_MMS
  • android.permission.READ_CELL_BROADCASTS
android.permission-group.STORAGE(存储)
  • android.permission.READ_EXTERNAL_STORAGE
  • android.permission.WRITE_EXTERNAL_STORAGE


获取分组中某个权限的同时也就获取了同组中的其他权限。

比如,在应用中申请READ_EXTERNAL_STORAGE权限,用户同意授权后,则应用同时具有READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限


切记,危险权限除了需要动态申请,也还是需要在Manifest中声明的


特殊权限

Special Permissions
SYSTEM_ALERT_WINDOW 设置悬浮窗
WRITE_SETTINGS 修改系统设置

看权限名就知道特殊权限危险权限更危险,特殊权限需要在manifest中申请并且通过发送Intent让用户在设置界面进行勾选.

特殊权限申请方式:

SYSTEM_ALERT_WINDOW

     
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     
     
private static final int REQUEST_CODE = 1;
private void requestAlertWindowPermission() {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse( "package:" + getPackageName()));
startActivityForResult(intent, REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE) {
if (Settings.canDrawOverlays( this)) {
Log.i(LOGTAG, "onActivityResult granted");
}
}
}

WRITE_SETTINGS 

     
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     
     
private static final int REQUEST_CODE_WRITE_SETTINGS = 2;
private void requestWriteSettings() {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse( "package:" + getPackageName()));
startActivityForResult(intent, REQUEST_CODE_WRITE_SETTINGS );
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_WRITE_SETTINGS) {
if (Settings.System.canWrite( this)) {
Log.i(LOGTAG, "onActivityResult write settings granted" );
}
}
}

如果永远不将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);
    }
}

至此,权限的封装就结束了





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值