Git传送门
Android开发中不可避免的会用到很多第三方库, 如果碰到异常 常常有种心有余而力不足的想法,如果是开源的 你可以吧源码导入进来进行修改,但不可避免的会造成维护性差, 本文提供一个捕获屏蔽第三方库异常的思路,也可以扩展为在编译时修改第三方库代码,从而插入自己的需求
1.Javassist 简介
javassist是一个修改java字节码的开源库
下面是个很简单的例子,获取一个classPool,设置运行所需要的库,写入到对应位置
具体语法可以参考 Javassist介绍
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath("/usr/local/javalib");
CtClass cc = pool.get("test.Rectangle");
cc.setSuperclass(pool.get("test.Point"));
cc.writeFile();
2.在安卓中的应用
gradle 编译安卓项目是通过一个个task来执行任务, 我们可以通过gradle看到很多transform*的task
在编译时插入一个自己的transform 从而实现对源码或第三方jar库拦截 实现修改第三方库
下面时定义一个gradle插件, 注册一个自己的transform
public class MainPlugin implements Plugin<Project>{
void apply(Project project) {
project.logger.error("Dhjar start=========================")
project.extensions.create("dhjar", LJarConfig)
project.android.registerTransform(new JavassistTransform(project))
}
}
transform的几个方法
//获取输入类型jar或者class @Override
public Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS;
}
//需要处理的范围, 主项目 子项目 或者三方库
@Override
public Set<? super QualifiedContent.Scope> getScopes() {
Set<QualifiedContent.Scope> sets = new HashSet<QualifiedContent.Scope>()
sets.add(QualifiedContent.Scope.EXTERNAL_LIBRARIES)
return sets;
}
@Override
Set<? super QualifiedContent.Scope> getReferencedScopes() {
Set<QualifiedContent.Scope> sets = new HashSet<QualifiedContent.Scope>()
sets.add(QualifiedContent.Scope.EXTERNAL_LIBRARIES)
sets.add(QualifiedContent.Scope.PROVIDED_ONLY)
return sets
}
他的核心方法就是 分别为获取jar 和source目录
@Override
public void transform(TransformInvocation transformInvocation) throws IOException {
}
下面就是捕获第三方异常的核心代码 通过插入一个相同的方法包裹上try catch 从而拦截需要捕获的方法, 具体代码可以看开头的链接
private static void modify(CtClass c, ClassPool mClassPool,List<String> methods) {
if (c.isFrozen()) {
c.defrost()
}
System.out.println("find class==============="+c.getName())
for(String method : methods){
CtMethod ctMethod = c.getDeclaredMethod(method)
String method2 = method+"DhCut"
CtMethod ctMethod2 = CtNewMethod.copy(ctMethod,method2,c,null)
c.addMethod(ctMethod2)
int methodLen = ctMethod.getParameterTypes().length
StringBuffer sb = new StringBuffer()
sb.append("{try{")
if(!ctMethod.getReturnType().getName().contains("void")){
sb.append("return ")
}
sb.append(method2)
sb.append("(")
for(int i = 0; i<methodLen;i++){
sb.append("\$"+(i+1))
if(i!=methodLen-1){
sb.append(",")
}
}
sb.append(");}catch(Exception ex){ System.out.println(ex.toString());ex.printStackTrace();}")
if(!ctMethod.getReturnType().getName().contains("void")){
sb.append("return ")
String result = getReturnValue(ctMethod.getReturnType().getName())
sb.append(result)
sb.append(";")
}
sb.append("}")
System.out.println("return type =======" +ctMethod.getReturnType().getName())
ctMethod.setBody(sb.toString())
}
}
拦截前得类 此时我们直接调用getString 或造成空指针崩溃
package com.vova.testlibrary;
public class TestFile
{
public int getInt()
{
return 1;
}
public float getFloat()
{
return 0.0F;
}
public double getDoulbe()
{
return 0.0D;
}
public long getLong()
{
return 0L;
}
public char getChar()
{
return 'a';
}
public short getShort()
{
return 0;
}
public double getDouble()
{
return 0.0D;
}
public String getString()
{
String aa = null;
int len = aa.length();
return null;
}
public byte getByte()
{
return 0;
}
}
View Code
gradle编译效果图 输入test.jar 输出19.jar 打印需要替换的方法
下面是19.jar源码
package com.vova.testlibrary;
import java.io.PrintStream;
public class TestFile
{
public int getIntDhCut()
{
return 1;
}
public float getFloatDhCut()
{
return 0.0F;
}
public double getDoulbe()
{
return 0.0D;
}
public long getLongDhCut()
{
return 0L;
}
public char getCharDhCut()
{
return 'a';
}
public short getShortDhCut()
{
return 0;
}
public double getDoubleDhCut()
{
return 0.0D;
}
public String getStringDhCut()
{
String aa = null;
int len = aa.length();
return null;
}
public byte getByteDhCut()
{
return 0;
}
public int getInt()
{
try
{
return getIntDhCut();
}
catch (Exception localException)
{
System.out.println(localException.toString());
localException.printStackTrace();
}
return 0;
}
public float getFloat()
{
try
{
return getFloatDhCut();
}
catch (Exception localException)
{
System.out.println(localException.toString());
localException.printStackTrace();
}
return 0.0F;
}
public long getLong()
{
try
{
return getLongDhCut();
}
catch (Exception localException)
{
System.out.println(localException.toString());
localException.printStackTrace();
}
return 0L;
}
public char getChar()
{
try
{
return getCharDhCut();
}
catch (Exception localException)
{
System.out.println(localException.toString());
localException.printStackTrace();
}
return 'a';
}
public short getShort()
{
try
{
return getShortDhCut();
}
catch (Exception localException)
{
System.out.println(localException.toString());
localException.printStackTrace();
}
return 0;
}
public double getDouble()
{
try
{
return getDoubleDhCut();
}
catch (Exception localException)
{
System.out.println(localException.toString());
localException.printStackTrace();
}
return 0.0D;
}
public String getString()
{
try
{
return getStringDhCut();
}
catch (Exception localException)
{
System.out.println(localException.toString());
localException.printStackTrace();
}
return null;
}
public byte getByte()
{
try
{
return getByteDhCut();
}
catch (Exception localException)
{
System.out.println(localException.toString());
localException.printStackTrace();
}
return 0;
}
}
View Code
|