android架構師之路——AOP應用(android 6.0權限申請)

簡介

這篇文章主要是用來將學習的AOP用以實踐,如果不清楚aop的使用方法,可以參考:android架構師之路——AOP講解,如果想要直接使用可以參考:PermissionsDispatcher,如果是學習android 6.0權限申請可以參考:android 6.0 權限申請

項目結構

@NeedPermission
請求權限的標註,有兩個參數:1、value()數組,請求權限數組。2、requestCode請求權限返回的code值
@PermissionCancled
申請權限結果處理,取消權限的標註(請求權限時候,點擊取消),有一個參數:requestCode(對應@NeedPermission中的requestCode)
@PermissionDenied
申請權限結果處理,不再提醒的標註(請求權限時候,有一個不在提醒的checkbox)
PermissionAspect
處理@NeedPermission、@PermissionCancled、@PermissionDenied標註,以及請求權限的處理,是這個demo的重點
CancelBean
與@PermissionCancled一起使用,包含了取消權限的equestCode值,用來處理取消權限以後的邏輯
DenyBean
與@PermissionDenied一起使用,包含了不在提醒的requestCode值,以及不在提醒的權限集合denyList
IPermission
權限申請的接口
PermissionUtil
申請權限的一些方法
Utils
工具類方法
MainActivity
主activity
PermissionRequestActivity
一個透明的activity,用來申請權限

 代碼介紹

  • 主入口MainActivity

@NeedPermission申請了兩個權限Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA

@PermissionCancled申請權限被拒絕後的處理

@PermissionDenied 申請權限被拒絕,並且不在提醒的處理

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @NeedPermission(value = {Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA},requestCode = 100)
    public void requestPermission(View view) {
        Log.e("zkq","請求權限");
    }

    @PermissionCancled
    public void cancle(CancelBean bean) {
        Log.e("zkq","拒絕");
        int requestCode = bean.getRequestCode();
        if (requestCode==100){
            Log.e("zkq","requestCode==100的被拒絕了");
        }
    }

    @PermissionDenied
    public void defied(DenyBean bean) {
        List<String> denyList = bean.getDenyList();
        for (String s : denyList) {
            Log.e("zkq","已經拒絕,不再提醒 : "+s);
        }
    }
}
  • 標註

NeedPermission

