Android动态权限封装(基于AspectJ的注解检查)

    网上有很多关于动态权限检查的开源库,使用方式呢都大同小异。之前也做过一个动态权限检查的功能,通过注解的形式来进行检查,现在把思路做个分享。

1.使用到的开源库

    1.    AOP思想的AspectJ (面向切面思想的解决方案)

    2.    EasyPermissions 开源库 (动态权限检查库)

    AOP是Aspect Oriented Programming的缩写,即『面向切面编程』。它和我们平时接触到的OOP都是编程的不同思想,OOP,即『面向对象编程』,它提倡的是将功能模块化,对象化,而AOP的思想,则不太一样,它提倡的是针对同一类问题的统一处理。AspectJ实际上是对AOP编程思想的一个实践。我们可以利用AspectJ,把用来修饰方法的注解作为一个切点,在执行该方法时,触发该切点所对应的逻辑。

AspectJ的使用:https://blog.csdn.net/eclipsexys/article/details/54425414 (大家可以通过此链接了解一下aspectj的使用)

    EasyPermissions呢,时一个动态权限检查的开源库,大大简化了Android端对动态权限问题的代码编写。其实其他的开源库也一样可以实现我的思路,在此用EasyPermissions作为一个例子。

EasyPermissions   github地址:https://github.com/jiezongnewstar/easypermissions

2.直接上代码吧

首先,创建注解PermissionCheck,Target为修饰方法,Retention为运行时,其中设置一个成员变量,以用来传入需要检查的权限信息。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionCheck {
    public String[] checkString();
}

另外我们需要创建一个被@Aspect修饰的类来对PermissionCheck注解做切点,以及切入后的逻辑编写。类中比如@Pointcut

@Around等注解的用法等,可以参考上面的链接,对AspectJ的使用熟悉熟悉。@Pointcut,就是设置一个切入点。类中的意思就是被PermissionCheck的注解所修饰的方法作为一个切点。@Around,就是在执行被PermissionCheck注解修饰的方法时,进入切点,并执行check方法。

@Aspect
public class PermissionCheckAspectJ {
    private static final String TAG = "PermissionCheck";

    @Pointcut("execution(@com.sound.base.aspectj.PermissionCheck * *(..)) && @annotation(ann)")
    public void checkPermission(PermissionCheck ann) {

    }

    @Around("checkPermission(permissioncheck)")
    public Object check(ProceedingJoinPoint joinPoint, PermissionCheck permissioncheck) throws Throwable {
        
        return joinPoint.proceed();
    }
}

    好,接下来我们就需要编写check方法,来对注解所传过来的权限进行检查。

    首先就是对参数做个判空,以保证代码完整性与安全性,try catch也是必要的。由于EasyPermissions的api的使用需要上下文参数,所以必须先通过joinPoint.getThis()来获取到当前方法所在的类实例中。由于切点既有可能在Activity中,也有可能在Fragment中,所以我们要对joinPoint.getThis()做个区分,通过不同方式获取到context。

