当前位置 : 主页 > 手机开发 > android >

android用 javassist实现捕获第三方库异常

来源:互联网 收集:自由互联 发布时间:2021-06-11
Git传送门 Android开发中不可避免的会用到很多第三方库, 如果碰到异常 常常有种心有余而力不足的想法,当日,如果是开源的 你可以吧源码导入进来进行修改, 但不可避免的会造成维

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
网友评论