通过解析所有的类,过滤出onClick方法用来注入我们的事件统计代码。 没有逻辑性的问题,就直接上代码了。
由于Javassist的封装比较复杂,首先我要定义两个实体,存放我解析出来需要用到的Method属性。
public class IMethod {
private String name;
private List params = new ArrayList<>();
private String returnType;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getParams() {
return params;
}
public void setParams(List params) {
this.params = params;
}
public String getReturnType() {
return returnType;
}
public void setReturnType(String returnType) {
this.returnType = returnType;
}
public void addParam(IMethodParam param) {
if(param != null){
params.add(param);
}
}
}
public class IMethodParam {
private String type;//the typename of param, example:android.view.View
private String name;//the name of param, example:v
public IMethodParam() {
super();
}
public IMethodParam(String type, String name) {
super();
this.type = type;
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof IMethodParam) {
IMethodParam param = (IMethodParam) obj;
return (type != null && name != null//
&& param != null//
&& param.getType() != null//
&& param.getName() != null//
&& type.equals(param.getType())//
&& name.equals(param.getName()));//
}
return super.equals(obj);
}
@Override
public int hashCode() {
if(type != null && name != null)
return (type + name).hashCode();
return super.hashCode();
}
}
接着我们要解析Mehod,我们主要需要方法名,参数类型的名称,参数的名称以及返回值的类型名称
public static IMethod parse(CtMethod method){
if(method != null){
IMethod iMethod = new IMethod();
iMethod.setName(method.getName());
/***
* 获取参数的类型和值
*/
try {
CtClass[] parameterTypes = method.getParameterTypes();
if(parameterTypes != null && parameterTypes.length > 0){
int len = parameterTypes.length;
String[] paramNames = getMethodParamNames(method);
if(paramNames != null && paramNames.length >= len){
for (int i = 0; i < parameterTypes.length; i++) {
IMethodParam param = new IMethodParam();
param.setType(parameterTypes[i].getName());
param.setName(paramNames[i]);
iMethod.addParam(param);
}
}
}
CtClass returnType = method.getReturnType();
if(returnType != null){
iMethod.setReturnType(returnType.getName());
}
} catch (NotFoundException e) {
e.printStackTrace();
}
return iMethod;
}
return null;
}
public static String[] getMethodParamNames(CtMethod cm) {
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
.getAttribute(LocalVariableAttribute.tag);
if (attr == null) {
return null;
}
String[] paramNames = null;
try {
CtClass[] parameterTypes = cm.getParameterTypes();
if(parameterTypes != null && parameterTypes.length > 0){
paramNames = new String[parameterTypes.length];
}
} catch (NotFoundException e) {
e.printStackTrace();
return null;
}
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < paramNames.length; i++) {
paramNames[i] = attr.variableName(i + pos);
}
return paramNames;
}
剩下的就是根据解析出来的内容来判断是否是onClick方法
public static final String ONCLICK_METHOD_NAME = "onClick";
public static final String ONCLICK_METHOD_PARAM_TYPE = "android.view.View";
public static final String ONCLICK_METHOD_RETURN_TYPE = "void";
public static boolean isOnClick(IMethod method){
if(method != null){
String name = method.getName();
List params = method.getParams();
String returnType = method.getReturnType();
if(notNul(name) && notNul(returnType) && notNul(params)){
IMethodParam param = params.get(0);
return ONCLICK_METHOD_NAME.equals(name)
&& ONCLICK_METHOD_RETURN_TYPE.equals(returnType)
&& ONCLICK_METHOD_PARAM_TYPE.equals(param.getType());
}
}
return false;
}
public static boolean notNul(String s){
return s!= null && !"".equals(s);
}
public static boolean notNul(List list){
return list != null && list.size() > 0;
}