2018-07-14 11:47:32 qq_33200967 阅读数 1076
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12940 人正在学习 去看看 CSDN讲师

目录

前言

在Android 6.0(API 级别 23)以下申请权限是非常简单的,直接在AndroidManifest.xml这个配置文件中加入申请权限的列表就可以了,比如我要申请四个权限,如下:

<!--打电话-->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!--使用相机-->
<uses-permission android:name="android.permission.CAMERA" />
<!--写入内存卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--读取内存卡-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

但是在Android 6.0(API 级别 23)以上的版就不可以这样申请了,因为这样申请权限对用户来说是非常危险的,应用已安装就获取了全部权限,也不知道这些权限应用要来干什么,可能是用户不希望发生的一些操作。所以在Android 6.0之后,一些危险的权限就要动态申请了,哪些是危险权限呢,下面是官方提供的一个需要动态申请的危险权限:

权限组 权限
CALENDAR • READ_CALENDAR
• WRITE_CALENDAR
CAMERA • CAMERA
CONTACTS • READ_CONTACTS
• WRITE_CONTACTS
• GET_ACCOUNTS
LOCATION • ACCESS_FINE_LOCATION
• ACCESS_COARSE_LOCATION
MICROPHONE • RECORD_AUDIO
PHONE • READ_PHONE_STATE
• CALL_PHONE
• READ_CALL_LOG
• WRITE_CALL_LOG
• ADD_VOICEMAIL
• USE_SIP
• PROCESS_OUTGOING_CALLS
SENSORS • BODY_SENSORS
SMS • SEND_SMS
• RECEIVE_SMS
• READ_SMS
• RECEIVE_WAP_PUSH
• RECEIVE_MMS
STORAGE • READ_EXTERNAL_STORAGE
• WRITE_EXTERNAL_STORAGE

如果要使用上面的权限,除了要在AndroidManifest.xml这个配置文件声明,还要在Java代码中增加动态申请。下面我们就介绍如何单个和多个权限动态申请。

单个权限的动态申请

比如我们的应用要打电话,打电话是一个危险权限.

  • 首先需要动态申请AndroidManifest.xml配置文件添加申请打电话权限的声明,如下:
<!--打电话-->
<uses-permission android:name="android.permission.CALL_PHONE" />
  • 然后在Java代码中编写一个动态申请打电话权限的方法,当我们需要打电话之前,先要调用这个方法获取权限:
// 请求单个权限
private void request_permission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
            != PackageManager.PERMISSION_GRANTED) {
        // 最后的请求码是对应回调方法的请求码
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.CALL_PHONE}, 1001);
    } else {
        Toast.makeText(this, "你已经有权限了,可以直接拨打电话", Toast.LENGTH_LONG).show();
    }
}
  • 请求申请权限之后,当用户同意或者拒绝权限之后,都会在请求权限的回调方法反馈,我们可以在这个回调方法中判断是否已经授权,并做相关的操作:
// 请求权限回调方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case 1001:
            // 1001的请求码对应的是申请打电话的权限
            // 判断是否同意授权,PERMISSION_GRANTED 这个值代表的是已经获取了权限
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(MainActivity.this, "你同意授权,可以打电话了", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(MainActivity.this, "你不同意授权,不可以打电话", Toast.LENGTH_LONG).show();
            }
            break;
    }
}
  • 我们增加一个按钮,让这个按钮的点击事件调用我们的申请权限方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button request_permission_btn = (Button) findViewById(R.id.request_permission_btn);

    // 点击获取单个权限
    request_permission_btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            request_permission();
        }
    });
}
  • activity_main中的界面代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.yeyupiaoling.testpermission.MainActivity">

    <Button
        android:id="@+id/request_permission_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请求单个权限" />
</LinearLayout>
  • 测试我们的程序,第二个按钮时下一部分的,读者目前可以不用理会。第一次申请的时候是没有权限的,然后就会动态申请权限,用户同意了就获得了权限。第二次申请权限时,因为第一次已经申请到了,所以可以直接使用了。
    这里写图片描述

多个权限动态申请

  • 多个权限申请也是一样的,首先同样需要动态申请AndroidManifest.xml配置文件添加所有申请的权利,如下。值得注意的是WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE都是属于STORAGE组的,在申请它们两个的时候吗,只要同意一个,系统会立即另外一个权限,不会再弹出权限授予询问的对话框。
