初学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