Android 中反射还能这么用?

cnmd9247 8年前
   <p>这几天稍微过了一下Weex的源码,可谓是亲眼目睹了它的源码。无意间发现一个类,叫WXHack,搜索一下代码,发现在Weex里用的地方就一处,好奇心驱使下去看了WXHack的源码,好家伙!看完之后总觉得这个类似曾相识,后来昨天在看OpenAtlas的代码的时候又看到了这个类,相关链接如下</p>    <ul>     <li><a href="/misc/goto?guid=4959671917898715265">Hack.java</a></li>     <li><a href="/misc/goto?guid=4959671917990245968">Interception.java</a></li>    </ul>    <p>后来我断定这个类应该是淘宝Atlas里的类,Weex直接抽出来了。为了验证自己的想法,下了个淘宝客户端反编译了下去找这个类,真的找到了。</p>    <p><img alt="这里写图片描述" src="https://simg.open-open.com/show/01501cb471923c4fcbe836f7be57b9db.png"></p>    <p>想看源码的可以直接点上面的链接去看OpenAtals里的类,也可以看这个保持了淘宝的包结构,但是反编译并完全的项目,也就是包含了一些字节码的,但是这两个类应该是完整的。</p>    <ul>     <li><a href="/misc/goto?guid=4959671918073274270">AtlasForAndroid</a></li>    </ul>    <p>那么携程的动态加载框架也算是有Atlas的成分了,自然也就有这两个类了,不出所料的找到了它们。</p>    <ul>     <li><a href="/misc/goto?guid=4959671918157718797">Hack.java</a></li>     <li><a href="/misc/goto?guid=4959671918242520330">Interception.java</a></li>    </ul>    <p>其实这个应该也不是淘专的专利,因为后来我在github上搜索了一番,发现了几个类似的类,这几个类在eclipse中竟然出现了。</p>    <ul>     <li><a href="/misc/goto?guid=4959671918328289146">HackedField.java</a></li>     <li><a href="/misc/goto?guid=4959671918407878328">HackedMethod0.java</a></li>     <li><a href="/misc/goto?guid=4959671918493365896">HackedMethod1.java</a></li>    </ul>    <p>那么,这两个类到底有什么作用呢,莫慌,容我慢慢道来。</p>    <p>首先,从名字上可以看出这是一个Hack类,它的作用就是辅助反射,但是它们却不是简简单单的辅助反射,而是反射后包装的形式:类,方法,字段 ,也就是HackedClass,HackedConstructor,HackedMethod,HackedField这几个反射的包装形式。并且还有AssertionFailureHandler用于处理反射发生异常时的处理,你可以选择扔出异常或者自己处理掉。</p>    <p>在看他的源码之前,我们先来看看传统的反射是怎么玩的。<br> 写了两三个类用来测试。</p>    <p>Student实体类,内部有一个IBehavior类,代表学生的行为;此外还有静态变量,非静态变量,静态方法,非静态方法,泛型变量,作用就是等下测试不同场景的反射。</p>    <pre>  <code class="language-java">public class Student implements Serializable {      private static String school = "清华大学";      private String name;      private int age;      private HashMap<String, Integer> scores = new HashMap<String, Integer>();        private IBehavior behavior = new BehaviorImpl();        public Student() {      }        public Student(String name, int age) {          this.name = name;          this.age = age;      }          public IBehavior getBehavior() {          return behavior;      }        public void setBehavior(IBehavior behavior) {          this.behavior = behavior;      }        public void addScore(String name, int score) {          scores.put(name, score);      }          public HashMap<String, Integer> getScores() {          return scores;      }        public void setScores(HashMap<String, Integer> scores) {          this.scores = scores;      }        public String getName() {          return name;      }        public void setName(String name) {          this.name = name;      }        public int getAge() {          return age;      }        public void setAge(int age) {          this.age = age;      }        public static String getSchool() {          return school;      }        public static void setSchool(String school) {          Student.school = school;      }        public void say(String word) {          System.out.println(word);      }          @Override      public String toString() {          return "Student{" +                  "school=" + school +                  ", age=" + age +                  ", name='" + name + '\'' +                  ", scores=" + scores +                  ", behavior=" + behavior +                  '}';      }  }  </code></pre>    <p>IBehavior接口以及其实现类的代码如下</p>    <pre>  <code class="language-java">public interface IBehavior {      void perform(String behaiviorName, String behaiviorContent);  }  public class BehaviorImpl implements IBehavior {      @Override      public void perform(String behaiviorName, String behaiviorContent) {          System.out.println("behaiviorName:" + behaiviorName);          System.out.println("behaiviorContent:" + behaiviorContent);      }  }  </code></pre>    <p>你要反射,就先得拿到Class对象,两种方式,一直是Class在你的项目中,可以直接引用,第二种就是这个Class可能你不能直接引用,比如Android中的ContextImpl,一般来说,第二种的使用场景会更广泛。</p>    <pre>  <code class="language-java">//直接通过class  Class<?> studentClassByClass = Student.class;    //通过class的字符串全类名  Class<?> studentClassByName = Class.forName("cn.edu.zafu.Student");</code></pre>    <p>然后你可以直接调用class的newInstance方法新建一个对象,但是对于没有默认构造函数的类来说,你需要拿到构造函数再去新建对象。这里需要注意的是你不知道修饰符是private,protected,public中的哪一个时,建议调用setAccessible设置成true,不然极有可能会发生异常。</p>    <pre>  <code class="language-java">//构造函数new对象  Constructor<?> constructor = studentClassByName.getConstructor(String.class, int.class);  constructor.setAccessible(true);  Student student = (Student) constructor.newInstance("区长", 22);  System.out.println(student);</code></pre>    <p>对于静态变量的访问,可以拿到Field,直接设置即可。set方法的第一个参数传null就是了。</p>    <pre>  <code class="language-java">//静态变量  Field schoolField = studentClassByName.getDeclaredField("school");  schoolField.setAccessible(true);  schoolField.set(null, "浙江大学");  System.out.println(Student.getSchool());</code></pre>    <p>但是对于非静态变量,set方法的第一个参数你就需要传递一个实例进去,比如上面通过构造函数new出来的对象。</p>    <pre>  <code class="language-java">//非静态变量  Field ageFiled = studentClassByName.getDeclaredField("age");  ageFiled.setAccessible(true);  Integer age = (Integer) ageFiled.get(student);  System.out.println(age);    ageFiled.set(student, 100);  System.out.println(student.getAge());</code></pre>    <p>同理静态方法同静态变量</p>    <pre>  <code class="language-java">//静态方法调用  Method setSchoolMethod = studentClassByName.getDeclaredMethod("setSchool", String.class);  setSchoolMethod.invoke(null, "清华大学");  System.out.println(Student.getSchool());</code></pre>    <p>非静态方法同非静态变量</p>    <pre>  <code class="language-java">//非静态方法调用  Method sayMethod = studentClassByName.getDeclaredMethod("say", String.class);  sayMethod.setAccessible(true);  sayMethod.invoke(student, "hello world");</code></pre>    <p>等等,还有一个泛型变量呢</p>    <pre>  <code class="language-java"> private HashMap<String, Integer> scores = new HashMap<String, Integer>();</code></pre>    <p>懵逼了,不会写。。。。。其实还是一样,强转就ok了,只不过强转前需要对类型进行校验。</p>    <p>然后就是异常处理,反射大多数人都是通过try catch直接捕捉异常。。。这也没什么好说的。</p>    <p>劫持,什么叫劫持呢,其实就是替换字段,有人说你直接反射拿到变量,直接反射替换就是了,这是一种方式,但是这并不是我想要的,比如我要劫持Student里的behavior变量,但是我不想修改它,我想保留它原来的逻辑,但是我又想加入新的东西,这个就有点类型面向切面编程了,比如日志的注入。怎么做?懵逼了。。。。显然是动态代理啊。使用代理类去完成劫持操作,既可以保留原有操作,又可以增加新的逻辑。</p>    <p>那么Hack类是怎么做的呢。首先生成HackedClass类,怎么生成的呢,调用Hack的into方法,入参有两种形式,一种就是直接传Class,另一种就是传递Class的全类名字符串。</p>    <pre>  <code class="language-java">public static <T> HackedClass<T> into(final Class<T> clazz) {      return new HackedClass<T>(clazz);  }    @SuppressWarnings({"rawtypes", "unchecked"})  public static <T> HackedClass<T> into(final String class_name) throws HackDeclaration.HackAssertionException {      try {          return new HackedClass(Class.forName(class_name));      } catch (final ClassNotFoundException e) {          fail(new HackDeclaration.HackAssertionException(e));          return new HackedClass(null);    // TODO: Better solution to avoid null?      }  }</code></pre>    <p>into方法返回的是HackedClass对象,这个对象是对反射的包装类之一。其源码如下</p>    <pre>  <code class="language-java">public static class HackedClass<C> {        protected Class<C> mClass;        public HackedClass(final Class<C> clazz) {          mClass = clazz;      }        public HackedField<C, Object> staticField(final String name) throws HackDeclaration.HackAssertionException {          return new HackedField<C, Object>(mClass, name, Modifier.STATIC);      }        public HackedField<C, Object> field(final String name) throws HackDeclaration.HackAssertionException {          return new HackedField<C, Object>(mClass, name, 0);      }        public HackedMethod staticMethod(final String name, final Class<?>... arg_types) throws HackDeclaration.HackAssertionException {          return new HackedMethod(mClass, name, arg_types, Modifier.STATIC);      }        public HackedMethod method(final String name, final Class<?>... arg_types) throws HackDeclaration.HackAssertionException {          return new HackedMethod(mClass, name, arg_types, 0);      }        public HackedConstructor constructor(final Class<?>... arg_types) throws HackDeclaration.HackAssertionException {          return new HackedConstructor(mClass, arg_types);      }        public Class<C> getmClass() {          return mClass;      }  }   </code></pre>    <p>如果你要获得静态方法,就调用staticMethod,静态变量就调用staticField,非静态方法就调用method,非静态变量就调用field,要获得构造函数就调用constructor,当然你也可以调用getmClass获得Class。最终如果你调用方法相关的函数会得到HackedMethod,调用变量相关的会得到HackedField,调用构造函数相关的会获得HackedConstructor,这三个类的源码如下。自己看源码。。。。不解释了。。。太长了,主要是对反射的封装,并达到面向对象的效果。</p>    <pre>  <code class="language-java">public static class HackedField<C, T> {        private final Field mField;          HackedField(final Class<C> clazz, final String name, int modifiers) throws HackDeclaration.HackAssertionException {          Field field = null;          try {              if (clazz == null) {                  return;              }              field = clazz.getDeclaredField(name);              if (modifiers > 0 && (field.getModifiers() & modifiers) != modifiers) {                  fail(new HackDeclaration.HackAssertionException(field + " does not match modifiers: " + modifiers));              }              field.setAccessible(true);          } catch (final NoSuchFieldException e) {              HackDeclaration.HackAssertionException hae = new HackDeclaration.HackAssertionException(e);              hae.setHackedClass(clazz);              hae.setHackedFieldName(name);              fail(hae);          } finally {              mField = field;          }      }        @SuppressWarnings("unchecked")              public <T2> HackedField<C, T2> ofGenericType(final Class<?> type) throws HackDeclaration.HackAssertionException {          if (mField != null && !type.isAssignableFrom(mField.getType())) {              fail(new HackDeclaration.HackAssertionException(new ClassCastException(mField + " is not of type " + type)));          }          return (HackedField<C, T2>) this;      }        @SuppressWarnings("unchecked")      public HackedField<C, T> ofType(final String type_name) throws HackDeclaration.HackAssertionException {          try {              return (HackedField<C, T>) ofType(Class.forName(type_name));          } catch (final ClassNotFoundException e) {              fail(new HackDeclaration.HackAssertionException(e));              return this;          }      }        @SuppressWarnings("unchecked")      public <T2> HackedField<C, T2> ofType(final Class<T2> type) throws HackDeclaration.HackAssertionException {          if (mField != null && !type.isAssignableFrom(mField.getType())) {              fail(new HackDeclaration.HackAssertionException(new ClassCastException(mField + " is not of type " + type)));          }          return (HackedField<C, T2>) this;      }          public void hijack(final C instance, final Interception.InterceptionHandler<?> handler) {          final T delegatee = get(instance);          if (delegatee == null) {              throw new IllegalStateException("Cannot hijack null");          }          final Class<?>[] interfaces = delegatee.getClass().getInterfaces();          set(instance, Interception.proxy(delegatee, handler, interfaces));      }            public T get(final C instance) {          try {              @SuppressWarnings("unchecked") final T value = (T) mField.get(instance);              return value;          } catch (final IllegalAccessException e) {              e.printStackTrace();              return null;           }      }          public void set(final C instance, final Object value) {          try {              mField.set(instance, value);          } catch (final IllegalAccessException e) {              e.printStackTrace();            }      }        public Field getField() {          return mField;      }  }    public static class HackedMethod {        protected final Method mMethod;          HackedMethod(final Class<?> clazz, final String name, final Class<?>[] arg_types, int modifiers) throws HackDeclaration.HackAssertionException {          Method method = null;          try {              if (clazz == null) {                  return;              }              method = clazz.getDeclaredMethod(name, arg_types);              if (modifiers > 0 && (method.getModifiers() & modifiers) != modifiers) {                  fail(new HackDeclaration.HackAssertionException(method + " does not match modifiers: " + modifiers));              }              method.setAccessible(true);          } catch (final NoSuchMethodException e) {              HackDeclaration.HackAssertionException hae = new HackDeclaration.HackAssertionException(e);              hae.setHackedClass(clazz);              hae.setHackedMethodName(name);              fail(hae);          } finally {              mMethod = method;          }      }          public Object invoke(final Object receiver, final Object... args) throws IllegalArgumentException, InvocationTargetException {          Object obj = null;          try {              obj = mMethod.invoke(receiver, args);              return obj;          } catch (final IllegalAccessException e) { /* Should never happen */              e.printStackTrace();          }          return obj;      }        public Method getMethod() {          return mMethod;      }  }    public static class HackedConstructor {        protected Constructor<?> mConstructor;        HackedConstructor(final Class<?> clazz, final Class<?>[] arg_types) throws HackDeclaration.HackAssertionException {          try {              if (clazz == null) {                  return;              }              mConstructor = clazz.getDeclaredConstructor(arg_types);          } catch (NoSuchMethodException e) {              HackDeclaration.HackAssertionException hae = new HackDeclaration.HackAssertionException(e);              hae.setHackedClass(clazz);              fail(hae);          }      }        public Object getInstance(final Object... arg_types) throws IllegalArgumentException {          Object obj = null;          mConstructor.setAccessible(true);          try {              obj = mConstructor.newInstance(arg_types);          } catch (Exception e) {              e.printStackTrace();          }          return obj;      }  }</code></pre>    <p>注意HackedField中有个方法叫hijack,这个方法的作用就是劫持。</p>    <p>最终,如果反射失败的话会进入Hack的fail方法处理,我们可以设置AssertionFailureHandler处理器,返回false会扔出异常,否则不会扔出异常。可以在里面做一些事,比如埋点。这样就可以集中到一个地方处理了。</p>    <pre>  <code class="language-java">private static void fail(HackDeclaration.HackAssertionException e) throws HackDeclaration.HackAssertionException {      if (sFailureHandler == null || !sFailureHandler.onAssertionFailure(e)) {          throw e;      }  }      public static void setAssertionFailureHandler(AssertionFailureHandler handler) {      sFailureHandler = handler;  }      public interface AssertionFailureHandler {      boolean onAssertionFailure(HackDeclaration.HackAssertionException failure);  }</code></pre>    <p>瞎说了这么多,来实践一把。</p>    <p>获得HackedClass对象,调用Hack.into方法</p>    <pre>  <code class="language-java">//通过Class来获得一个HackedClass  Hack.HackedClass<Student> hackPersonByClass = Hack.into(Student.class);  //输出class测试  System.out.println(hackPersonByClass.getmClass());  //通过Class的全类名获得一个HackedClass  Hack.HackedClass<Student> hackPersonByName = Hack.into("cn.edu.zafu.Student");  //输出class测试  System.out.println(hackPersonByName.getmClass());</code></pre>    <p>创建实例,调用HackedClass的constructor方法,将参数的类型传入,然后调用getInstance方法就可以获得一个实例了。</p>    <pre>  <code class="language-java">//获得构造函数  Hack.HackedConstructor personConstructor = hackPersonByName.constructor(String.class, int.class);  //创建并获得实例  Student student = (Student) personConstructor.getInstance("区长", 121);  //输出结果测试  System.out.println(student);  //直接调用反射获得的对象的方法  student.say("世界你好,世界再见");</code></pre>    <p>非静态变量需要通过field方法获得一个HackedField对象,这时候你获得的field是一个Object类型的,因此如果你想要类型安全,需要调用一下ofType方法,将类型传入。</p>    <pre>  <code class="language-java">//通过field -> ofType 获得一个HackedField,非静态  Hack.HackedField<Student, String> hackName = hackPersonByName.field("name").ofType(String.class);  //反射调用  String name = hackName.get(student);  //输出结果测试  System.out.println(name);    //通过field -> ofType 获得一个HackedField,非静态  Hack.HackedField<Student, Integer> hackAge = hackPersonByName.field("age").ofType(int.class);  //反射设置属性  hackAge.set(student, 16);  //反射获得age,进行验证  Integer age = hackPersonByName.field("age").ofType(int.class).get(student);  //输出结果测试  System.out.println(age);</code></pre>    <p>静态变量直接调用staticField方法即可,除了上面的ofType将类型传入,这个类型可以是Class对象,也可以是Class字符串的全类名。</p>    <pre>  <code class="language-java">//反射获得静态变量  Hack.HackedField<Student, Object> hackSchool = hackPersonByName.staticField("school").ofType("java.lang.String");    //获得静态变量值  String sSchool = (String) hackSchool.get(null);  //输出结果测试  System.out.println(sSchool);    //设置值  hackSchool.getField().set(null, "北京大学");  //获得值验证是否设置成功,通过getField()方式  sSchool = (String) hackSchool.getField().get(null);  //输出结果测试  System.out.println(sSchool);</code></pre>    <p>泛型参数可以调用ofGenericType方法转为泛型,比如下面的Map</p>    <pre>  <code class="language-java">//泛型参数  Hack.HackedField<Student, Map<String, Integer>> hackScores = hackPersonByName.field("scores").ofGenericType(Map.class);  Map<String, Integer> stringIntegerMap = hackScores.get(student);  stringIntegerMap.put("语文", 80);  stringIntegerMap.put("数学", 90);  //泛型参数设置  hackScores.set(student, stringIntegerMap);  //输出结果测试  System.out.println(student.getScores());</code></pre>    <p>方法的调用需要调用method相关的方法,非静态方法直接调用method方法获得HackedMethod对象,需要将方法的参数类型传入。之后直接invoke调用的时候将调用对象实例和参数传入。</p>    <pre>  <code class="language-java">//反射非静态方法调用  hackPersonByName.method("say", String.class).invoke(student, "fuck the source code");</code></pre>    <p>静态方法和非静态方法相比就是invoke的时候调用对象可以直接传null。</p>    <pre>  <code class="language-java">//反射静态方法调用  hackPersonByName.staticMethod("setSchool", String.class).invoke(null, "南京大学");  //输出结果测试  System.out.println(Student.getSchool());  //反射静态方法调用  String school = (String) hackPersonByName.staticMethod("getSchool").getMethod().invoke(null);  System.out.println(school);</code></pre>    <p>以上调用的最终输出如下图所示,代码可能跟图有出入(貌似修改过前后顺序)</p>    <p><img alt="这里写图片描述" src="https://simg.open-open.com/show/06bbe823b11c41faf81add8cc07cb365.png"></p>    <p>Hack类里的异常处理最终都会走到fail方法中,fail方法中会判断AssertionFailureHandler是否为空,空的情况下会直接扔出异常,否则会看AssertionFailureHandler的处理结果,如果结果返回true,则不扔出异常,返回fasle的情况下也会扔出异常,我们通过setAssertionFailureHandler方法设置一个异常处理器就可以了。下面调用两个不存在的字段,让它进入到这个处理器中,如果字段名是notHandler则扔出异常,否则输出信息并返回true。</p>    <pre>  <code class="language-java">//异常处理  Hack.setAssertionFailureHandler(new Hack.AssertionFailureHandler() {      @Override      public boolean onAssertionFailure(Hack.HackDeclaration.HackAssertionException failure) {          //如果是notHandler字段,则不处理,即扔出异常,否则打印输出,不扔出异常          if ("notHandler".equals(failure.getHackedFieldName())) {              return false;          }            Class<?> hackedClass = failure.getHackedClass();          String hackedFieldName = failure.getHackedFieldName();          String hackedMethodName = failure.getHackedMethodName();          System.out.println("=====onAssertionFailure start=====");          System.out.println("hackedClass:" + hackedClass);          System.out.println("hackedFieldName:" + hackedFieldName);          System.out.println("hackedMethodName:" + hackedMethodName);          System.out.println("=====onAssertionFailure end=====");          //返回true不会抛出异常,否则抛出异常            return true;      }  });  //获得一个不存在的对象,验证onAssertionFailure回调  Hack.HackedField<Student, String> unknownField = hackPersonByName.field("unknownField").ofType(String.class);  Hack.HackedField<Student, String> notHandler = hackPersonByName.field("notHandler").ofType(String.class);  </code></pre>    <p>最终的效果如下</p>    <p><img alt="这里写图片描述" src="https://simg.open-open.com/show/d81bd5dda0695d110d30ddae744d17e6.png"></p>    <p>劫持字段,字段的劫持就是通过动态代理来实现的,内部的逻辑如下</p>    <pre>  <code class="language-java">public static abstract class InterceptionHandler<T> implements InvocationHandler {      private T mDelegatee;        @Override      public Object invoke(Object obj, Method method, Object[] args)              throws Throwable {          Object obj2 = null;          try {              obj2 = method.invoke(delegatee(), args);          } catch (IllegalArgumentException e) {              e.printStackTrace();          } catch (IllegalAccessException e2) {              e2.printStackTrace();          } catch (InvocationTargetException e3) {              throw e3.getTargetException();          }          return obj2;      }        protected T delegatee() {          return this.mDelegatee;      }        void setDelegatee(T t) {          this.mDelegatee = t;      }  }</code></pre>    <p>这个字段的方法调用都是调用委托对象,这个对象就是我们原始的字段,这个delegatee方法我们可以重写返回新对象,这样就和反射直接替换没有什么差别了。当然也可以重写invoke方法,在调用前和调用后做一些处理。比如我做一些日志输出。如下代码</p>    <pre>  <code class="language-java">//字段劫持处理  Interception.InterceptionHandler handler = new Interception.InterceptionHandler<IBehavior>() {      @Override      public Object invoke(Object obj, Method method, Object[] args) throws Throwable {          System.out.println("hijack:[invoke start]");            Object o = super.invoke(obj, method, args);            System.out.println("hijack:[invoke end]");          return o;      }  };  //劫持behavior字段  hackPersonByName.field("behavior").hijack(student, handler);  //测试劫持效果  student.getBehavior().perform("sleep", "sleep 10h");</code></pre>    <p>最终效果如下<br> <img alt="这里写图片描述" src="https://simg.open-open.com/show/7e299e5db7a72183594385398d1043a3.png"></p>    <p>好了说了这么多,还是不明白这个东西有什么软用呢?Android动态加载资源的时候我们需要用到的ContextImpl对象,需要对AssetManager和Resources需要做一些操作,就可以这么来了。</p>    <pre>  <code class="language-java">import java.lang.reflect.InvocationTargetException;    public class Hacks extends HackDeclaration implements AssertionFailureHandler {   public static HackedClass<AssetManager> AssetManager;   public static HackedMethod AssetManager_addAssetPath;   public static HackedClass<Object> ContextImpl;   public static HackedField<Object, Resources> ContextImpl_mResources;   public static boolean sIsReflectChecked;   public static boolean sIsReflectAvailable;     public static boolean defineAndVerify() {    if (sIsReflectChecked) {     return sIsReflectAvailable;    }    Hacks hacks = new Hacks();    try {     Hack.setAssertionFailureHandler(hacks);     allClasses();     allConstructors();     allFields();     allMethods();     sIsReflectAvailable = true;     return sIsReflectAvailable;    } catch (Throwable e) {     e.printStackTrace();    } finally {     Hack.setAssertionFailureHandler(null);     sIsReflectChecked = true;    }    return false;   }     private static void allClasses() throws HackAssertionException {    AssetManager = Hack.into(AssetManager.class);    ContextImpl = Hack.into("android.app.ContextImpl");   }     private static void allConstructors() throws HackAssertionException {   }     private static void allFields() throws HackAssertionException {    ContextImpl_mResources = ContextImpl.field("mResources").ofType(Resources.class);   }     private static void allMethods() throws HackAssertionException {    AssetManager_addAssetPath = AssetManager.method("addAssetPath", String.class);   }     @Override   public boolean onAssertionFailure(HackAssertionException hackAssertionException) { // throw it    return false;   }    }       </code></pre>    <p>调用 Hacks.defineAndVerify反复进行定义和验证,成功后就可以直接调用了。</p>    <pre>  <code class="language-java">boolean flag = Hacks.defineAndVerify();    if (flag) {      AssetManager assetManager = AssetManager.class.newInstance();      Hacks.AssetManager_addAssetPath.invoke(assetManager,"assetPath");      Hacks.ContextImpl_mResources.set(context, resources);  }</code></pre>    <p>上面的这个例子是伪代码,实际情况自己去把握~~~~写的比较随意,看看就好了~</p>    <p>来自: http://blog.csdn.net/sbsujjbcy/article/details/51280274</p>