<!--使用相机-->
<uses-permission android:name="android.permission.CAMERA" />
<!--写入内存卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--读取内存卡-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  • 多个权限的申请就复杂一些,首先要先创建一个列表,把需要的申请的权限添加到这个列表中,最后统一提交申请:
// 请求多个权限
private void request_permissions() {
    // 创建一个权限列表,把需要使用而没用授权的的权限存放在这里
    List<String> permissionList = new ArrayList<>();

    // 判断权限是否已经授予,没有就把该权限添加到列表中
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        permissionList.add(Manifest.permission.CAMERA);
    }

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
    }

    // 如果列表为空,就是全部权限都获取了,不用再次获取了。不为空就去申请权限
    if (!permissionList.isEmpty()) {
        ActivityCompat.requestPermissions(this,
                permissionList.toArray(new String[permissionList.size()]), 1002);
    } else {
        Toast.makeText(this, "多个权限你都有了,不用再次申请", Toast.LENGTH_LONG).show();
    }
}
  • 申请多个权限,在回调方法中也会反馈多个权限的申请结果,所以我们要判断每个权限的申请结果,全部的权限都申请成功了,那才是申请成功了:
// 请求权限回调方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case 1002:
            // 1002请求码对应的是申请多个权限
            if (grantResults.length > 0) {
                // 因为是多个权限,所以需要一个循环获取每个权限的获取情况
                for (int i = 0; i < grantResults.length; i++) {
                    // PERMISSION_DENIED 这个值代表是没有授权,我们可以把被拒绝授权的权限显示出来
                    if (grantResults[i] == PackageManager.PERMISSION_DENIED){
                        Toast.makeText(MainActivity.this, permissions[i] + "权限被拒绝了", Toast.LENGTH_SHORT).show();
                    }
                }
            }
            break;
    }
}
  • 我们同样增加一个按钮,让这个按钮的点击事件调用我们的申请多个权限方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button request_permissions_btn = (Button) findViewById(R.id.request_permissions_btn);

    // 点击获取多个权限
    request_permissions_btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            request_permissions();
        }
    });
}
  • activity_main中的界面代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.yeyupiaoling.testpermission.MainActivity">

    <Button
        android:id="@+id/request_permissions_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请求多个权限" />
</LinearLayout>
  • 效果展示,当我们点击按钮申请多个权限时,就会开始申请多个权限。如上面所说的读取内存卡和写入内存卡属于一个组,所以我们在看到关于内存卡的只是申请一次,如果一个拒绝了,那就全部都拒绝了。
    这里写图片描述

参考资料

  1. https://developer.android.com/guide/topics/security/permissions#normal-dangerous
2018-08-13 15:43:04 qq_36699930 阅读数 155
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12940 人正在学习 去看看 CSDN讲师

android 6.0 (API 23) 之前应用的权限在安装时全部授予,运行时应用不再需要询问用户。

在 Android 6.0 或更高版本对权限进行了分类,对某些涉及到用户隐私的权限可在运行时根据用户的需要动态授予。

这样就不需要在安装时被强迫同意某些权限。

官网的写法

 public void requestPower() {
    //判断是否已经赋予权限
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.上表权限字符)
                != PackageManager.PERMISSION_GRANTED) {
           //如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.上表权限字符)) {//这里可以写个对话框之类的项向用户解释为什么要申请权限,并在对话框的确认键后续再次申请权限
            } else {
            //申请权限,字符串数组内是一个或多个要申请的权限,1是申请权限结果的返回参数,在onRequestPermissionsResult可以得知申请结果
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.上表权限字符,}, 1);
            }
        }
    }

android6.0动态申请权限:9组27个

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

步骤

1.先判断有没有权限

2.有:直接进行相关操作

3.没有:申请权限

4.授予了权限:直接进行相关操作

5.拒绝:没有勾选不再提醒:重新申请;勾选了不再提醒,去设置界面主动开启权限

申请单个权限

/**
 * 申请单个权限
 * <p>
 * ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission):
 * true:应如果应用之前请求过此权限但用户拒绝了请求,没有点击不再提醒,此方法将返回 true
 * false: 如果应用之前请求过此权限但用户拒绝了请求,点击了不再提醒,此方法将返回 false
 */
public class SinglePermissionActivity extends AppCompatActivity {

    private static final int REQUESET_PERMISSIONS_CODE = 1;

