Aop实现6.0权限检查

初学Aop 之前一直想写权限检查的工具 github上也有一些,但是本着学习的目的 还是自己写下

基本逻辑是aop 知道方法啥时候执行 在方法执行之前 通过注解拿到需要判断的权限 进行 权限判断 为了处理判断结果 启动一个透明的activity进行 权限申请操作 处理权限申请回调

aop的引入 

如果是在主项目下进行比较简单

//app的build.gradle 下
dependencies {
    implementation 'org.aspectj:aspectjrt:1.8.9'
}
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.9'
    }
}

repositories {
    mavenCentral()
}

final def log = project.logger
final def variants = project.android.applicationVariants

variants.all { variant ->
    if (!variant.buildType.isDebuggable()) {
        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return;
    }

    JavaCompile javaCompile = variant.javaCompile
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.5",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)

        MessageHandler handler = new MessageHandler(true);
        new Main().run(args, handler);
        for (IMessage message : handler.getMessages(null, true)) {
            switch (message.getKind()) {
                case IMessage.ABORT:
                case IMessage.ERROR:
                case IMessage.FAIL:
                    log.error message.message, message.thrown
                    break;
                case IMessage.WARNING:
                    log.warn message.message, message.thrown
                    break;
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break;
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break;
            }
        }
    }
}

如果是在module下 配置 除了module要进行配置 主项目也要添加上面dependencies之后的代码

module 配置如下

dependencies {
    api 'org.aspectj:aspectjrt:1.8.9'
}
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.9'
//        classpath 'org.aspectj:aspectjweaver:1.8.13'
    }
}

repositories {
    mavenCentral()
}

android.libraryVariants.all { variant ->
    JavaCompile javaCompile = variant.javaCompile
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.5",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", android.bootClasspath.join(
                File.pathSeparator)]

        MessageHandler handler = new MessageHandler(true)
        new Main().run(args, handler)

        def log = project.logger
        for (IMessage message : handler.getMessages(null, true)) {
            switch (message.getKind()) {
                case IMessage.ABORT:
                case IMessage.ERROR:
                case IMessage.FAIL:
                    log.error message.message, message.thrown
                    break
                case IMessage.WARNING:
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break
            }
        }
    }
}

第一步

创建权限检查注解 PermissionCheck

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

第二步

创建aop Aspect类进行逻辑处理

@Aspect
public class PermissionAspect {
    @Pointcut("execution(@com.example.aoplibrary.PermissionCheck * *(..))")
    public void pointCut() {
    }

