安卓Aop 實現權限檢測

AOP(Aspect Oriented Programming),即面向切面編程,通過預編譯方式和運行期間動態代理實現程序功能的統一維護的一種技術。AOP是OOP(Object Oriented Programming , 面向對象編程)的延續、補充。利用AOP可以對業務邏輯的各個部分或則會各個進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。

這篇文章是接之前的一篇文章《安卓中利用註解生成java代碼

爲什麼使用AOP

其實上面已經大概說了。大家都知道java是面向對象編程的高級語言,面向對象的編程可以使代碼模塊化、高內聚低耦合,從而方便功能拓展和代碼維護,降低開發成本,提高代碼質量,甚至提升產品的穩定性。
但是實際的項目開發中必然涉及到一些穿插在各個模塊的重複功能,這個功能本身我們可以直接模塊化,但是這個功能模塊需要在各個其它模塊的地方使用,必然會使其它模塊產生依賴,影響模塊的獨立性,比如:安卓權限檢測、網絡檢測、日誌輸出等。當然不是說模塊間調用不可以,只是從開發者角度,這是可以有優化空間的,這個時候就需要面向切面的編程方法了。

AOP註解等知識

註解解釋:

@Aspect:聲明切面,用來標記類的,可以理解是橫切面
@Pointcut(切點表達式):定義切點,標記方法的,切面上的具體的切點

//下面的都是統一的切點處理類
@Before(切點表達式):前置通知,切點之前執行
@Around(切點表達式):環繞通知,切點前後執行
@After(切點表達式):後置通知,切點之後執行
@AfterReturning(切點表達式):返回通知,切點方法返回結果之後執行
@AfterThrowing(切點表達式):異常通知,切點拋出異常時執行
 
 

JointPoint一些方法(以本文的實例爲例):

MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String name = signature.getName(); // 方法名:click
Method method = signature.getMethod(); // 方法:click方法信息實體類
Class returnType = signature.getReturnType(); // click返回值類型
Class declaringType = signature.getDeclaringType(); // 方法所在類名:MainActivity
String[] parameterNames = signature.getParameterNames(); // 參數名:activity
Class[] parameterTypes = signature.getParameterTypes(); // 參數類型:Activity
Object[] args = signature.getArgs(); //click裏的參數傳的值,這裏就是一個MainActivity的實體類

使用AOP權限檢測實踐

1,添加插件和使用(這裏使用是apectj插件)

在project的build.gradle中添加:

dependencies {
    classpath 'com.android.tools.build:gradle:3.3.2'
    classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'

    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
}

在app的build.gradle中添加:

apply plugin: 'com.android.application'
apply plugin: 'android-aspectjx'

2,定義註解類和切面處理類

註解類如下:

/**
 * 權限檢測註解
 * <p>
 * <>
 *
 * @author : liuxs
 * @date : 2020/5/15
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)//注意:這裏必須使用RetentionPolicy.RUNTIME,如果使用class或者source會在運行時註解消失不起作用
public @interface RequestPermission {

    /**
     * 需要申請的權限
     *
     * @return
     */
    String[] permissions() default {};
}

切面處理類:

/**
 * 權限切面處理類
 * <p>
 * <權限檢測統一放這裏處理,其它模塊如果需要動態權限檢測,直接使用註解{@link RequestPermission}>
 *
 * @author : liuxs
 * @date : 2020/5/15
 */
@Aspect
public class PermissionAspect {
    @Pointcut("execution(@com.gome.permissionsdemo.RequestPermission * *(..))")
    public void checkPermissions(){

    }

    /**
     * 這裏除了@Around(表示包圍了添加了註解的方法),還可以使用
     *
     * @see org.aspectj.lang.annotation.After   表示添加了註解的方法執行之後執行
     * @see org.aspectj.lang.annotation.Before  表示添加了註解的方法執行之前執行
     * @see org.aspectj.lang.annotation.AfterReturning 表示添加了註解的方法執行返回後執行
     * @see org.aspectj.lang.annotation.AfterThrowing  表示添加了註解的方法執行有異常時執行
     *
     * @param proceedingJoinPoint
     */
    @Around("checkPermissions()")
    public void _checkPermissions(final ProceedingJoinPoint proceedingJoinPoint){
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        RequestPermission requestPermission = methodSignature.getMethod().getAnnotation(RequestPermission.class);
        if(requestPermission == null){
            return;
        }
        String[] permissions = requestPermission.permissions();
        Object[] args = proceedingJoinPoint.getArgs();
        if(args == null ||args.length == 0){
            return;
        }
        Activity appCompatActivity = (Activity)args[0];
        if(args[0] instanceof Activity){
            EasyPermissions.checkPermissions(appCompatActivity, permissions, new PermissionsCallback() {
                @Override
                public void permissionsGranted() {
                    //TODO 授權後執行
                    try {
                        //執行被註解的方法
                        proceedingJoinPoint.proceed();
                    } catch (Throwable throwable) {
                        throwable.printStackTrace();
                    }
                }

                @Override
                public void permissionsDenied() {
                    //TODO 權限拒絕後執行
                }
            });
        }else{

        }
    }
}

3,其它模塊使用

這裏權限申請成功後Toast 獲取權限成功

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.hellotv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                /*EasyPermissions.checkPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA , Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsCallback() {
                    @Override
                    public void permissionsGranted() {
                        //TODO 授權後執行
                    }

                    @Override
                    public void permissionsDenied() {
                        //TODO 權限拒絕後執行
                    }
                });*/
                click(MainActivity.this);
            }
        });
    }

    @RequestPermission(permissions={Manifest.permission.CAMERA , Manifest.permission.WRITE_EXTERNAL_STORAGE})
    public void click(Activity activity) {
        Toast.makeText(MainActivity.this,"獲取權限成功",Toast.LENGTH_SHORT).show();
    }
}

注意:

如果報zip、jar爲空,檢查一下切面處理類是否有問題,比如:execution拼寫錯誤,寫成了executation;execution後面的註解寫錯了;註解後面的“* *(…)”寫錯了,第一個(*)代表類,然後空格,然後*代表方法,(…)代表形參。

demo有需要的可以私信獲取

又到週末了,世界那麼大,人生有那麼短,我想出去轉轉!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章