概述

在安卓6.0曾经,安卓使用的权限会在装置阶段向用户展现。可是在使用使用的阶段不需求再请求任何权限。

而在6.0今后,一般股权限只需求在清单文件里注册即可,可是风险权限,则除了注册在清单里之外,还需求在使用app时动态请求。

权限分类

一般权限

在程序运行时自动获取,只需求在清单文件里声明即可。比方 internet。

风险权限

App在一些操作中需求拜访用户的隐私信息,比方图库,通讯录。此刻安卓体系就会向用户展现所需的权限。

完好的权限请求流程

图示

三十二、关于动态权限请求的必备常识

解释说明

    1. 判别sdk版别是否低于23,假如是,则不需求请求权限,流程结束。不然往下。
    1. 调用checkPermission 判别 权限是否已请求成功,假如回来true,流程结束。不然往下。
    1. 调用requestPermission 向体系自动发送请求权限的操作。

可是在 requestPermission 之前,有一个 shouldShowRequestPermissionRationale 的判别

关键的 shouldShowRequestPermissionRationale

  • 此判别假如回来了 true,则说明,之前app现已测验请求过权限,可是用户点击了回绝,可是并没有选择 Never ask again(今后不再提示).

这表明,用户没有永久回绝权限,app还能再次调用 requestPermission测验请求。

  • 假如回来了 false, 有两种状况:
    • app从来没有请求过此权限
      • 此刻,只需求 再次调用 requestPermission测验请求
    • app请求过此权限,可是被用户回绝,并且勾选了 Never ask again(永久回绝)
      • 此刻,只能弹出自定义对话框,提示用户此操作有必要具备权限之后才干持续,并且在点击某个按钮之后进入到 app的权限办理页面。

特别留意,以上回来true的状况,在某些国产手机上被屏蔽,比方华为,小米,也就是说,这些手机上动态请求权限,只有两种状况,允许 ,或许永久回绝, 不存在介于两者中间的 暂时回绝的选项。

规范代码示范

一般,我们需求按照 activity.requestPermissions() 传入 permissions权限数组,以及 requestCode回调码,然后在Activity内进行回调处理。

可是现在有了更优雅的方式,支撑我们在 恣意代码的位置,不限定activity内,支撑fragment,service,乃至一个一般类内进行处理。

基本思想为: 开启一个通明不行见的Activity作为请求权限的载体,请求的动作,以及 请求后的回调 全部放在此Activity内。首要代码如下:

权限请求成果接口


/**
 * 权限请求成果接口
 */
public interface IPermissionCallback {
    /**
     * 颁发权限
     */
    void granted(int requestCode);
    /**
     * 这次回绝,可是并没有勾选"今后不再提示"
     */
    void denied(int requestCode);
    /**
     * 勾选"今后不再提示",并且回绝
     */
    void deniedForever(int requestCode);
}

权限基本功能类

public class PermissionUtil {
    /**
     * 判别一切权限是否都赞同了,都赞同回来true 不然回来false
     *
     * @param context     context
     * @param permissions permission list
     * @return return true if all permissions granted else false
     */
    public static boolean hasSelfPermissions(Context context, String... permissions) {
        for (String permission : permissions) {
            if (!hasSelfPermission(context, permission)) {
                return false;
            }
        }
        return true;
    }
    /**
     * 判别单个权限是否赞同
     *
     * @param context    context
     * @param permission permission
     * @return return true if permission granted
     */
    private static boolean hasSelfPermission(Context context, String permission) {
        return ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
    }
    /**
     * 查看是否都赋予权限
     *
     * @param grantResults grantResults
     * @return 一切都赞同回来true 不然回来false
     */
    public static boolean verifyPermissions(int... grantResults) {
        if (grantResults.length == 0) return false;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }
    /**
     * 查看所给权限List是否需求给提示
     *
     * @param activity    Activity
     * @param permissions 权限list
     * @return 假如某个权限需求提示则回来true
     */
    public static boolean shouldShowRequestPermissionRationale(Activity activity, String... permissions) {
        for (String permission : permissions) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                return true;
            }
        }
        return false;
    }
}

权限请求核心类,仅有入口

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import org.jetbrains.annotations.Nullable;
public class PermissionAspectActivity extends Activity {
    private final static String permissionsTag = "permissions";
    private final static String requestCodeTag = "requestCode";
    private static IPermissionCallback mCallback;
    /**
     * 发动当时这个Activity
     */
    public static void startActivity(Context context, String[] permissions, int requestCode, IPermissionCallback callback) {
        Log.d("PermissionAspectTag", "context is : " + context.getClass().getSimpleName());
        if (context == null) return;
        mCallback = callback;
        //发动当时这个Activity并且取消切换动画
        Intent intent = new Intent(context, PermissionAspectActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);//开启新的任务栈并且铲除栈顶...为何要铲除栈顶
        intent.putExtra(permissionsTag, permissions);
        intent.putExtra(requestCodeTag, requestCode);
        context.startActivity(intent);//利用context发动activity
        if (context instanceof Activity) {//并且,假如是activity发动的,那么还要屏蔽掉activity切换动画
            ((Activity) context).overridePendingTransition(0, 0);
        }
    }
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        String[] permissions = intent.getStringArrayExtra(permissionsTag);
        int requestCode = intent.getIntExtra(requestCodeTag, 0);
        if (PermissionUtil.hasSelfPermissions(this, permissions)) {
            mCallback.granted(requestCode);
            finish();
            overridePendingTransition(0, 0);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(permissions, requestCode);
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        // 现在拿到了权限的请求成果,那么如何处理,我这个Activity仅仅为了请求,然后把成果告诉外界,所以成果的处理只能是外界传进来
        boolean granted = PermissionUtil.verifyPermissions(grantResults);
        if (granted) {//假如用户给了权限
            mCallback.granted(requestCode);
        } else {
            if (PermissionUtil.shouldShowRequestPermissionRationale(this, permissions)) { // 判别是否还能持续请求
                mCallback.denied(requestCode);
            } else { // 不能再次请求,用户现已彻底回绝
                mCallback.deniedForever(requestCode);
            }
        }
        this.finish();
        overridePendingTransition(0, 0);
    }
}

留意,此 PermissionAspectActivity 有必要在清单文件中注册

三十二、关于动态权限请求的必备常识

并且它的风格是通明的:

三十二、关于动态权限请求的必备常识

作用如下,恣意类中都能使用权限请求:

三十二、关于动态权限请求的必备常识