概述

最近项目中涉及到权限开发,发现Android 6.0以后权限被官方重新设计了,经过一顿查阅资料加实践,于是决定结合代码对权限开发知识做个梳理总结,希望对大家有用。(ps:个人第一次写论文,有错误的地方希望能留言指正哈~~~~)。

1.为啥使用权限

由于每个Android应用都在进程沙盒中运行,沙盒内的资源数据是共享开放的,但是想要获取沙盒外的资源数据,需要申明所需权限,部分权限需要用户授权。

2.权限级别

(1)正常权限:不会对用户隐私或设备操作造成很大风险的权限。应用运行时,系统会自动授权该权限。
(2)危险权限:可能影响用户隐私或设备正常操作的权限。例如,读取用户的联系人就属于危险权限。应用运行时需要用户手动授权该权限。

3.授权方式

这里先了解一下权限组的概念,任何权限都属于一个权限组,该权限组可以是多个,也可以是一个。举个栗子:

Permission Group

Single Permission

CAMERA

• CAMERA

CONTACTS

• READ_CONTACTS

• WRITE_CONTACTS

• GET_ACCOUNTS

Android 5.1(API22)及之前:你想授权某权限,系统会在安装时要求用户授权权限组。
Android 6.0(API23)及之后:你想授权某权限,系统会弹出一个描述权限组文字的弹出框,栗如你想要给READ_CONTACTS授权,系统会给出“应用需要访问设备联系人”而不是“应用需要读取设备联系人”的提示。

4.检查权限

如果你的应用需要一个危险权限,你每次执行该权限下的操作时都必须检查你是否被授予了该权限。用户可以随便撤销某个权限,所以即使应用昨天还能使用相机,那也没法保证今天也有权使用。为了检查当前是否拥有该权限.可以调用ContextCompat.checkSelfPermission()方法。

/**
     * 检查是否对该权限授权
     * 拥有该权限返回true
     * 否则返回false
     */
    private boolean checkPermission(Context context, String permission){
        if(ContextCompat.checkSelfPermission(context,permission) == PackageManager.PERMISSION_GRANTED){
            return true;
        }
        return false;
    }

5.请求权限

请求权限发生在用户还没对该权限授权的情况下。
笔者把它分成直接请求间接请求,拿请求相机权限举栗,所谓直接请求就是点击拍照按钮,我直接请求该权限,看看用户会不会授权,假如请求被拒绝了,那下次再请求该权限可以加个提示框,说明下这个权限对应用将要使用沙盒外的拍照功能很重要,这就形成了间接请求,android提供了shouldShowRequestPermissionRationale()方法告诉程序是直接请求还是间接请求。请求权限用方法ActivityCompat.requestPermissions()。

if(!checkPermission(this, Manifest.permission.CAMERA)){
    if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)){
        //向用户显示一个解释,等用户看完解释后再继续尝试请求权限
        //、、、、、、
    }else{
        //直接请求权限
		ActivityCompat.requestPermissions(this,
        	new String[]{Manifest.permission.CAMERA},
        	REQUEST_PERMISSION_OF_CAMERA);
    }
}else{
    //权限被授权,打开相机
}

REQUEST_PERMISSION_OF_CAMERA 是应用自定义的一个int常量,用户唯一标识一个权限请求以便回调时进行判断

6.处理请求响应结果

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){
        case REQUEST_PERMISSION_OF_CAMERA:
			// 如果请求被取消了,那么结果数组就是空的
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限被授予了,打开相机
            } else {
                // 权限请求被拒绝了,不能继续依赖该权限的相关操作了
            }
            break;
    }
}

7.请求流程

android 多用户模式的权限管理 安卓用户权限_android 多用户模式的权限管理

8.核心完整代码

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.little_seven.permission">
	<uses-permission android:name="android.permission.CAMERA"/>