    @Around("pointCut()")
    public void aroundMethod(final ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] permissions = methodSignature.getMethod().getAnnotation(PermissionCheck.class).permissions();
        final Object o = joinPoint.getThis();
        Context context = null;
        if (o instanceof Context) {
            context = (Context) o;
        } else if (o instanceof Fragment) {
            context = ((Fragment) o).getActivity();
        } else if (o instanceof android.app.Fragment) {
            context = ((android.app.Fragment) o).getActivity();
        }
        if (context == null) return;
        if (permissions.length == 0) {
            joinPoint.proceed();
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            List<String> permissionList = new ArrayList<>();
            for (String permission : permissions) {
                if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                    permissionList.add(permission);
                }
            }
            if (permissionList.isEmpty()) {
                joinPoint.proceed();
                return;
            }
            String[] noPassPermission = permissionList.toArray(new String[permissionList.size()]);
            final Context finalContext = context;
            PermissionActivity.requestPermission(context, noPassPermission, new PermissionActivity.onRequestPermissionListener() {
                @Override
                public void onRequestPermissionsPass() {
                    try {
                        joinPoint.proceed();
                    } catch (Throwable throwable) {
                        throwable.printStackTrace();
                    }
                }

                @Override
                public void onRequestPermissionsDenied(String[] deniedPermissions, String[] cancelPermissions) {
                    if (deniedPermissions.length == 0) {
                        return;
                    }
                    Method[] declaredMethods = o.getClass().getDeclaredMethods();
                    boolean hasMethod = false;
                    for (Method method : declaredMethods) {
                        if (method.isAnnotationPresent(PermissionDenied.class)) {
                            try {
                                method.setAccessible(true);
                                method.invoke(o, deniedPermissions);
                                hasMethod = true;
                                break;
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    for (Method method : declaredMethods) {
                        if (method.isAnnotationPresent(PermissionCanceled.class)) {
                            try {
                                method.setAccessible(true);
                                method.invoke(o, cancelPermissions);
                                break;
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    if (!hasMethod) {
                        PermissionActivity.showPermissionDialog(finalContext, deniedPermissions);
                    }
                }
            });

        } else {
            joinPoint.proceed();
        }
    }
}

其中代码很简单 就是过去获取上下文context 进行权限判断 包括Android版本判断 如果没有权限 就调用PermissionActivity.requestPermission进行权限检查

代码如下

public class PermissionActivity extends AppCompatActivity {
    private static String[] sPermissions;
    private static boolean sIsRequest;
    private static WeakReference<onRequestPermissionListener> sListener;
    public static int CODE_PERMISSIONS = 1011;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (sIsRequest) {
            ActivityCompat.requestPermissions(this, sPermissions, CODE_PERMISSIONS);
        } else {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("缺少必要权限");
            StringBuilder stringBuffer = new StringBuilder();
            for (String permission : sPermissions) {
                stringBuffer.append(permission).append(" ");
            }
            builder.setMessage(stringBuffer.toString());
            builder.setCancelable(false);
            builder.setPositiveButton("去设置", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    new PermissionPageUtil().jumpPermissionPage(PermissionActivity.this);
                    finish();
                }
            });
            builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();
                }
            });
            AlertDialog dialog = builder.create();
            dialog.show();

        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == CODE_PERMISSIONS) {
            if (sListener != null && sListener.get() != null) {
                List<String> canceledPermissions = new ArrayList<>();
                List<String> deniedPermissions = new ArrayList<>();
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        boolean isCanceled = ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i]);
                        if (isCanceled) {
                            canceledPermissions.add(permissions[i]);
                        } else {
                            deniedPermissions.add(permissions[i]);
                        }
                    }
                }
                if (canceledPermissions.isEmpty() && deniedPermissions.isEmpty()) {
                    sListener.get().onRequestPermissionsPass();
                } else {
                    sListener.get().onRequestPermissionsDenied(deniedPermissions.toArray(new String[deniedPermissions.size()]), canceledPermissions.toArray(new String[canceledPermissions.size()]));
                }
            }
            finish();
        }
    }

    public static void requestPermission(Context context, String[] permissions, onRequestPermissionListener listener) {
        Intent intent = new Intent(context, PermissionActivity.class);
        context.startActivity(intent);
        sIsRequest = true;
        sPermissions = permissions;
        sListener = new WeakReference<>(listener);

    }

    public static void showPermissionDialog(Context context, String[] permissions) {
        sIsRequest = false;
        sPermissions = permissions;
        Intent intent = new Intent(context, PermissionActivity.class);
        context.startActivity(intent);
    }

    public interface onRequestPermissionListener {
        void onRequestPermissionsPass();

        void onRequestPermissionsDenied(String[] deniedPermissions, String[] cancelPermissions);
    }
}

启动一个透明的activity 进行权限申请 处理申请结果 接口回调结果进行处理 在PermissionAspect中处理接口回调的结果 此处有两个注解 一个PermissionCanceled

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionCanceled {
}

这个注解是处理权限被取消并且没有点击取消后不再提示 PermissionAspect处理结果 拿到目标页面的方法判断有没有被这个注解注解过后的方法 如果有 反射执行这个方法

还有一个注解是PermissionDenied
 

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionDenied {
}

处理逻辑和上面基本一样 只是如果没有该方法 这边做了一个处理 是跳转到设置界面 引导用户去开启权限代码 开启设置代码如下

public class PermissionPageUtil {
    private Context mContext;
    //自己的项目包名
    private String packageName="";