    private String[] permissions = {Manifest.permission.CALL_PHONE};

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

    }


    public void call(View view) {
        //版本>=23,动态申请的权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            checkPermissions();
        } else {
            callPhone();
        }
    }


    private void checkPermissions() {
        //判断是否已经赋予权限
        if (ContextCompat.checkSelfPermission(SinglePermissionActivity.this, permissions[0])
                != PackageManager.PERMISSION_GRANTED) { //没有授予权限
            //申请权限
            ActivityCompat.requestPermissions(SinglePermissionActivity.this, permissions, REQUESET_PERMISSIONS_CODE);

        } else {//授予了权限
            //直接进行相关操作
            callPhone();
        }
    }


    /**
     * 申请权限的回调
     *
     * @param requestCode  请求权限时传入的请求码,用于区别是哪一次请求的
     * @param permissions  所请求的所有权限的数组
     * @param grantResults 权限授予结果,和 permissions 数组参数中的权限一一对应,元素值为两种情况,如下:
     *                     授予: PackageManager.PERMISSION_GRANTED
     *                     拒绝: PackageManager.PERMISSION_DENIED
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == REQUESET_PERMISSIONS_CODE) {
            //授予了权限
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                callPhone();

            } else { //拒绝了该权限

                //如果应用之前请求过此权限但用户拒绝了请求,没有选中不再提醒,此方法将返回 true。
                //写个对话框向用户解释为什么要申请权限,并在对话框的确认键后续再次申请权限
                if (ActivityCompat.shouldShowRequestPermissionRationale(SinglePermissionActivity.this,
                        permissions[0])) { 
                    showPermissionReason();
                } else { //选中了不再提醒,提示用户去应用设置界面手动开启权限
                    showDialogTipUserGoToAppSettting();
                }
            }
        }

    }

    private void showPermissionReason() {
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setMessage("需要拨打电话权限,请开启权限!")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {

                        //再次申请权限
                        if (ContextCompat.checkSelfPermission(SinglePermissionActivity.this, permissions[0])
                                != PackageManager.PERMISSION_GRANTED) { //没有授予权限
                            ActivityCompat.requestPermissions(SinglePermissionActivity.this, permissions, REQUESET_PERMISSIONS_CODE);
                        }
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).setCancelable(false).show();
    }

    private void showDialogTipUserGoToAppSettting() {
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setTitle("权限不可用")
                .setMessage("请在-应用设置-权限-中,允许该权限!")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // 跳转到应用设置界面
                        goToAppSetting();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).setCancelable(false).show();
    }

    /**
     * 跳转到应用设置界面
     */
    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);
    }


    public void callPhone() {
        Toast.makeText(this, "执行操作", Toast.LENGTH_SHORT).show();
    }
}

申请多个权限

public class MuiltPermissionActivity extends AppCompatActivity {

    private static final int REQUESET_PERMISSIONS_CODE = 1;

    //需要申请权限的集合
    private List<String> mPermissionList = new ArrayList<>();

    private String[] permissions = {
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.WRITE_EXTERNAL_STORAGE

    };

    private String[] permStr = {
            "需要读取联系人权限",
            "需要读取内存卡权限"

    };

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

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            checkPermissions();
        } else {
            doBackup();
        }
    }

    private void checkPermissions() {
        mPermissionList.removeAll(mPermissionList);
        for (int i = 0; i < permissions.length; i++) {
            if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
                mPermissionList.add(permissions[i]);
            }
        }

        if (mPermissionList.isEmpty()) { //未授予的权限为空,表示权限都授予了
            //可以直接执行相关操作
            doBackup();
        } else {
            //申请权限
            String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);//将List转为数组
            ActivityCompat.requestPermissions(this, permissions, REQUESET_PERMISSIONS_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == REQUESET_PERMISSIONS_CODE) {

            boolean isAllGranted = true; //权限是否全部授予

            for (int i = 0; i < grantResults.length; i++) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { //拒绝
                    isAllGranted = false;

                    if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
                            permissions[i])) { //点击了不再提醒,提示用户去应用设置界面手动开启权限
                        showDialogTipUserGoToAppSettting(permStr[i]);
                    } else {
                        showPermissionReason(new String[]{permissions[i]}, permStr[i]);
                    }
                }
            }

            //权限全部授予了,执行操作
            if (isAllGranted) {
                doBackup();
            }
        }
    }

    private void showPermissionReason(final String[] permission, String s) {
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setTitle("提示")
                .setMessage(s)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        if (ContextCompat.checkSelfPermission(MuiltPermissionActivity.this, permission[0])
                                != PackageManager.PERMISSION_GRANTED) { //没有授予权限
                            ActivityCompat.requestPermissions(MuiltPermissionActivity.this, permission, REQUESET_PERMISSIONS_CODE);
                        }
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).setCancelable(false).show();
    }

    private void showDialogTipUserGoToAppSettting(String s) {
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setTitle(s)
                .setMessage("请在-应用设置-权限-中,允许该权限!")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // 跳转到应用设置界面
                        goToAppSetting();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).setCancelable(false).show();
    }

    /**
     * 跳转到应用设置界面
     */
    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);
    }

    private void doBackup() {
        // 本文主旨是讲解如果动态申请权限, 具体备份代码不再展示, 就假装备份一下
        Toast.makeText(this, "正在备份通讯录...", Toast.LENGTH_SHORT).show();
    }
}

