IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android进阶宝典 --- AOP打造动态申请权限框架 -> 正文阅读

[移动开发]Android进阶宝典 --- AOP打造动态申请权限框架

在上一节中介绍了如何利用AspectJ进行AOP编程,那么既然知道了AOP,那么AOP在实际的项目中会在哪里用到呢?

说一下我自己的项目,我现在负责的项目中App很多,几乎每个App都需要权限申请,之前是每个App都自己做一套权限申请,UI的样式也不统一,交互设计经常吐槽,其实利用AOP完全就可以把权限申请拉齐,下沉到base,每个项目依赖base_permission。

1 传统权限申请

在Android 6.0之后,部分权限申请动态配置,用户如果明确禁止该权限,那么只能去设置页开启,以下就是传统的权限申请流程

t1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {

        getSD();
    }
});

public void getSD(){

    if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
        //如果没有获取到权限
        ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
    }else {
        //do work
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(requestCode == 1){
        for (int result : grantResults) {
            if(result == PackageManager.PERMISSION_GRANTED){
                Log.e("TAG","获取到权限");
            }else {
                Log.e("TAG","禁止获取权限");
                //跳到设置页

            }
        }
    }
}

这是OOP思想进行权限申请,即便是将其封装为一套权限申请工具,那么每次调用时都需要调用其中的方法做处理,而且不易于扩展。

2 AOP思想打造权限申请框架

如果使用AOP的思想,那么getSD()方法就是一个切入点,从而针对切入点织入代码

2.1 注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
    //需要申请的权限
    String[] value();
    //请求码
    int requestCode();
}

Permission注解用于修饰 切入点,其中传入的参数是按照传统的请求方式设置的,在申请权限时,我需要对哪个权限申请,申请权限时需要设置一个请求码判断是否获取到了权限

@Permission(value = Manifest.permission.WRITE_EXTERNAL_STORAGE,requestCode = 1)
public void getSD(){

//        if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
//            //如果没有获取到权限
//            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
//        }else {
//            //do work
//        }
}

2.2 权限织入类

/**
 * 权限织入类
 */
@Aspect
public class PermissionWearAspectJ {

    @Pointcut("execution(@com.take.aop.annatation.Permission * * (..))")
    public void permission(){

    }
	@Around("permission()")
    public void checkPermission(ProceedingJoinPoint joinPoint){
        //在这个方法之前之前,首先判断,是否获取了某个权限
        
    }

}

这样找到所有标注Permission注解的方法作为切入点—那么这里有一个问题,我在织入类中进行权限申请,能可以吗?

显然是不行的,因此在传统的权限申请中,需要onRequestPermissionsResult回调判断用户是否拒绝或者同意这个权限,在织入类中是没有这个回调的,那么该怎么办呢? ------ 办法就是启动一个透明的Activity,在透明的Activity中只进行权限获取结果的回调

<style name="Transparent" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>

2.1 获取上下文

如何在织入类中获取上下文对象,这得借助到ProceedingJoinPoint;

//获取上下文
Object aThis = joinPoint.getThis();
Context context = null;
if(aThis instanceof Context){
    context = (Context) aThis;
}else if(aThis instanceof Fragment){
    context = ((Fragment) aThis).getContext();
}

ProceedingJoinPoint的getThis方法,就是拿到的切入点方法所在的上下文,getSD所在的上下文就是MainActivity。

2.2 获取注解参数

在切入点方法注解中,传入了2个参数,分别是申请权限名称和请求码,那么如何获取到这个两个参数,那么还是需要从切入点赋值

@Pointcut("execution(@com.take.aop.annatation.Permission * * (..)) && @annotation(permission)")
public void permission(Permission permission){

}

@annotation(permission)代表注解的赋值在切入点传入接收,那么在permission方法中就可以接收,同样,在Advice中也可以接收这个permission参数

2.3 透明Activity配置

public class TransParentActivity extends AppCompatActivity {

    private static PermissionResultCallback mCallback;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();
        if(intent == null){
            this.finish();
            return;
        }

        String[] permissions = getIntent().getStringArrayExtra("permission");
        int code = getIntent().getIntExtra("code", -99);

        if(permissions == null || code == -99 || mCallback == null){
            this.finish();
            return;
        }

        //权限申请 --- 判断当前所有的权限是否都申请过了
        if(PermissionUtils.hasAllPermission(this,permissions)){
            mCallback.onPermissionGranted();
            this.finish();
            return;
        }

        //申请权限
        ActivityCompat.requestPermissions(this,permissions,code);

    }

    public static void openActivity(Context context,String[] permission,int requestCode,PermissionResultCallback callback){

        mCallback = callback;
        Intent intent = new Intent();
        intent.putExtra("permission",permission);
        intent.putExtra("code",requestCode);
        intent.setClass(context,TransParentActivity.class);
        context.startActivity(intent);
    }

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

        if(PermissionUtils.hasAllPermission(this,permissions)){
            mCallback.onPermissionGranted();
            this.finish();
            return;
        }

        if(PermissionUtils.isUserReject(this,permissions)){
            mCallback.onPermissionDenied();
            this.finish();
            return;
        }

        mCallback.onPermissionReject();
        this.finish();

    }
}

其实,透明Activity的主要工作就是判断当前app是否拥有了某个权限,以及做用户权限申请操作的回调

public interface PermissionResultCallback {

    /**
     * 同意权限
     */
    void onPermissionGranted();

    /**
     * 拒绝权限
     */
    void onPermissionReject();

    /**
     * 拒绝权限并不再询问
     */
    void onPermissionDenied();
}

在结果的回调里,可以做相应的处理

最终的织入类

/**
 * 权限织入类
 */
@Aspect
public class PermissionWearAspectJ {

    @Pointcut("execution(@com.take.aop.annatation.Permission * * (..)) && @annotation(permission)")
    public void permission(Permission permission){

    }

    @Around("permission(permission)")
    public void checkPermission(ProceedingJoinPoint joinPoint,Permission permission){
        //在这个方法之前之前,首先判断,是否获取了某个权限

        //获取上下文
        Object aThis = joinPoint.getThis();
        Context context = null;
        if(aThis instanceof Context){
            context = (Context) aThis;
        }else if(aThis instanceof Fragment){
            context = ((Fragment) aThis).getContext();
        }

        //获取注解传参
        if(context == null || permission == null || permission.value().length == 0){
            return;
        }
        String[] value = permission.value();
        int requestCode = permission.requestCode();
        Log.e("TAG","value -"+value+"requestCode = "+requestCode);


        //启动透明Activity
        TransParentActivity.openActivity(context, value, requestCode, new PermissionResultCallback() {
            @Override
            public void onPermissionGranted() {
                Log.e("TAG","获取了权限");
                try {
                    joinPoint.proceed();
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }

            @Override
            public void onPermissionReject() {
                Log.e("TAG","拒绝了权限");
            }

            @Override
            public void onPermissionDenied() {

            }
        });

    }

}

总结:其实这只是一个简单的方式来利用AOP思想来做权限申请框架,里面可能涉及到很多自己的业务逻辑,之后会封装一个完整的框架放在git上提供给各位参考。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 12:02:43  更:2022-05-10 12:03:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 1:29:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码