package com.didichuxing.doraemonkit.plugin.bytecode; import com.didichuxing.doraemonkit.plugin.DokitExtUtil; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.AmapLocationMethodAdapter; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.BaiduLocationMethodAdapter; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.PluginConfigMethodAdapter; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.OkHttpNullConsMethodAdapter; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.OkHttpOneParamConsMethodAdapter; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.PlatformNullConsHttpMethodAdapter; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.PlatformOneParamHttpMethodAdapter; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.TencentLocationMethodAdapter; import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.TencentLocationSingleMethodAdapter; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; /** * Created by jint on 13/12/2019. * 类访问器 */ public final class DokitCommClassAdapter extends ClassVisitor { /** * 当前类型 */ private String className; /** * 当前类的父类 假如存在的话 */ private String superName; /** * @param cv cv */ public DokitCommClassAdapter(final ClassVisitor cv) { super(Opcodes.ASM7, cv); } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); this.className = name; this.superName = superName; } /** * Visits a method of the class. This method must return a new {@link MethodVisitor} * instance (or {@literal null}) each time it is called, i.e., it should not return a previously * returned visitor. * * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if * the method is synthetic and/or deprecated. * @param methodName the method's name. * @param desc the method's descriptor (see {@link Type}). * @param signature the method's signature. May be {@literal null} if the method parameters, * return type and exceptions do not use generic types. * @param exceptions the internal names of the method's exception classes (see {@link * Type#getInternalName()}). May be {@literal null}. * @return an object to visit the byte code of the method, or {@literal null} if this class * visitor is not interested in visiting the code of this method. */ @Override public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, String[] exceptions) { //从传进来的ClassWriter中读取MethodVisitor MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions); //开发者变量字节码替换 if (className.equals("com/didichuxing/doraemonkit/DoraemonKitReal") && methodName.equals("pluginConfig")) { log(className, access, methodName, desc, signature); //创建MethodVisitor代理 return mv == null ? null : new PluginConfigMethodAdapter(access, desc, mv, methodName); } //地图配置 if (DokitExtUtil.getInstance().getCommConfig().mapSwitch) { //高德地图字节码替换 if (className.equals("com/amap/api/location/AMapLocationClient") && methodName.equals("setLocationListener")) { //创建MethodVisitor代理 log(className, access, methodName, desc, signature); return mv == null ? null : new AmapLocationMethodAdapter(access, desc, mv); } //腾讯地图字节码替换 if (className.equals("com/tencent/map/geolocation/TencentLocationManager") && methodName.equals("requestLocationUpdates")) { log(className, access, methodName, desc, signature); //创建MethodVisitor代理 return mv == null ? null : new TencentLocationMethodAdapter(access, desc, mv); } //腾讯地图单次定位 if (className.equals("com/tencent/map/geolocation/TencentLocationManager") && methodName.equals("requestSingleFreshLocation")) { log(className, access, methodName, desc, signature); //创建MethodVisitor代理 return mv == null ? null : new TencentLocationSingleMethodAdapter(access, desc, mv); } //百度地图定位 汇报函数签名错误 暂时未找到原因 // if (className.equals("com/baidu/location/LocationClient") && name.equals("registerLocationListener")) { // log(className, access, name, desc, signature); // //创建MethodVisitor代理 // return mv == null ? null : new BaiduLocationMethodAdapter(access, desc, mv); // } //百度地图定位 if (methodName.equals("onReceiveLocation") && desc.equals("(Lcom/baidu/location/BDLocation;)V")) { log(className, access, methodName, desc, signature); //创建MethodVisitor代理 return mv == null ? null : new BaiduLocationMethodAdapter(access, desc, mv); } } //网络配置 if (DokitExtUtil.getInstance().getCommConfig().networkSwitch) { //okhttp 拦截器字节码替换 空构造函数 if (className.equals("okhttp3/OkHttpClient$Builder") && methodName.equals("") && getParamsSize(desc) == 0) { //创建MethodVisitor代理 log(className, access, methodName, desc, signature); return mv == null ? null : new OkHttpNullConsMethodAdapter(access, desc, mv); } //okhttp 拦截器字节码替换 一个参数的构造函数 if (className.equals("okhttp3/OkHttpClient$Builder") && methodName.equals("") && getParamsSize(desc) == 1) { //创建MethodVisitor代理 log(className, access, methodName, desc, signature); return mv == null ? null : new OkHttpOneParamConsMethodAdapter(mv, access, methodName, desc); } //didi平台端 网络 空构造函数 if (className.equals("didihttp/DidiHttpClient$Builder") && methodName.equals("") && getParamsSize(desc) == 0) { //创建MethodVisitor代理 log(className, access, methodName, desc, signature); return mv == null ? null : new PlatformNullConsHttpMethodAdapter(access, desc, mv); } //didi平台端 网络 一个参数的构造函数 if (className.equals("didihttp/DidiHttpClient$Builder") && methodName.equals("") && getParamsSize(desc) == 1) { //创建MethodVisitor代理 log(className, access, methodName, desc, signature); return mv == null ? null : new PlatformOneParamHttpMethodAdapter(mv, access, methodName, desc); } } return mv; } /** * 获取形参个数 * * @param desc * @return */ private int getParamsSize(String desc) { //(Landroid/app/Application;Ljava/util/List;Ljava/lang/String;)V 包含3个参数的install方法实例 if (desc == null || desc.equals("")) { return 0; } //包含返回值 所以需要减1 return desc.split(";").length - 1; } /** * 日志输出 * * @param className * @param access * @param name * @param desc * @param signature */ private void log(String className, int access, String name, String desc, String signature) { System.out.println("DokitCommClassAdapter===matched====>" + " className===" + className + " access===" + access + " methodName===" + name + " desc===" + desc + " signature===" + signature); } }