PermissionUtils:动态申请权限工具类

/**
 * 动态申请权限工具类
 * Created by xiaoyehai on 2018/4/25 0025.
 */

public class PermissionUtils {

    public static final int GOTO_SEETING_CODE = 152;

    /**
     * 判断是否有权限
     *
     * @param context
     * @param perms
     * @return
     */
    public static boolean hasPermissions(@NonNull Context context, @Size(min = 1) @NonNull String... perms) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true;
        }

        if (context == null) {
            throw new IllegalArgumentException("Can't check permissions for null context");
        }

        for (String perm : perms) {
            if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }


    /**
     * 申请权限
     *
     */
    public static void requestPermissions(@NonNull Activity activity, int requestCode, String[] permissions) {

        List<String> permissionList = new ArrayList<>();
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
                permissionList.add(permission);
            }
        }

        String[] permissionsArray = permissionList.toArray(new String[permissionList.size()]);//将List转为数组
        if (permissionList.isEmpty()) {
            //不可能为空
        } else {
            ActivityCompat.requestPermissions(activity, permissionsArray, requestCode);
            //返回结果onRequestPermissionsResult
        }
    }


    /**
     * 申请权限的回调
     *
     * @param requestCode  请求权限时传入的请求码,用于区别是哪一次请求的
     * @param permissions  所请求的所有权限的数组
     * @param grantResults 权限授予结果,和 permissions 数组参数中的权限一一对应,元素值为两种情况,如下:
     *                     授予: PackageManager.PERMISSION_GRANTED
     *                     拒绝: PackageManager.PERMISSION_DENIED
     */
    public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                                  @NonNull int[] grantResults, @NonNull PermissionCallbacks callBack) {
        //授予的权限。
        List<String> granted = new ArrayList<>();

        //拒绝的权限
        List<String> denied = new ArrayList<>();


        for (int i = 0; i < permissions.length; i++) {
            String perm = permissions[i];
            if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                granted.add(perm);
            } else {
                denied.add(perm);
            }
        }

        if (null != callBack) {
            if (denied.isEmpty()) {
                callBack.onPermissionsAllGranted(requestCode, granted, denied.isEmpty());
            }

            if (!denied.isEmpty()) {
                callBack.onPermissionsDenied(requestCode, denied);
            }
        }
    }

    /**
     * 用户是否拒绝权限,并检查“不要提醒”。
     *
     * @param activity
     * @param perms
     * @return
     */
    public static boolean somePermissionPermanentlyDenied(Activity activity, @NonNull List<String> perms) {
        for (String deniedPermission : perms) {
            if (permissionPermanentlyDenied(activity, deniedPermission)) {
                return true;
            }
        }

        return false;
    }

    public static boolean permissionPermanentlyDenied(Activity activity, @NonNull String perms) {
        if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, perms)) {
            return true;
        }
        return false;
    }


    public static void showDialogGoToAppSettting(final Activity activity) {
        AlertDialog dialog = new AlertDialog.Builder(activity)
                .setMessage("去设置界面开启权限")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // 跳转到应用设置界面
                        goToAppSetting(activity);
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).setCancelable(false).show();
    }


    /**
     * 跳转到应用设置界面
     */
    public static void goToAppSetting(Activity activity) {
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
        intent.setData(uri);
        activity.startActivityForResult(intent, GOTO_SEETING_CODE);
    }

    public static void showPermissionReason(final int requestCode, final Activity activity, final String[] permission, String s) {
        AlertDialog dialog = new AlertDialog.Builder(activity)
                .setMessage(s)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        requestPermissions(activity, requestCode, permission);
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).setCancelable(false).show();
    }


    public interface PermissionCallbacks {

        /**
         * @param isAllGranted 是否全部同意
         */
        void onPermissionsAllGranted(int requestCode, List<String> perms, boolean isAllGranted);

        /**
         */
        void onPermissionsDenied(int requestCode, List<String> perms);

    }
}

使用

public class PermissionUtilsActivity extends AppCompatActivity implements PermissionUtils.PermissionCallbacks {

    private static final int REQUESET_PERMISSIONS_CODE = 1;

    private String[] permissions = {Manifest.permission.CALL_PHONE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE};

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