@Around("checkPermission(permissioncheck)")
    public Object check(ProceedingJoinPoint joinPoint, PermissionCheck permissioncheck) throws Throwable {
        if (null != permissioncheck) {
            Context context = null;
            try {
                if (joinPoint.getThis() instanceof android.support.v4.app.Fragment) {
                    System.out.println("Fragment");
                    android.support.v4.app.Fragment fragment = (android.support.v4.app.Fragment) joinPoint.getThis();
                    context = fragment.getActivity();
                } else {
                    context = (Context) joinPoint.getThis();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
        return joinPoint.proceed();
    }

    接下来就需要调用EasyPermissions的api来进行权限的检查。看代码即可。

@Around("checkPermission(permissioncheck)")
    public Object check(ProceedingJoinPoint joinPoint, PermissionCheck permissioncheck) throws Throwable {
        if (null != permissioncheck) {
            Context context = null;
            try {
                if (joinPoint.getThis() instanceof android.support.v4.app.Fragment) {
                    android.support.v4.app.Fragment fragment = (android.support.v4.app.Fragment) joinPoint.getThis();
                    context = fragment.getActivity();
                } else {
                    context = (Context) joinPoint.getThis();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (null != context) {
                String[] checkStrings = permissioncheck.checkString();
                int code = PermissionCode.getCode(checkStrings);
                String string = PermissionCode.getInfo(checkStrings);
                if (EasyPermissions.hasPermissions(context, checkStrings)) {
                    return joinPoint.proceed();
                } else {
                    if (joinPoint.getThis() instanceof Activity) {
                        Activity activity = (Activity) joinPoint.getThis();
                        EasyPermissions.requestPermissions(activity, string, code, checkStrings);
                    } else if (joinPoint.getThis() instanceof android.support.v4.app.Fragment) {
                        Fragment fragment = (android.support.v4.app.Fragment) joinPoint.getThis();
                        EasyPermissions.requestPermissions(fragment, string, code, checkStrings);
                    }
                    return null;
                }
            }
        }
        return joinPoint.proceed();
    }

    代码的意思就是,如果检查当前是拥有对应权限的,则执行joinPoint.proceed()方法来让注解修饰了的方法继续执行下去。如果说并没有对应权限,则会打开权限请求的弹框,通知用户去分配权限,return null 让方法不继续执行下去。


    这两个编写好后,最重要的代码基本就编写完成了,为了更加方便使用,我们可以通过编写BaseActivity和BaseFragment来更加简化我们的使用。

base代码中的onRequestPermissionResult中调用EasyPermissions的api,并实现EasyPermissions的两个方法。

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

        // Forward results to EasyPermissions
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }
base页面实现PermissionCallbacks,并实现对应的两个方法,在方法中调用我们自己编写的抽象方法,暴露给子类页面去使用。
public abstract class BaseActivity extends NetObserverAppCompatActivity implements EasyPermissions.PermissionCallbacks {
public abstract void permissionSuccess(int requestCode, List perms);

    public abstract void permissionFaild(int requestCode, List perms);

    @Override
    public void onPermissionsGranted(int requestCode, List perms) {
        permissionSuccess(requestCode, perms);
    }

    @Override
    public void onPermissionsDenied(int requestCode, List perms) {
        permissionFaild(requestCode, perms);
    }

那么,代码就编写完成了,我们可以看下如何使用了。

比如我们要打开相机拍照并获取照片,则需要相机权限,存储的读写权限。

首先,可以创建一个cameraPermission的方法,用来调用打开相机。然后用PermissionCheck注解设置我们所需要检查的权限。

@PermissionCheck(checkString = {PermissionCode.CAMERA_PERMISSION, PermissionCode.WRITE_EXTERNAL_STORAGE_PERMISSION, PermissionCode.READ_EXTERNAL_STORAGE_PERMISSION})
    public void cameraPermission() {
        CameraUtils.getInstance().openAlbum(this);
    }

然后去实现base中的两个抽象方法

@Override
    public void permissionSuccess(int requestCode, List perms) {
        cameraPermission();
    }

    @Override
    public void permissionFaild(int requestCode, List perms) {
        Toast.makeText(this, "用户已拒绝相机权限", Toast.LENGTH_SHORT).show();
    }

当用户给与了权限之后,就会调用到permissionSuccess方法,从而打开了相机。当用户拒绝了权限请求,就会弹出对应吐司来提示用户。

这些都编写完成之后,那么就可以调用方法了。

} else if (i == R.id.check_camera_permission_button) {
            cameraPermission();
        } else if (i == R.id.arouter_jump_activity) {

我们只需要调用cameraPermission()就ok了,所有的权限检查等等就在上面的编写过程中一一处理了,还是比较方便的。这样代码也相对比较整洁。

希望能给大家带来一些帮助,谢谢。


你可能感兴趣的:(Android动态权限封装(基于AspectJ的注解检查))