/**
 * 請求權限
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NeedPermission {
    String[] value();

    //默認值 0
    int requestCode() default 0;
}
PermissionCancled
/**
 * 取消權限
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PermissionCancled {
    int requestCode() default 0;
}
PermissionDenied
/**
 * 拒絕權限並且選中不再提示
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PermissionDenied {
}
  • PermissionAspect主要處理標註與權限申請的邏輯,是這裏的重點,注意com.example.aoprequestpermission.annotation需要和自己的包名一致
@Aspect
public class PermissionAspect {
    Context context;

    @Pointcut("execution(@com.example.aoprequestpermission.annotation.NeedPermission *  *(..)) && @annotation(needPermission)")
    public void methodPermissionAspect(NeedPermission needPermission){

    }

    @Around("methodPermissionAspect(needPermission)")
    public void AroundPoint(final ProceedingJoinPoint joinPoint, NeedPermission needPermission){

        final Object aThis = joinPoint.getThis();
        if (aThis==null)return;

        if (aThis instanceof Context){
            this.context = (Context) aThis;
        }else if (aThis instanceof Fragment){
            this.context = ((Fragment) aThis).getActivity();
        }else if (aThis instanceof  android.support.v4.app.Fragment){
            this.context = ((android.support.v4.app.Fragment) aThis).getActivity();
        }else {
            //切點參數
            Object[] args = joinPoint.getArgs();
            if (args.length > 0) {
                //非靜態方法且第一個參數爲context
                if (args[0] instanceof Context) {
                    context = (Context) args[0];
                } else {
                    //沒有傳入context 默認使用application
                    context = Utils.getApp();
                }
            } else {
                context = Utils.getApp();
            }
        }

        if (context==null || needPermission ==null) return;

        PermissionRequestActivity.PermissionRequest(context, needPermission.value(), needPermission.requestCode(), new IPermission() {

            //已經允許了,直接執行
            @Override
            public void PermissionGranted() {
                try {
                    joinPoint.proceed();
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }

            @Override
            public void PermissionDenied(int requestCode, List<String> denyList) {
                //獲取所有方法
                Class<?> aClass = aThis.getClass();
                Method[] declaredMethods = aClass.getDeclaredMethods();
                if (declaredMethods==null || declaredMethods.length==0) return;

                for (Method method : declaredMethods) {
                    //過濾不含自定義註解PermissionDenied的方法
                    boolean isHasAnnotation = method.isAnnotationPresent(PermissionDenied.class);
                    if (isHasAnnotation){

                        method.setAccessible(true);
                        //獲取方法類型
                        Class<?>[] types = method.getParameterTypes();
                        if (types.length != 1) return;
                        //獲取方法上的註解
                        PermissionDenied aInfo = method.getAnnotation(PermissionDenied.class);
                        if (aInfo == null) return;
                        //解析註解上對應的信息
                        DenyBean bean = new DenyBean();
                        bean.setRequestCode(requestCode);
                        bean.setContext(context);
                        bean.setDenyList(denyList);
                        try {
                            method.invoke(aThis, bean);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }

                    }
                }

            }

            @Override
            public void PermissionCanceled(int requestCode) {
                Class<?> cls = aThis.getClass();
                Method[] methods = cls.getDeclaredMethods();
                if (methods.length == 0) return;

                for (Method method : methods) {
                    //過濾不含自定義註解PermissionCanceled的方法
                    boolean isHasAnnotation = method.isAnnotationPresent(PermissionCancled.class);

                    if (isHasAnnotation) {

                        method.setAccessible(true);

                        //獲取方法類型
                        Class<?>[] types = method.getParameterTypes();
                        if (types.length != 1) return;
                        //獲取方法上的註解
                        PermissionCancled aInfo = method.getAnnotation(PermissionCancled.class);
                        if (aInfo==null) return;;

                        CancelBean bean = new CancelBean();
                        bean.setContext(context);
                        bean.setRequestCode(requestCode);
                        try {
                            method.invoke(aThis, bean);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }

                    }
                }
            }
        });


    }

}
  • PermissionRequestActivity 用來申請權限的activity,主要是像fragment,services等,是沒有辦法申請權限的,所以就使用了一個透明的activity來實現這一步驟
public class PermissionRequestActivity extends Activity {

    private static IPermission permissionListener;
    private String[] permissions;
    private static final String PERMISSION_KEY = "permission_key";
    private static final String REQUEST_CODE = "request_code";
    private int requestCode;

    /**
     * 跳轉到Activity申請權限
     *
     * @param context     Context
     * @param permissions Permission List
     * @param iPermission Interface
     */
    public static void PermissionRequest(Context context, String[] permissions, int requestCode, IPermission iPermission) {
        permissionListener = iPermission;
        Intent intent = new Intent(context, PermissionRequestActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        Bundle bundle = new Bundle();
        bundle.putStringArray(PERMISSION_KEY, permissions);
        bundle.putInt(REQUEST_CODE, requestCode);
        intent.putExtras(bundle);
        context.startActivity(intent);
        if (context instanceof Activity) {
            ((Activity) context).overridePendingTransition(0, 0);
        }

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_request_permission);
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
            permissions = bundle.getStringArray(PERMISSION_KEY);
            requestCode = bundle.getInt(REQUEST_CODE, 0);
        }
        if (permissions == null || permissions.length <= 0) {
            finish();
            return;
        }
        requestPermission(permissions);
    }


    /**
     * 申請權限
     *
     * @param permissions permission list
     */
    private void requestPermission(String[] permissions) {

        if (PermissionUtil.hasSelfPermissions(this, permissions)) {
            //all permissions granted
            if (permissionListener != null) {
                permissionListener.PermissionGranted();
                permissionListener = null;
            }
            finish();
            overridePendingTransition(0, 0);
        } else {
            //request permissions
            ActivityCompat.requestPermissions(this, permissions, requestCode);
        }
    }

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

        if (PermissionUtil.verifyPermissions(grantResults)) {
            //所有權限都同意
            if (permissionListener != null) {
                permissionListener.PermissionGranted();
            }
        } else {
            if (!PermissionUtil.shouldShowRequestPermissionRationale(this, permissions)) {
                //權限被拒絕並且選中不再提示
                if (permissions.length != grantResults.length) return;
                List<String> denyList = new ArrayList<>();
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] == -1) {
                        denyList.add(permissions[i]);
                    }
                }
                if (permissionListener != null) {
                    permissionListener.PermissionDenied(requestCode, denyList);
                }
            } else {
                //權限被取消
                if (permissionListener != null) {
                    permissionListener.PermissionCanceled(requestCode);
                }
            }

        }
        permissionListener = null;
        finish();
        overridePendingTransition(0, 0);
    }

}
  •  權限申請接口IPermission
/**
 * 權限申請接口
 */

public interface IPermission {

    //同意權限
    void PermissionGranted();

    //拒絕權限並且選中不再提示
    void PermissionDenied(int requestCode, List<String> denyList);

    //取消權限
    void PermissionCanceled(int requestCode);
}
  • 請求權限返回結果類

CancelBean取消權限返回結果