        if (PermissionUtils.hasPermissions(this, permissions)) {
            doSomething();
        } else {
            PermissionUtils.requestPermissions(this, REQUESET_PERMISSIONS_CODE, permissions);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        //把申请权限的回调交由PermissionUtils处理
        PermissionUtils.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    @Override
    public void onPermissionsAllGranted(int requestCode, List<String> perms, boolean isAllGranted) {
        //全部授予
        if (isAllGranted) {
            doSomething();
        }
    }

    //拒绝权限的回调
    @Override
    public void onPermissionsDenied(int requestCode, List<String> perms) {

        //一些权限拒绝了并且点击了不再提醒,去设置界面手动打开权限
        if (PermissionUtils.somePermissionPermanentlyDenied(this, perms)) {
            PermissionUtils.showDialogGoToAppSettting(this);
        } else {
            //一些权限拒绝了没有点击了不再提醒,弹出框提示申请权限原因
            PermissionUtils.showPermissionReason(requestCode, this, permissions, "该功能需要拨打电话和读取本地内存权限,是否开启?");
        }
    }

    public void doSomething() {
        Toast.makeText(this, "执行相关操作", Toast.LENGTH_SHORT).show();
    }

}

   @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        //从设置界面返回
        if (requestCode == PermissionUtils.GOTO_SEETING_CODE) {
            if (!PermissionUtils.hasPermissions(this, permissions)) {
                PermissionUtils.requestPermissions(this, REQUEST_PERMISSION_CODE, permissions);
            }
        }
    }

第三方开源控件

EasyPermissions

github地址

dependencies {
    implementation 'pub.devrel:easypermissions:1.3.0'
}

申请一个权限

public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks,
                                                               EasyPermissions.RationaleCallbacks{

    private static final String TAG = "MainActivity";
   
    private static final int RC_CAMERA_PERM = 123;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //申请一个权限
        findViewById(R.id.button_camera).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                cameraTask();
            }
        });
    }

    private boolean hasCameraPermission() {
        return EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA);
    }

//使用了该注解,当权限请求被用户同意后,会根据请求code来执行,相应的含有@AfterPermissionGranted注解的方法。不需要在EasyPermissions.onRequestPermissionsResult()的回调监听器中请求成功的方法中,再次手动调用,获取权限后需要操作的逻辑代码
    @AfterPermissionGranted(RC_CAMERA_PERM)
    public void cameraTask() {
        if (hasCameraPermission()) {
            // 有权限,执行相关操作
           Toast.makeText(this, "执行操作", Toast.LENGTH_SHORT).show();
        } else {
            // 申请权限
             /**
             * 第一个参数:Context对象
             * 第二个参数:权限弹窗上的文字提示语。告诉用户,这个权限用途。
             * 第三个参数:这次请求权限的唯一标示,code。
             * 第四个参数 : 一些系列的权限。
             */
            EasyPermissions.requestPermissions(
                    this,
                    getString(R.string.rationale_camera),
                    RC_CAMERA_PERM,
                    Manifest.permission.CAMERA);
        }
    }



    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

         //把申请权限的回调交由EasyPermissions处理
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

	//某些权限已被授予
    @Override
    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
        Toast.makeText(this, "执行操作", Toast.LENGTH_SHORT).show();
    }

	//某些权限已被拒绝
    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
        Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size());

        //(可选)检查用户是否拒绝任何权限,并检查“不要再问”。
        //这将显示一个对话框,引导他们在应用程序设置中启用权限。
         if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
            new AppSettingsDialog.Builder(this).setRationale("去设置界面开启权限").setTitle("提示").build().show();
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {
           
          // 在用户从应用程序设置屏幕返回后做一些事情,比如展示Toast。
           
        }
    }

    @Override
    public void onRationaleAccepted(int requestCode) {
        Log.d(TAG, "onRationaleAccepted:" + requestCode);
    }

    @Override
    public void onRationaleDenied(int requestCode) {
        Log.d(TAG, "onRationaleDenied:" + requestCode);
    }
}

申请多个权限

public class EasypermissionsActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks {

    private static final String TAG = "EasypermissionsActivity";

    private static final String[] LOCATION_AND_CONTACTS =
            {Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_CONTACTS};

    private static final int RC_LOCATION_CONTACTS_PERM = 124;


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