    public void jumpPermissionPage(Context context) {
        this.mContext = context;
        packageName = context.getPackageName();
        String name = Build.MANUFACTURER;
        switch (name) {
            case "HUAWEI":
                goHuaWeiMainager();
                break;
            case "vivo":
                goVivoMainager();
                break;
            case "OPPO":
                goOppoMainager();
                break;
            case "Coolpad":
                goCoolpadMainager();
                break;
            case "Meizu":
                goMeizuMainager();
                break;
            case "Xiaomi":
                goXiaoMiMainager();
                break;
            case "samsung":
                goSangXinMainager();
                break;
            case "Sony":
                goSonyMainager();
                break;
            case "LG":
                goLGMainager();
                break;
            default:
                goIntentSetting();
                break;
        }
    }

    private void goLGMainager(){
        try {
            Intent intent = new Intent(packageName);
            ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$AccessLockSummaryActivity");
            intent.setComponent(comp);
            mContext.startActivity(intent);
        } catch (Exception e) {
            Toast.makeText(mContext, "跳转失败", Toast.LENGTH_LONG).show();
            e.printStackTrace();
            goIntentSetting();
        }
    }
    private void goSonyMainager(){
        try {
            Intent intent = new Intent(packageName);
            ComponentName comp = new ComponentName("com.sonymobile.cta", "com.sonymobile.cta.SomcCTAMainActivity");
            intent.setComponent(comp);
            mContext.startActivity(intent);
        } catch (Exception e) {
            Toast.makeText(mContext, "跳转失败", Toast.LENGTH_LONG).show();
            e.printStackTrace();
            goIntentSetting();
        }
    }

    private void goHuaWeiMainager() {
        try {
            Intent intent = new Intent(packageName);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");
            intent.setComponent(comp);
            mContext.startActivity(intent);
        } catch (Exception e) {
            Toast.makeText(mContext, "跳转失败", Toast.LENGTH_LONG).show();
            e.printStackTrace();
            goIntentSetting();
        }
    }