</manifest>
package com.little_seven.permission;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.StaticLayout;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final int REQUEST_PERMISSION_OF_CAMERA = 1000;
    private PermissionDialogFragment dialogFragment;
    private boolean isFirst = true;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initClick();
    }

    private void initClick(){
        findViewById(R.id.btn_click).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                requestPermission();
            }
        });
    }

    private void requestPermission(){
        if(!checkPermission(this, Manifest.permission.CAMERA)){
            if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)){
                //向用户显示一个解释,等用户看完解释后再继续尝试请求权限
                dialogFragment = PermissionDialogFragment.newInstance("应用需要获取您的相机权限,以便用于扫描二维码");
                dialogFragment .show(getSupportFragmentManager(),"dialog for permission");
                dialogFragment.setOnDialogClick(new PermissionDialogFragment.OnDialogClick() {
                    @Override
                    public void clickSure() {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.CAMERA},
                                REQUEST_PERMISSION_OF_CAMERA);
                    }
                    @Override
                    public void clickCancle() {

                    }
                });
            }else{
                //直接请求权限
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.CAMERA},
                        REQUEST_PERMISSION_OF_CAMERA);
            }
        }else{
            //权限被授权,打开相机
        }
    }

    /**
     * 检查是否对该权限授权
     * 拥有该权限返回true
     * 否则返回false
     */
    private boolean checkPermission(Context context, String permission){
        if(ContextCompat.checkSelfPermission(context,permission) == PackageManager.PERMISSION_GRANTED){
            return true;
        }
        return false;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case REQUEST_PERMISSION_OF_CAMERA:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // 权限被授予了,打开相机
                } else {
                    // 权限请求被拒绝了,不能继续依赖该权限的相关操作了
                    if(!ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)){
                        if(isFirst){
                            isFirst = false;
                            return;
                        }
                        dialogFragment = PermissionDialogFragment.newInstance("请前往“设置>应用>[你的应用]”页面进行手动授权相机权限");
                        dialogFragment .show(getSupportFragmentManager(),"dialog for permission");
                        dialogFragment.setOnDialogClick(new PermissionDialogFragment.OnDialogClick() {
                            @Override

                            public void clickSure() {
                                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                Uri uri = Uri.fromParts("package", MainActivity.this.getPackageName(), null);
                                intent.setData(uri);
                                startActivity(intent);
                            }

                            @Override
                            public void clickCancle() {

                            }
                        });
                    }
                }
                break;
        }
    }
}

DialogFragment也贴一下

package com.little_seven.permission;

import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.TextView;


public class PermissionDialogFragment extends DialogFragment implements View.OnClickListener {
    private View contentView;
    private TextView tv_content;
    private String content;

    public static PermissionDialogFragment newInstance(String content){
        Bundle bundle = new Bundle();
        bundle.putString("content",content);
        PermissionDialogFragment fragment = new PermissionDialogFragment();
        fragment.setArguments(bundle);
        return fragment;
    }


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        if(contentView == null){
            contentView = inflater.inflate(R.layout.dialog_permission,null);
            initView(contentView);
        }
        return contentView;
    }

    @Override
    public void onStart() {
        super.onStart();
        getDialog().getWindow().getAttributes().gravity = Gravity.CENTER;
    }

    private void initView(View contentView){
        content = getArguments().getString("content");
        getDialog().setCancelable(false);
        getDialog().setCanceledOnTouchOutside(false);
        tv_content = contentView.findViewById(R.id.tv_content);
        tv_content.setText(content);
        contentView.findViewById(R.id.btn_sure).setOnClickListener(this);
        contentView.findViewById(R.id.btn_cancle).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_sure:
                onDialogClick.clickSure();
                getDialog().dismiss();
                break;
            case R.id.btn_cancle:
                onDialogClick.clickCancle();
                getDialog().dismiss();
                break;
        }

    }

    private OnDialogClick onDialogClick;

    public void setOnDialogClick(OnDialogClick onDialogClick){
        this.onDialogClick = onDialogClick;
    }

    public interface OnDialogClick{
        void clickSure();
        void clickCancle();
    }
}