        //申请多个权限
        findViewById(R.id.button_location_and_contacts).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                locationAndContactsTask();
            }
        });
    }

    @AfterPermissionGranted(RC_LOCATION_CONTACTS_PERM)
    public void locationAndContactsTask() {
        if (hasLocationAndContactsPermissions()) {
            Toast.makeText(this, "执行操作", Toast.LENGTH_LONG).show();
        } else {
            EasyPermissions.requestPermissions(
                    this,
                    getString(R.string.rationale_location_contacts),
                    RC_LOCATION_CONTACTS_PERM,
                    LOCATION_AND_CONTACTS);
        }
    }

    private boolean hasLocationAndContactsPermissions() {
        return EasyPermissions.hasPermissions(this, LOCATION_AND_CONTACTS);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        //把申请权限的回调交由EasyPermissions处理
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }


    /**
     * 某些权限已被授予
     *
     * @param requestCode
     * @param perms       授权成功的权限
     */
    @Override
    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
        //权限全部同意
        if (perms.size() == LOCATION_AND_CONTACTS.length) {
            Toast.makeText(this, "执行操作", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 某些权限已被拒绝
     *
     * @param requestCode
     * @param perms
     */
    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
        //(可选)检查用户是否拒绝任何权限,并检查“不要再问”。
        //这将显示一个对话框,引导他们在应用程序设置中启用权限。
        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
            new AppSettingsDialog.Builder(this).setRationale("去设置界面开启权限").setTitle("提示").build().show();
        }
    }

    @Override
    public void onRationaleAccepted(int requestCode) {
        Toast.makeText(this, "onRationaleAccepted", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onRationaleDenied(int requestCode) {
        Toast.makeText(this, "onRationaleDenied", Toast.LENGTH_SHORT).show();
    }
}

@AfterPermissionGranted注解:

@AfterPermissionGranted注解为了提供方便,但可以添加也可以不添加,是可选的。

好处:

使用了该注解,当权限请求被用户同意后,会根据请求code来执行,相应的含有@AfterPermissionGranted注解的方法。

简化了请求成功操作流程,不需要在EasyPermissions.onRequestPermissionsResult()的回调监听器中请求成功的方法中,再次手动调用,获取权限后需要操作的逻辑代码。

RxPermissions

AndPermission

PermissionsDispatcher

2019-12-31 18:31:50 qq_24542767 阅读数 41
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12940 人正在学习 去看看 CSDN讲师

示例:获取读写权限

1、同样需要在清单文件里面配置

   <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>

2、然后再动态申请 

 //申请权限
    public void applyPermission() {
        //判断是否已经赋予权限
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {
            //用户是否上次拒绝权限申请(第二次打开)
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.WRITE_CONTACTS)) {
                //用户已经拒绝过一次,需要提示用户去设置里面授权
                Log.e("AddressBook", "用户上次拒绝权限申请");
            } else {
               //申请权限,定义数组会一次申请多个权限
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS}, 100);
            }
        } else {
            Log.e("AddressBook", "还没有赋予权限");
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 100) {
            for (int i = 0; i < permissions.length; i++) {
                if (grantResults[i] == PERMISSION_GRANTED) {
                    Log.e("AddressBook", "权限" + permissions[i] + "申请成功");
                } else {
                    Log.e("AddressBook", "权限" + permissions[i] + "申请失败");
                }
            }
        }
    }

 

2017-05-04 09:47:08 weixin_37730482 阅读数 3156
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12940 人正在学习 去看看 CSDN讲师

1.Android 权限简介

自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装的事情,也不会再不征求用户授权的情况下,就可以任意的访问用户隐私,而且即使在授权之后也可以及时的更改权限。这就是6.0版本做出的更拥护和注重用户的一大体现。

 

 

 

2.Android 权限级别

 

Android6.0系统把权限分为两个级别:

 

一类是Normal Permissions,即普通权限,这类权限不会潜藏有侵害用户隐私和安全的问题,比如,访问网络的权限,访问WIFI的权限等。

 

一类是Dangerous Permissions,即危险权限,这类权限会直接的威胁到用户的安全和隐私问题,比如说访问短信,相册等权限,地理位置权限。

 

2.1.Normal Permissions (普通权限 举例)

 

  • ACCESS_LOCATION_EXTRA_COMMANDS
  • ACCESS_NETWORK_STATE
  • ACCESS_NOTIFICATION_POLICY
  • ACCESS_WIFI_STATE
  • BLUETOOTH
  • BLUETOOTH_ADMIN
  • BROADCAST_STICKY
  • CHANGE_NETWORK_STATE
  • CHANGE_WIFI_MULTICAST_STATE
  • CHANGE_WIFI_STATE
  • DISABLE_KEYGUARD
  • EXPAND_STATUS_BAR
  • GET_PACKAGE_SIZE
  • INSTALL_SHORTCUT
  • INTERNET
  • KILL_BACKGROUND_PROCESSES
  • MODIFY_AUDIO_SETTINGS
  • NFC
  • READ_SYNC_SETTINGS
  • READ_SYNC_STATS
  • RECEIVE_BOOT_COMPLETED
  • REORDER_TASKS
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
  • REQUEST_INSTALL_PACKAGES
  • SET_ALARM
  • SET_TIME_ZONE
  • SET_WALLPAPER
  • SET_WALLPAPER_HINTS
  • TRANSMIT_IR
  • UNINSTALL_SHORTCUT
  • USE_FINGERPRINT
  • VIBRATE
  • WAKE_LOCK
  • WRITE_SYNC_SETTINGS

 