    private static String getMiuiVersion() {
        String propName = "ro.miui.ui.version.name";
        String line;
        BufferedReader input = null;
        try {
            Process p = Runtime.getRuntime().exec("getprop " + propName);
            input = new BufferedReader(
                    new InputStreamReader(p.getInputStream()), 1024);
            line = input.readLine();
            input.close();
        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        } finally {
            try {
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return line;
    }

    private void goXiaoMiMainager() {
        String rom = getMiuiVersion();
        Intent intent=new Intent();
        if ("V6".equals(rom) || "V7".equals(rom)) {
            intent.setAction("miui.intent.action.APP_PERM_EDITOR");
            intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
            intent.putExtra("extra_pkgname", packageName);
        } else if ("V8".equals(rom) || "V9".equals(rom)) {
            intent.setAction("miui.intent.action.APP_PERM_EDITOR");
            intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
            intent.putExtra("extra_pkgname", packageName);
        } else {
            goIntentSetting();
        }
        mContext.startActivity(intent);
    }

    private void goMeizuMainager() {
        try {
            Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.putExtra("packageName", packageName);
            mContext.startActivity(intent);
        } catch (ActivityNotFoundException localActivityNotFoundException) {
            localActivityNotFoundException.printStackTrace();
            goIntentSetting();
        }
    }

    private void goSangXinMainager() {
        //三星4.3可以直接跳转
        goIntentSetting();
    }

    private void goIntentSetting() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", mContext.getPackageName(), null);
        intent.setData(uri);
        try {
            mContext.startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void goOppoMainager() {
        doStartApplicationWithPackageName("com.coloros.safecenter");
    }

    /**
     * doStartApplicationWithPackageName("com.yulong.android.security:remote")
     * 和Intent open = getPackageManager().getLaunchIntentForPackage("com.yulong.android.security:remote");
     * startActivity(open);
     * 本质上没有什么区别,通过Intent open...打开比调用doStartApplicationWithPackageName方法更快,也是android本身提供的方法
     */
    private void goCoolpadMainager() {
        doStartApplicationWithPackageName("com.yulong.android.security:remote");
      /*  Intent openQQ = getPackageManager().getLaunchIntentForPackage("com.yulong.android.security:remote");
        startActivity(openQQ);*/
    }

    private void goVivoMainager() {
        doStartApplicationWithPackageName("com.bairenkeji.icaller");
     /*   Intent openQQ = getPackageManager().getLaunchIntentForPackage("com.vivo.securedaemonservice");
        startActivity(openQQ);*/
    }

    /**
     * 此方法在手机各个机型设置中已经失效
     *
     * @return
     */
    private Intent getAppDetailSettingIntent() {
        Intent localIntent = new Intent();
        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= 9) {
            localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
            localIntent.setData(Uri.fromParts("package", mContext.getPackageName(), null));
        } else if (Build.VERSION.SDK_INT <= 8) {
            localIntent.setAction(Intent.ACTION_VIEW);
            localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
            localIntent.putExtra("com.android.settings.ApplicationPkgName", mContext.getPackageName());
        }
        return localIntent;
    }

    private void doStartApplicationWithPackageName(String packagename) {
        // 通过包名获取此APP详细信息,包括Activities、services、versioncode、name等等
        PackageInfo packageinfo = null;
        try {
            packageinfo = mContext.getPackageManager().getPackageInfo(packagename, 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        if (packageinfo == null) {
            return;
        }
        // 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
        Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
        resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        resolveIntent.setPackage(packageinfo.packageName);
        // 通过getPackageManager()的queryIntentActivities方法遍历
        List<ResolveInfo> resolveinfoList = mContext.getPackageManager()
                .queryIntentActivities(resolveIntent, 0);
        Log.e("PermissionPageManager", "resolveinfoList" + resolveinfoList.size());
        for (int i = 0; i < resolveinfoList.size(); i++) {
            Log.e("PermissionPageManager", resolveinfoList.get(i).activityInfo.packageName + resolveinfoList.get(i).activityInfo.name);
        }
        ResolveInfo resolveinfo = resolveinfoList.iterator().next();
        if (resolveinfo != null) {
            // packageName参数2 = 参数 packname
            String packageName = resolveinfo.activityInfo.packageName;
            // 这个就是我们要找的该APP的LAUNCHER的Activity[组织形式:packageName参数2.mainActivityname]
            String className = resolveinfo.activityInfo.name;
            // LAUNCHER Intent
            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);
            // 设置ComponentName参数1:packageName参数2:MainActivity路径
            ComponentName cn = new ComponentName(packageName, className);
            intent.setComponent(cn);
            try {
                mContext.startActivity(intent);
            } catch (Exception e) {
                goIntentSetting();
                e.printStackTrace();
            }
        }
    }
}

下面是使用示列

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testPermission();
            }
        });
    }
    @PermissionCheck(permissions = {Manifest.permission.CAMERA})
    public void testPermission(){
        Log.d("MainActivity", "已经有权限了");
    }
    @PermissionCanceled
    public void permissionCanceled(String[] permissions){
        Log.d("MainActivity", permissions.toString());
    }
    @PermissionDenied
    public void permissionDenied(String[] permissions){
        Log.d("MainActivity", permissions.toString());
    }
}

aop刚学不久 有不对的地方 望各位指正 

代码链接:https://pan.baidu.com/s/1ORKeTJH3NNCKlGBJWUFlLA 提取码:qswi

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: AOP实现自定义权限注解可以通过使用Spring AOP实现。首先,你需要定义一个自定义注解,用于标记需要进行权限控制的方法。然后,你可以使用AOP的方式,在方法执行前或执行后进行权限验证。具体实现可以参考以下步骤: 1. 定义自定义注解:你可以使用@PreventRepeat注解来标记需要进行权限控制的方法。 2. 创建切面:你需要创建一个切面类,使用@Aspect注解标记,并在该类中定义一个切点,用于匹配被@PreventRepeat注解标记的方法。 3. 实现权限验证逻辑:在切面类中,你可以使用@Before或@After注解来定义权限验证的逻辑。在方法执行前或执行后,你可以进行相应的权限验证操作。 4. 配置AOP:最后,你需要在Spring配置文件中配置AOP,将切面类和切点与目标对象关联起来。 通过以上步骤,你就可以实现自定义权限注解的AOP实现了。这样,在被@PreventRepeat注解标记的方法执行前或执行后,你可以进行相应的权限验证操作。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* *3* [java-使用spring AOP实现自定义注解](https://blog.csdn.net/weixin_43846708/article/details/129547120)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值