DenyBean  不再提心的權限 ,denyList是不再提醒的權限集合,可以做後續處理

/**
 * 取消權限返回結果
 */

public class CancelBean {
    private int requestCode;
    private Context context;

    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public int getRequestCode() {
        return requestCode;
    }

    public void setRequestCode(int requestCode) {
        this.requestCode = requestCode;
    }
}
/**
 * 不再提心的權限
 */

public class DenyBean {

    private int requestCode;
    private List<String> denyList;
    private Context context;

    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public int getRequestCode() {
        return requestCode;
    }

    public void setRequestCode(int requestCode) {
        this.requestCode = requestCode;
    }

    public List<String> getDenyList() {
        return denyList;
    }

    public void setDenyList(List<String> denyList) {
        this.denyList = denyList;
    }
}
  • 工具類
PermissionUtil
public class PermissionUtil {

    private static final SimpleArrayMap<String, Integer> MIN_SDK_PERMISSIONS;

    static {
        MIN_SDK_PERMISSIONS = new SimpleArrayMap<>(8);
        MIN_SDK_PERMISSIONS.put("com.android.voicemail.permission.ADD_VOICEMAIL", 14);
        MIN_SDK_PERMISSIONS.put("android.permission.BODY_SENSORS", 20);
        MIN_SDK_PERMISSIONS.put("android.permission.READ_CALL_LOG", 16);
        MIN_SDK_PERMISSIONS.put("android.permission.READ_EXTERNAL_STORAGE", 16);
        MIN_SDK_PERMISSIONS.put("android.permission.USE_SIP", 9);
        MIN_SDK_PERMISSIONS.put("android.permission.WRITE_CALL_LOG", 16);
        MIN_SDK_PERMISSIONS.put("android.permission.SYSTEM_ALERT_WINDOW", 23);
        MIN_SDK_PERMISSIONS.put("android.permission.WRITE_SETTINGS", 23);
    }

    /**
     * 判斷是否所有權限都同意了,都同意返回true 否則返回false
     *
     * @param context     context
     * @param permissions permission list
     * @return return true if all permissions granted else false
     */
    public static boolean hasSelfPermissions(Context context, String... permissions) {
        for (String permission : permissions) {
            if (permissionExists(permission) && !hasSelfPermission(context, permission)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判斷單個權限是否同意
     *
     * @param context    context
     * @param permission permission
     * @return return true if permission granted
     */
    private static boolean hasSelfPermission(Context context, String permission) {
        return ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
    }

    /**
     * 判斷權限是否存在
     *
     * @param permission permission
     * @return return true if permission exists in SDK version
     */
    private static boolean permissionExists(String permission) {
        Integer minVersion = MIN_SDK_PERMISSIONS.get(permission);
        return minVersion == null || Build.VERSION.SDK_INT >= minVersion;
    }

    /**
     * 檢查是否都賦予權限
     *
     * @param grantResults grantResults
     * @return 所有都同意返回true 否則返回false
     */
    public static boolean verifyPermissions(int... grantResults) {
        if (grantResults.length == 0) return false;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * 檢查所給權限List是否需要給提示
     *
     * @param activity    Activity
     * @param permissions 權限list
     * @return 如果某個權限需要提示則返回true
     */
    public static boolean shouldShowRequestPermissionRationale(Activity activity, String... permissions) {
        for (String permission : permissions) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                return true;
            }
        }
        return false;
    }
}
Utils
public class Utils {

    private static Application sApplication;

    /**
     * Init utils.
     * <p>Init it in the class of Application.</p>
     *
     * @param app application
     */
    private static void init(final Application app) {
        if (sApplication == null) {
            if (app == null) {
                sApplication = getApplicationByReflect();
            } else {
                sApplication = app;
            }
        } else {
            if (app != null && app.getClass() != sApplication.getClass()) {
                sApplication = app;
            }
        }
    }

    /**
     * Return the context of Application object.
     *
     * @return the context of Application object
     */
    public static Application getApp() {
        if (sApplication != null) return sApplication;
        Application app = getApplicationByReflect();
        init(app);
        return app;
    }

    private static Application getApplicationByReflect() {
        try {
            @SuppressLint("PrivateApi")
            Class<?> activityThread = Class.forName("android.app.ActivityThread");
            Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
            Object app = activityThread.getMethod("getApplication").invoke(thread);
            if (app == null) {
                throw new NullPointerException("u should init first");
            }
            return (Application) app;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        throw new NullPointerException("u should init first");
    }

}

總結

這是AOP實踐的用例,使用@NeedPermission請求權限,用@PermissionCancled、@PermissionDenied對權限申請進行處理,大大減少了在每一個需要使用權限的activity中動態申請權限的代碼量

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