使用以上权限是不会威胁到用户安全的,所以这类权限是可以直接的在manifest里面直接的使用,而且在安装后也会直接的生效了。

 

 

2.2.Dangerous Permissions (危险权限 举例)

 

 

  • SMS(短信)
    • SEND_SMS
    • RECEIVE_SMS
    • READ_SMS
    • RECEIVE_WAP_PUSH
    • RECEIVE_MMS
  • STORAGE(存储卡)
    • READ_EXTERNAL_STORAGE
    • WRITE_EXTERNAL_STORAGE
  • CONTACTS(联系人)
    • READ_CONTACTS
    • WRITE_CONTACTS
    • GET_ACCOUNTS
  • PHONE(手机)
    • READ_PHONE_STATE
    • CALL_PHONE
    • READ_CALL_LOG
    • WRITE_CALL_LOG
    • ADD_VOICEMAIL
    • USE_SIP
    • PROCESS_OUTGOING_CALLS
  • CALENDAR(日历)
    • READ_CALENDAR
    • WRITE_CALENDAR
  • CAMERA(相机)
    • CAMERA
  • LOCATION(位置)
    • ACCESS_FINE_LOCATION
    • ACCESS_COARSE_LOCATION
  • SENSORS(传感器)
    • BODY_SENSORS
  • MICROPHONE(麦克风)
    • 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


  
存储卡
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
  

 

联系人

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.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION  



传感器
group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS
  
  

 

麦克风
group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO

 

危险权限包含:传感器、日历、摄像头、通讯录、地理位置、麦克风、电话、短信、存储空间,具体见下图:


  

危险权限和普通权限也有区别,普通权限是单条的权限,而危险权限是以组展示的,也就是说,当你接受一个危险权限时,不但但接受的是界面上展示的这一个权限,而是它所在这个组里面的其他所有访问权限也将会被自动获取权限,比如,一旦WRITE_CONTACTS被授权了,App也有READ_CONTACTS和GET_ACCOUNTS的权限了。
值得注意的是,这类权限也是需要在manifest中注册的。

 

注意:同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS了。

 


3.举例说明

 

3.1.获取当前设备手机联系人

 

Android 6.0以下

 

测试设备

 

清单文件

 

 

java 代码

 /**
         * 获取当前设备联系人信息
         * 1.从raw_contacts中读取联系人的id("contact_id")
         * 2.根据contact_id从data表中查询出相应的电话号码和联系人名称
         * 3.根据mimetype来区分哪个是联系人,哪个是电话号码
         * */

        private ArrayList<HashMap<String, String>> readContact () {
            Uri rawContactsUri = Uri.parse("content://com.android.contacts/raw_contacts");
            Uri dataUri = Uri.parse("content://com.android.contacts/data");
            ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
            //从raw_contacts中读取联系人的id("contact_id")
            Cursor rawContactsCursor = getContentResolver().query(rawContactsUri, new String[]{"contact_id"}, null, null, null);
            if (rawContactsCursor != null) {
                while (rawContactsCursor.moveToNext()) {
                    String contactId = rawContactsCursor.getString(0);
//根据contact_id从data表中查询出相应的电话号码和联系人名称, 实际上查询的是视图view_data
                    Cursor dataCursor = getContentResolver().query(dataUri,
                            new String[]{"data1", "mimetype"}, "contact_id=?",
                            new String[]{contactId}, null);
                    if (dataCursor != null) {
                        HashMap<String, String> map = new HashMap<String, String>();
                        while (dataCursor.moveToNext()) {
                            String data1 = dataCursor.getString(0);
                            String mimetype = dataCursor.getString(1);
                            if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
                                map.put("phone", data1);
                            } else if ("vnd.android.cursor.item/name".equals(mimetype)) {
                                map.put("name", data1);
                            }
                        }
                        list.add(map);
                        dataCursor.close();
                    }
                }
                rawContactsCursor.close();
            }
            return list;
        }


        button = (Button) findViewById(R.id.permissions_btn);
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                ArrayList<HashMap<String, String>> list = readContact();
                int count = list.size();
                StringBuilder sb = new StringBuilder();
                sb.append("当前设备联系人数:" + count + "\n\n\n");
                for (int i = 0; i < count; i++) {
                    HashMap<String, String> map = list.get(i);
                    String name = map.get("name");
                    String phone = map.get("phone");
                    sb.append("姓名:" + name + "     手机号:" + phone + "\n\n\n");
                }
                String result = sb.toString();
                tv.setText(result);
            }
        });

 

结果

 

 

 

 

 

