簡介
這篇文章主要是用來將學習的AOP用以實踐,如果不清楚aop的使用方法,可以參考:android架構師之路——AOP講解,如果想要直接使用可以參考:PermissionsDispatcher,如果是學習android 6.0權限申請可以參考:android 6.0 權限申請
項目結構
|
請求權限的標註,有兩個參數:1、value()數組,請求權限數組。2、requestCode請求權限返回的code值 |
|
申請權限結果處理,取消權限的標註(請求權限時候,點擊取消),有一個參數:requestCode(對應@NeedPermission中的requestCode) |
|
申請權限結果處理,不再提醒的標註(請求權限時候,有一個不在提醒的checkbox) |
|
處理@NeedPermission、@PermissionCancled、@PermissionDenied標註,以及請求權限的處理,是這個demo的重點 |
|
與@PermissionCancled一起使用,包含了取消權限的equestCode值,用來處理取消權限以後的邏輯 |
|
與@PermissionDenied一起使用,包含了不在提醒的requestCode值,以及不在提醒的權限集合denyList |
|
權限申請的接口 |
|
申請權限的一些方法 |
|
工具類方法 |
|
主activity |
|
一個透明的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中動態申請權限的代碼量