转载请标明出处:【顾林海的博客】

个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持!


前言

我们知道在Android中想要申请权限就需要在AndroidManifest配置文件中通过uses-permission标签设置申请的权限,通过这种方式申请权限固然方便,但在安全性方面却不高,比如开发者申请获取用户隐私的权限,这样用户在不知情的情况下获取到了用户的隐私,如何避免这种不安全的权限获取?从Android 6.0开始,Google将权限分为两类,分别是默认权限(Normal Permission)和危险权限(Dangerous Permission),默认权限在程序安装时授权,但危险权限需要用户在运行APP时手动授权,这里使用EasyPermissions库来简化运行时权限的操作。

EasyPermissions使用

/** * 权限管理类 * * @author glh */public abstract class BasePermissionsActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestPermissions(this);    }    public void requestPermissions(Context context) {        String[] perms = {Manifest.permission.CAMERA,                Manifest.permission.WRITE_EXTERNAL_STORAGE,                Manifest.permission.READ_PHONE_STATE};        if (!EasyPermissions.hasPermissions(context, perms)) {            EasyPermissions.requestPermissions((Activity) context, context.getResources().getString(R.string.camera_rationale),                    124, perms);        }    }    @Override    public void onPermissionsGranted(int requestCode, List perms) {        ToastUtils.showToast(this, "用户授权成功");    }    @Override    public void onPermissionsDenied(int requestCode, List perms) {        /*         * 若是在权限弹窗中,用户勾选了'NEVER ASK AGAIN.'或者'不在提示',且拒绝权限。         * 这时候,需要跳转到设置界面去,让用户手动开启。         */        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {            new AppSettingsDialog                    .Builder(this)                    .setTitle("\"某APP\"权限提示")                    .setRationale("\"某APP\"需要使用相关权限,是否打开设置")                    .setPositiveButton("是")                    .setNegativeButton("否")                    .build()                    .show();        }    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        switch (requestCode) {            //当从软件设置界面,返回当前程序时候            case AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE:                requestPermissions(this);                break;        }    }    @AfterPermissionGranted(value = 0x99)    public void checkPermissions() {        String[] perms = {Manifest.permission.CAMERA, Manifest.permission.CHANGE_WIFI_STATE};        if (EasyPermissions.hasPermissions(this, perms)) {            //已经授权后的操作        } else {            //没有授权后的操作            EasyPermissions.requestPermissions(this, getString(R.string.camera_rationale),                    0x99, perms);        }    }}

使用EasyPermissions时,需要实现它的PermissionCallbacks接口,这个接口提供了三个方法,其中onPermissionsGranted方法是授权成功后的回调,onPermissionsDenied方法是授权失败的回调,onRequestPermissionsResult方法是android.support.v4.app的ActivityCompat中的公共接口,当我们进行权限的请求时onRequestPermissionsResult方法会返回相应的请求结果,通过这个权限回调,可以对相应的操作做出响应。

EasyPermissions提供了hasPermissions方法,第二个参数传入的是一个权限数组,该方法会判断APP是否对这些权限进行过授权,如果其中有一个权限并没有被授权,最终结果会返回false,这时可以通过EasyPermissions的requestPermissions方法进行权限授权,其中requestCode是请求码,可以根据对应的请求码在授权回调中进行相应的处理,第三个可变参数就是我们需要授权的相关权限。具体的权限回调处理上面只是给出一个模板,具体的操作还是根据相关业务场景来调整。

EasyPermissions还提供了注解形式来处理授权后对应的requestCode处理,具体使用如下:

    @AfterPermissionGranted(value = 0x99)    public void checkPermissions() {        String[] perms = {Manifest.permission.CAMERA, Manifest.permission.CHANGE_WIFI_STATE};        if (EasyPermissions.hasPermissions(this, perms)) {            //已经授权后的操作        } else {            //没有授权后的操作            EasyPermissions.requestPermissions(this, getString(R.string.camera_rationale),                    0x99, perms);        }    }

源码解析

    public static boolean hasPermissions(Context context, @NonNull String... perms) {        //Android版本判断        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {            Log.w(TAG, "hasPermissions: API version < M, returning true by default");            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;    }

hasPermissions方法比较简单,先是对Android版本进行判断,小于Android 6.0的版本直接检查通过,只有大于Android 6.0时才会对权限列表进行检查,这里使用了ContextCompat的checkSelfPermissions方法进行权限检查,检查的结果不为0说明未授权。

在Android源码中,权限的检查最终会调用到 ContextImp中的checkPermission方法,源码如下:

    @Override    public int checkPermission(String permission, int pid, int uid) {        if (permission == null) {            throw new IllegalArgumentException("permission is null");        }        try {            return ActivityManagerNative.getDefault().checkPermission(                    permission, pid, uid);        } catch (RemoteException e) {            return PackageManager.PERMISSION_DENIED;        }    }

在ContextImp中的checkPermission方法中,调用了ActivityManagerNative的getDefault()方法来获取ActivityManagerService的对象。ActivityManagerService 的职责是管理着应用程序中创建的所有组件(Activity、Service等),实现组件的管理,每个组件的状态变化都需要通知AMS,组件间的跨进程通信(IPC)是由ActivityManagerService 来操作的。

ActivityManagerNative中的getDefault方法如下:

    static public IActivityManager getDefault() {        return gDefault.get();    }        private static final Singleton gDefault = new Singleton() {        protected IActivityManager create() {            IBinder b = ServiceManager.getService("activity");            if (false) {                Log.v("ActivityManager", "default service binder = " + b);            }            IActivityManager am = asInterface(b);            if (false) {                Log.v("ActivityManager", "default service = " + am);            }            return am;        }};        static public IActivityManager asInterface(IBinder obj) {        if (obj == null) {            return null;            }        IActivityManager in =                (IActivityManager) obj.queryLocalInterface(descriptor);        if (in != null) {            return in;        }        return new ActivityManagerProxy(obj);    }

在上面的create方法中通过ServiceManager.getService(“activity”)获取到ActivityManagerService对象,ActivityManagerService继承了 ActivityManagerNative,而 ActivityManagerNative继承了Binder并实现了IActivityManager接口,因此ActivityManagerService也是一个Binder对象,在asInterface方法中创建远程代理ActvityManagerProxy对象,经过一系列调用,最终调用ActivityManagerService的checkPermission方法。

    int checkComponentPermission(String permission, int pid, int uid,                                 int owningUid, boolean exported) {        // We might be performing an operation on behalf of an indirect binder        // invocation, e.g. via {@link #openContentUri}.  Check and adjust the        // client identity accordingly before proceeding.        Identity tlsIdentity = sCallerIdentity.get();        if (tlsIdentity != null) {            Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"                    + tlsIdentity.pid + "," + tlsIdentity.uid + "}");            uid = tlsIdentity.uid;            pid = tlsIdentity.pid;        }        if (pid == MY_PID) {            return PackageManager.PERMISSION_GRANTED;        }        return ActivityManager.checkComponentPermission(permission, uid,                owningUid, exported); // 调用ActivityManager的checkComponentPermission来检查权限    }    @Override    public int checkPermission(String permission, int pid, int uid) {        if (permission == null) {            return PackageManager.PERMISSION_DENIED;        }        // 调用checkComponentPermission函数来检查权限        return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);    }

调用ActivityManager的checkComponentPermission方法:

    ./base/core/java/android/app/ActivityManager.java    public static int checkComponentPermission(String permission, int uid,                                               int owningUid, boolean exported) {    ........        try {            // 调用AppGlobals的getPackageManager()函数返回IPackageManager对象            return AppGlobals.getPackageManager()                    .checkUidPermission(permission, uid);        } catch (RemoteException e) {            // Should never happen, but if it does... deny!            Slog.e(TAG, "PackageManager is dead?!?", e);        }        return PackageManager.PERMISSION_DENIED;    }
    ./base/core/java/android/app/AppGlobals.java    public static IPackageManager getPackageManager() {        return ActivityThread.getPackageManager(); // 调用ActivityThread的getPackageManager()函数    }
    ./base/core/java/android/app/ActivityThread.java    public static IPackageManager getPackageManager() {        if (sPackageManager != null) {            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);            return sPackageManager;        }        IBinder b = ServiceManager.getService("package");        //Slog.v("PackageManager", "default service binder = " + b);        sPackageManager = IPackageManager.Stub.asInterface(b);        //Slog.v("PackageManager", "default service = " + sPackageManager);        return sPackageManager;    }

AppGlobals的getPackageManager方法中,通过ActivityThread的getPackageManager方法获取PackageManageService对象。
接着通过PackageManageService的checkUidPermission方法来检查权限。

    ./base/services/core/java/com/android/server/pm/PackageManagerService.java    @Override    public int checkUidPermission(String permName, int uid) {        synchronized (mPackages) {            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));            if (obj != null) {                GrantedPermissions gp = (GrantedPermissions) obj;                if (gp.grantedPermissions.contains(permName)) {                    return PackageManager.PERMISSION_GRANTED;                }            } else {                HashSet perms = mSystemPermissions.get(uid);                if ( perms != null &;&;                perms.contains(permName)){                    return PackageManager.PERMISSION_GRANTED;                }            }        }        return PackageManager.PERMISSION_DENIED;    }

PackageManageService的checkUidPermission方法中,通过Settings的getUserIdLPr方法根据UID获取权限列表获,如果存在授权的权限返回PackageManager.PERMISSION_GRANTED,表示授权成功。

hasPermissions方法算是分析完毕了,这里在分析该方法的同时也梳理了权限检查的流程。

在分析EasyPermissions的requestPermissions方法前,先介绍一下几个重要的辅助类。

PermissionHelper是一个抽象类(模板方法),内部定义了几个抽象方法:

@RestrictTo(RestrictTo.Scope.LIBRARY)public abstract class PermissionHelper {        .....    public abstract void directRequestPermissions(int requestCode, @NonNull String... perms);    public abstract boolean shouldShowRequestPermissionRationale(@NonNull String perm);    public abstract void showRequestPermissionRationale(@NonNull String rationale,                                                        @StringRes int positiveButton,                                                        @StringRes int negativeButton,                                                        int requestCode,                                                        @NonNull String... perms);    public abstract Context getContext();}

shouldShowRequestPermissionRationale方法:如果应用之前请求过此权限但用户拒绝了请求,并在权限请求系统对话框中没有选择了 Don’t ask again 选项,此方法将返回 true。如果用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了 Don’t ask again 选项,此方法将返回 false。如果设备规范禁止应用具有该权限,此方法也会返回 false。

directRequestPermissions方法:进行权限请求。

showRequestPermissionRationale方法:显示权限弹框,具体逻辑有子类实现。

getContext方法:获取对应的上下文。

很显然PermissionHelper是权限操作的抽象类,具体实现由子类来实现,请求权限时,可以在Activity、android.support.v4.app.Fragment或是android.app.Fragment中执行请求,PermissionHelper提供了创建这几种情况下的实现类。

@NonNullpublic static PermissionHelper newInstance(Activity host) {    if (Build.VERSION.SDK_INT < 23) {        return new LowApiPermissionsHelper(host);    }    return new ActivityPermissionHelper(host);}@NonNullpublic static PermissionHelper newInstance(Fragment host) {    if (Build.VERSION.SDK_INT < 23) {        return new LowApiPermissionsHelper(host);    }    return new SupportFragmentPermissionHelper(host);}@NonNullpublic static PermissionHelper newInstance(android.app.Fragment host) {    if (Build.VERSION.SDK_INT < 23) {        return new LowApiPermissionsHelper(host);    }    return new FrameworkFragmentPermissionHelper(host);}

如果权限授权在小于Android 6.0的版本时,会创建LowApiPermissionsHelper对象,LowApiPermissionsHelper实现了PermissionHelper的几个抽象方法。

class LowApiPermissionsHelper extends PermissionHelper {    public LowApiPermissionsHelper(@NonNull Object host) {        super(host);    }    @Override    public void directRequestPermissions(int requestCode, @NonNull String... perms) {        throw new IllegalStateException("Should never be requesting permissions on API < 23!");    }    @Override    public boolean shouldShowRequestPermissionRationale(@NonNull String perm) {        return false;    }    @Override    @SuppressLint("NewApi")    public void showRequestPermissionRationale(@NonNull String rationale,                                               int positiveButton,                                               int negativeButton,                                               int requestCode,                                               @NonNull String... perms) {        throw new IllegalStateException("Should never be requesting permissions on API < 23!");    }    @Override    public Context getContext() {        return null;    }}   

LowApiPermissionsHelper的几个方法都是空的,这是因为在API小于23时,不需要对运行时权限做处理。

ActivityPermissionHelper和FrameworkFragmentPermissionHelper针对的是在android.app包的Actvity和Fragment。

ActivityPermissionHelper:

class ActivityPermissionHelper extends BaseFrameworkPermissionsHelper {    public ActivityPermissionHelper(Activity host) {        super(host);    }    @Override    @SuppressLint("NewApi")    public FragmentManager getFragmentManager() {        return getHost().getFragmentManager();    }    @Override    public void directRequestPermissions(int requestCode, @NonNull String... perms) {        ActivityCompat.requestPermissions(getHost(), perms, requestCode);    }    @Override    public boolean shouldShowRequestPermissionRationale(@NonNull String perm) {        return ActivityCompat.shouldShowRequestPermissionRationale(getHost(), perm);    }    @Override    public Context getContext() {        return getHost();    }}

FrameworkFragmentPermissionHelper:

class FrameworkFragmentPermissionHelper extends BaseFrameworkPermissionsHelper {    public FrameworkFragmentPermissionHelper(@NonNull Fragment host) {        super(host);    }    @Override    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)    public FragmentManager getFragmentManager() {        return getHost().getChildFragmentManager();    }    @Override    @SuppressLint("NewApi")    public void directRequestPermissions(int requestCode, @NonNull String... perms) {        getHost().requestPermissions(perms, requestCode);    }    @Override    @SuppressLint("NewApi")    public boolean shouldShowRequestPermissionRationale(@NonNull String perm) {        return getHost().shouldShowRequestPermissionRationale(perm);    }    @Override    @SuppressLint("NewApi")    public Context getContext() {        return getHost().getActivity();    }}

ActivityPermissionHelper和FrameworkFragmentPermissionHelper实现逻辑都差不多,在Activity中请求权限会通过ActivityCompat的requestPermissions方法进行请求,在Fragment中会通过Fragment的requestPermissions方法进行权限请求。并且这两个Helper类都继承了BaseFrameworkPermissionsHelper类。

    public abstract class BaseFrameworkPermissionsHelper extends PermissionHelper {        public BaseFrameworkPermissionsHelper(@NonNull T host) {            super(host);        }        public abstract FragmentManager getFragmentManager();        @Override        @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)        public void showRequestPermissionRationale(@NonNull String rationale,                                                   int positiveButton,                                                   int negativeButton,                                                   int requestCode,                                                   @NonNull String... perms) {            RationaleDialogFragment                    .newInstance(positiveButton, negativeButton, rationale, requestCode, perms)                    .show(getFragmentManager(), RationaleDialogFragment.TAG);        }    }

BaseFrameworkPermissionsHelper类非常简单,就两个方法,其中一个抽象方法getFragmentManager获取FragmentManager对象,还有一个实现了PermissionHelper类中的抽象方法showRequestPermissionRationale,showRequestPermissionRationale方法会显示一个权限弹框。
具体的子类实现在PermissionHelper中已经介绍过,继续看support.v4.app包的下Fragment的权限操作(SupportFragmentPermissionHelper)。

 class SupportFragmentPermissionHelper extends BaseSupportPermissionsHelper {        public SupportFragmentPermissionHelper(@NonNull Fragment host) {            super(host);        }        @Override        public FragmentManager getSupportFragmentManager() {            return getHost().getChildFragmentManager();        }        @Override        public void directRequestPermissions(int requestCode, @NonNull String... perms) {            getHost().requestPermissions(perms, requestCode);        }        @Override        public boolean shouldShowRequestPermissionRationale(@NonNull String perm) {            return getHost().shouldShowRequestPermissionRationale(perm);        }        @Override        public Context getContext() {            return getHost().getActivity();        }    }

SupportFragmentPermissionHelper的逻辑与之前两个Helper类一样,不需要再介绍了。

继续分析requestPermissions方法,EasyPermissions提供了多个requestPermissions方法:

    public static void requestPermissions(            @NonNull Activity host, @NonNull String rationale,            int requestCode, @NonNull String... perms) {        requestPermissions(host, rationale, android.R.string.ok, android.R.string.cancel,                requestCode, perms);    }    public static void requestPermissions(            @NonNull Fragment host, @NonNull String rationale,            int requestCode, @NonNull String... perms) {        requestPermissions(host, rationale, android.R.string.ok, android.R.string.cancel,                requestCode, perms);    }    public static void requestPermissions(            @NonNull android.app.Fragment host, @NonNull String rationale,            int requestCode, @NonNull String... perms) {        requestPermissions(host, rationale, android.R.string.ok, android.R.string.cancel,                requestCode, perms);    }

这个三个requestPermissions方法应该很熟悉了,权限弹框按钮的文案是默认的,要想设置权限弹框的文案,可以调用以下三种requestPermissions方法。

    public static void requestPermissions(            @NonNull Activity host, @NonNull String rationale,            @StringRes int positiveButton, @StringRes int negativeButton,            int requestCode, @NonNull String... perms) {        requestPermissions(PermissionHelper.newInstance(host), rationale,                positiveButton, negativeButton,                requestCode, perms);    }    public static void requestPermissions(            @NonNull Fragment host, @NonNull String rationale,            @StringRes int positiveButton, @StringRes int negativeButton,            int requestCode, @NonNull String... perms) {        requestPermissions(PermissionHelper.newInstance(host), rationale,                positiveButton, negativeButton,                requestCode, perms);    }    public static void requestPermissions(            @NonNull android.app.Fragment host, @NonNull String rationale,            @StringRes int positiveButton, @StringRes int negativeButton,            int requestCode, @NonNull String... perms) {        requestPermissions(PermissionHelper.newInstance(host), rationale,                positiveButton, negativeButton,                requestCode, perms);    }

通过一系列调用,最后都是都用以下方法:

    private static void requestPermissions(            @NonNull PermissionHelper helper, @NonNull String rationale,            @StringRes int positiveButton, @StringRes int negativeButton,            int requestCode, @NonNull String... perms) {        //进行权限检查        if (hasPermissions(helper.getContext(), perms)) {            notifyAlreadyHasPermissions(helper.getHost(), requestCode, perms);            return;        }        //请求权限        helper.requestPermissions(rationale, positiveButton,                negativeButton, requestCode, perms);    }

方法第一个参数PermissionHelper就是前三个requestPermissions方法针对app包和suppor包下的Activity和Fragment权限操作类,也就是前面提到的那几个Helper类。在请求权限之前会检查之前权限有没有授权过,如果授权过调用notifyAlreadyHasPermissions方法。

    private static void notifyAlreadyHasPermissions(@NonNull Object object,                                                    int requestCode,                                                    @NonNull String[] perms) {        int[] grantResults = new int[perms.length];        for (int i = 0; i < perms.length; i++) {            grantResults[i] = PackageManager.PERMISSION_GRANTED;        }        onRequestPermissionsResult(requestCode, perms, grantResults, object);    }

notifyAlreadyHasPermissions方法非常简单,授权成功后将 grantResults 数组全部赋值未PackageManager.PERMISSION_GRANTED,再通过onRequestPermissionsResult方法将结果回调给客户端。继续看requestPermissions方法中的helper.requestPermissions方法,该方法就是调用app和support下Activity和Fragment的
shouldShowRequestPermissionRationale方法,该方法就是Android进行权限授权的方法,当进行授权操作后会回调onRequestPermissionsResult方法。如下:

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

拿到授权结果后通过EasyPermissions的onRequestPermissionsResult方法进行结果回调,onRequestPermissionsResult方法如下。

    public static void onRequestPermissionsResult(int requestCode,                                                  @NonNull String[] permissions,                                                  @NonNull int[] grantResults,                                                  @NonNull Object... receivers) {        //授权成功        List granted = new ArrayList<>();        //授权失败或没授权        List 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);        }        for (Object object : receivers) {            // 授权成功            if (!granted.isEmpty()) {                if (object instanceof EasyPermissions.PermissionCallbacks) {                    ((EasyPermissions.PermissionCallbacks) object).onPermissionsGranted(requestCode, granted);                }            }            //未授权            if (!denied.isEmpty()) {                if (object instanceof EasyPermissions.PermissionCallbacks) {                    ((EasyPermissions.PermissionCallbacks) object).onPermissionsDenied(requestCode, denied);                }            }            //全部授权通过             if (!granted.isEmpty() && denied.isEmpty()) {                runAnnotatedMethods(object, requestCode);            }        }    }

方法中granted集合用于保存授权成功的权限,denied集合保存的是未授权或授权失败的权限,接着通过循环遍历权限请求类,对授权成功和未成功集合做判断,如果granted集合不为空说明授权成功,会回调onPermissionsGranted方法,如果denied集合不为空,说明有权限未授权成功,会回调onPermissionsDenied方法,当然如果granted集合不为空并且denied集合为空,说明百分百之一百授权成功,这时调用runAnnotatedMethods方法。

    private static void runAnnotatedMethods(@NonNull Object object, int requestCode) {        Class clazz = object.getClass();        if (isUsingAndroidAnnotations(object)) {            clazz = clazz.getSuperclass();        }        while (clazz != null) {            //遍历请求权限类中的方法            for (Method method : clazz.getDeclaredMethods()) {                //判断是否使用了AfterPermissionGranted注解                if (method.isAnnotationPresent(AfterPermissionGranted.class)) {                    AfterPermissionGranted ann = method.getAnnotation(AfterPermissionGranted.class);                    if (ann.value() == requestCode) {                        //无参方法                        if (method.getParameterTypes().length > 0) {                            throw new RuntimeException(                                    "Cannot execute method " + method.getName() + " because it is non-void method and/or has input parameters.");                        }                        try {                            // Make method accessible if private                            if (!method.isAccessible()) {                                method.setAccessible(true);                            }                            //反射调用AfterPermissionGranted注解的方法                            method.invoke(object);                        } catch (IllegalAccessException e) {                            Log.e(TAG, "runDefaultMethod:IllegalAccessException", e);                        } catch (InvocationTargetException e) {                            Log.e(TAG, "runDefaultMethod:InvocationTargetException", e);                        }                    }                                   }            }            //获取父类的Class            clazz = clazz.getSuperclass();        }    }

该方法主要对AfterPermissionGranted注解的方法进行处理,通过遍历请求权限类的方法,如果是通过AfterPermissionGranted注解的方法并且是无参的,通过请求的requestCode与该注解方法的value一样,就通过反射执行该方法,告之请求类权限请求成功。这里稍微提下,一开始会执行isUsingAndroidAnnotations方法进行判断是否获取直接继承父类的class,isUsingAndroidAnnotations方法如下:

    private static boolean isUsingAndroidAnnotations(@NonNull Object object) {        if (!object.getClass().getSimpleName().endsWith("_")) {            return false;        }        try {            Class clazz = Class.forName("org.androidannotations.api.view.HasViews");            return clazz.isInstance(object);        } catch (ClassNotFoundException e) {            return false;        }    }

其实这个方法也就是判断是否使用了 AndroidAnnotations这个注解框架,关于这个框架大家可以自行网上搜索。

之前看了onRequestPermissionsResult方法,也就是授权后的结果回调,现在看下权限请求的逻辑。

//请求权限    helper.requestPermissions(rationale, positiveButton,            negativeButton, requestCode, perms);

调用了PermissionHelper的requestPermissions方法。

    public boolean shouldShowRationale(@NonNull String... perms){        for (String perm:perms){            // 上次弹出权限点击了禁止(但没有勾选“下次不在询问”)            if(shouldShowRequestPermissionRationale(perm)){                return true;            }        }        //第一次打开App时或者上次选择禁止并勾选“下次不在询问”        return false;    }    public void requestPermissions(@NonNull String rationale,                                   @StringRes int positiveButton,                                   @StringRes int negativeButton,                                   int requestCode,                                   @NonNull String... perms){        if(shouldShowRationale(perms)){            // 上次弹出权限点击了禁止(但没有勾选“下次不在询问”)            showRequestPermissionRationale(rationale,                    positiveButton,                    negativeButton,                    requestCode,                    perms);        }else{            //第一次打开App时或者上次选择禁止并勾选“下次不在询问”            //进行权限请求            directRequestPermissions(requestCode,perms);        }    }

requestPermissions方法中,当上次弹出权限点击了禁止(但没有勾选“下次不在询问”),这时需要弹出权限弹框,当第一次打开App时或者上次选择禁止并勾选“下次不在询问”,这时进行权限请求。shouldShowRequestPermissionRationale、showRequestPermissionRationale和directRequestPermissions都是抽象方法,具体实现由子类实现,关于这三个方法在上面已经介绍过了。
结合上面的一系列分析,权限请求后,通过回调onPermissionsGranted和onPermissionsDenied方法告之请求类请求结果,比如当我们选择禁止并勾选“下次不在询问”时,这时请求授权失败,回调onPermissionsDenied方法:

    @Override    public void onPermissionsDenied(int requestCode, List perms) {        /**         * 若是在权限弹窗中,用户勾选了'NEVER ASK AGAIN.'或者'不在提示',且拒绝权限。         * 这时候,需要跳转到设置界面去,让用户手动开启。         */        if(requestCode==124) {            if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {                new AppSettingsDialog                        .Builder(this)                        .setTitle("\"火链财经\"权限提示")                        .setRationale("\"火链财经\"需要使用相关权限,是否打开设置")                        .setPositiveButton("是")                        .setNegativeButton("否")                        .build()                        .show();            } else {                requestPermissions(this);            }        }    }

可以针对具体业务进行操作,就像上面若是在权限弹窗中,用户勾选了’NEVER ASK AGAIN.‘或者’不在提示’,且拒绝权限。 这时候,需要跳转到设置界面去,让用户手动开启。否则再次请求授权。
到这里EasyPermissions分析分析完毕。

更多相关文章

  1. Android(安卓)系统权限
  2. Objective-C与JavaScript交互的那些事
  3. android中关于使用scrollview嵌套LinearLayout,页面滚动条不到底
  4. android外部存储读写权限问题
  5. 第一篇技术贴(Android(安卓)WebView)
  6. Android学习路线总结
  7. Android:剖析源码,随心所欲控制Toast显示
  8. 从AIDL开始谈Android进程间Binder通信机制
  9. Android之异步任务加载网络数据

随机推荐

  1. 想抢先体验Android操作系统的魅力吗?那就
  2. Android的Activity切换动画特效库SwitchL
  3. Android(安卓)AIDL Service调试方法
  4. android 跳转到横屏activity出现之前acti
  5. 【android开发】Android(安卓)2.2版本的
  6. 当 PC 开始运行 Android……
  7. Android(安卓)apk数字签名总结
  8. Android开发指南-框架主题-资源和资产
  9. 话语收集
  10. 一个Android登陆/注册XML布局文件代码