当清单文件中

 

即目标版本号是6.0以上(23为6.0)时 结果还是如上图(测试设备一样)

 

总结

当运行app的当前设备Android系统版本<23时,不管我们的targetSdkVersion 值是否大于23,都不会影响我们在manifest里面申请的权限。即在清单文件中配置了相应的权限就可以使用。

 

由上面的几条结论,我们应该很清晰的知道了访问权限在真机中的使用状况,但是我们的手机在升级,版本也会越来越高,因此我们现在的应用不可能一直只支持低版本的使用也不考虑兼顾高版本。所以现在APP权限升级是必然的趋势。那么现在回来解决上面遗留的问题,当真机和目标版本都大于6.0时出现的权限异常我们该怎么解决呢?

 

主要分为三个步骤:

1:检查是否拥有权限

2:假如没有权限,则申请权限

3:处理权限回调

 

检查是否拥有权限

 

检查是否已拥有了权限,可以使用ContextCompat.checkSelfPermission(Context context, String permission);

checkSelfPermission方法中有两个参数,分别是上下文,以及所申请的权限。

 

申请权限

申请权限则是使用:

public static void requestPermissions(final Activity activity,final String[] permissions, final int requestCode) {}

requestPermissions方法中需要三个参数,当前的activity,所申请的权限,可以是多个,最后就是请求码,既然有请求码说明它会有一个回调,也就是我们下面要讲的处理回调。

 

处理权限回调

处理权限回调,需要在Activity中重写onRequestPermissionsResult方法:

 

注意:

要用23 版本以上的V4包。在23以下版本的V4包中并没有这几个方法。

  • ActivityCompat.checkSelfPermission()
  • ActivityCompat.requestPermissions()
  • ActivityCompat.OnRequestPermissionsResultCallback
  • ActivityCompat.shouldShowRequestPermissionRationale()

 

 

 

3.2.Android 6.0及以上相机存储位置权限使用

 

1.清单文件

<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />

<!-- 存储卡 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<!-- 允许应用访问手机状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

 

2.常量类

 /**
  * Android 6.0及以上申请权限
* */

public static final String permission1="android.permission.READ_EXTERNAL_STORAGE";
public static final String permission2="android.permission.WRITE_EXTERNAL_STORAGE";
public static final String permission3="android.permission.CAMERA";
public static final String [] permission=new String[]{permission1,permission2,permission3};//敏感权限

 

3.工具类

/**
 * Created by wjn on 2017/11/28.
 * Android 6.0及以上权限工具类
 */

public class AndroidPermissionUtils {

    /**
     * Android 6.0及以上 检测是否具有某些权限
     * */

    public static boolean hasAndroidPermission(Context context, String [] permission){
        boolean has=true;
        for(String per:permission){
            if(ContextCompat.checkSelfPermission(context,per) != PackageManager.PERMISSION_GRANTED){
                has=false;
                break;
            }
        }
        return has;
    }

    /**
     * Android 6.0及以上 申请某些权限
     * */

    public static void requestAndroidPermission(Activity activity, int code, String []permission){
        ActivityCompat.requestPermissions(activity,permission,code);
    }

}

 

4.使用以及回调

/**
     * Android 6.0系统及以上申请敏感权限方法
     * */

    private void requestAndroidPermission(){
        if(FileHelper.isSdCardExist()){
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){//6.0
                boolean has= AndroidPermissionUtils.hasAndroidPermission(SetUpActivity.this, DataConstant.permission);
                if(!has){//6.0及以上 没有权限
                    AndroidPermissionUtils.requestAndroidPermission(SetUpActivity.this,0,DataConstant.permission);
                }else{//6.0及以上 有权限 操作文件
                    loadNewVersion();
                }
            }else{//6.0以下 操作文件
                loadNewVersion();
            }
        }else{
            toast.showToast(StringConstant.Filestatus2);
        }
    }

    /**
     * onRequestPermissionsResult 动态申请回调方法
     * */

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(grantResults.length > 0 && !(grantResults[0] == PackageManager.PERMISSION_GRANTED)){
            showDialogs("温馨提示",StringConstant.errorstate6);
        }
    }

 

2019-07-11 09:22:54 The_Only_God 阅读数 41
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12940 人正在学习 去看看 CSDN讲师

文章目录

电话

//动态申请电话权限
if(ContextCompat.checkSelfPermission(LoginActivity.this, Manifest.permission.CALL_PHONE)
        != PackageManager.PERMISSION_GRANTED){
    ActivityCompat.requestPermissions(LoginActivity.this,new String[]{Manifest.permission.CALL_PHONE},1);
}

Android动态权限申请

阅读数 1316

没有更多推荐了,返回首页