当前位置: 首页 > news >正文

武汉网站优化价格/网上如何推广自己的产品

武汉网站优化价格,网上如何推广自己的产品,做网站用哪种编程语言,网站开发者购物支付模板*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 本节课程主要分为3块: 1.一步步手动实现热修复(一)-dex文件的生成与加载2.一步步手动实现热修复(二)-类的加载机制简要介绍3.一步步手动实现热修复(三)-Class文件的替换 本节示例所用…

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

本节课程主要分为3块:

  • 1.一步步手动实现热修复(一)-dex文件的生成与加载
  • 2.一步步手动实现热修复(二)-类的加载机制简要介绍
  • 3.一步步手动实现热修复(三)-Class文件的替换

本节示例所用到的任何资源都已开源,项目中包含工程中所用到代码、示例图片、说明文档。项目地址为:
https://code.csdn.net/u011064099/sahadevhotfix/tree/master


在上一节了解了基本的类加载原理之后,我们这一节开始对工程内部的类实行替换。

Tips: 本章主要依赖文章http://blog.csdn.net/vurtne_ye/article/details/39666381中的未实现代码实现,实现思路也源自该文章,在阅读本文之前可以先行了解。

这一节我们主要实现的流程有:

  • 在工程内创建相同的ClassStudent类,但在调用getName()方法返回字符串时会稍有区别,用于结果验证
  • 使用DexClassLoader加载外部的user.dex
  • 将DexClassLoader中的dexElements放在PathClassLoader的dexElements之前
  • 验证替换结果

创建工程内的ClassStudent

我们在第一节中演示了如何加载外部的Class,为了起到热修复效果,那么我们需要在工程内有一个被替换的类,被替换的ClassStudent类内容如下:

package com.sahadev.bean;/*** Created by shangbin on 2016/11/24.* Email: sahadev@foxmail.com*/public class ClassStudent {private String name;public ClassStudent() {}public void setName(String name) {this.name = name;}public String getName(){return this.name + ".Miss";}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

外部的ClassStudent类的内容如下:

package com.sahadev.bean;/*** Created by shangbin on 2016/11/24.* Email: sahadev@foxmail.com*/public class ClassStudent {private String name;public ClassStudent() {}public void setName(String name) {this.name = name;}public String getName(){return this.name + ".Mr";   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这两个类除了在getName()方法返回之处有差别之外,其它地方一模一样,不过这足可以让我们说明情况。

我们这里要实现的目的: 我们默认调用getName()方法返回的是“xxxx.Miss”,如果热修复成功,那么再使用该方法的话,返回的则会是“xxxx.Mr”

对含有包名的类再次编译

因为第一节中专门声明了不可以对类声明包名,但是这样在Android工程中无法引用到该类,所以把不能声明包名的问题解决了一下。

不能声明包名的主要原因是在编译Java文件时,没有正确的使用命令。对含有包名的Java文件应当使用以下命令:

javac -d ./ ClassStudent.java
  • 1

经过上面命令编译后的.class文件便可以顺利通过dx工具的转换。

我们还是按照第一节的步骤将转换后的user.dex文件放入工程中并写入本地磁盘,以便稍后使用。

Dex转换注意: 很多同学走到这一步时遇到了问题,这是因为第一章介绍的时候并没有带包名,所以在这里我们所使用的命令的最后一个参数应当携带包的相对路径,例如:

dx –dex –output=user.dex .\com\sahadev\bean\ClassStudent.class

替换工程内的类文件

在开始之前还是再回顾一下实现思路:类在使用之前必须要经过加载器的加载才能够使用,在加载类时会调用自身的findClass()方法进行查找。然而在Android中类的查找使用的是BaseDexClassLoader,BaseDexClassLoader对findClass()方法进行了重写:

    @Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {Class clazz = pathList.findClass(name);if (clazz == null) {throw new ClassNotFoundException(name);}return clazz;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

pathList是类DexPathList的实例,这里pathList.findClass的实现如下:

    public Class findClass(String name) {for (Element element : dexElements) {DexFile dex = element.dexFile;if (dex != null) {Class clazz = dex.loadClassBinaryName(name, definingContext);if (clazz != null) {return clazz;}}}return null;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

由此我们可以得知类的查找是通过遍历dexElements来进行查找的。所以为了实现替换效果,我们需要将DexClassLoader中的Element对象放到dexElements数组的第0个位置,这样才能在BaseDexClassLoader查找类时先找到DexClassLoader所用的user.dex中的类。

Tips: 如果对上面这段内容看不懂的,没关系,可以移步到本系列课程的第二节了解一下类加载的具体流程。

类的加载是从上而下加载的,所以就算是DexClassLoader加载了外部的类,但是在系统使用类的时候还是会先在ClassLoader中查找,如果找不到则会在BaseDexClassLoader中查找,如果再找不到,就会进入PathClassLoader中查找,最后才会使用DexClassLoader进行查找,所以按照这个流程外部类是无法正常发挥作用的。所以我们的目的就是在查找工程内的类之前,先让加载器去外部的dex中查找。

好了,再次梳理了思路之后,我们接下来对思路进行实践。

下面的方法是我们主要的注入方法:

    public String inject(String apkPath) {boolean hasBaseDexClassLoader = true;File file = new File(apkPath);try {Class.forName("dalvik.system.BaseDexClassLoader");} catch (ClassNotFoundException e) {hasBaseDexClassLoader = false;}if (hasBaseDexClassLoader) {PathClassLoader pathClassLoader = (PathClassLoader) getClassLoader();DexClassLoader dexClassLoader = new DexClassLoader(apkPath, file.getParent() + "/optimizedDirectory/", "", pathClassLoader);try {Object dexElements = combineArray(getDexElements(getPathList(pathClassLoader)), getDexElements(getPathList(dexClassLoader)));Object pathList = getPathList(pathClassLoader);setField(pathList, pathList.getClass(), "dexElements", dexElements);return "SUCCESS";} catch (Throwable e) {e.printStackTrace();return android.util.Log.getStackTraceString(e);}}return "SUCCESS";}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Tips: 这段代码原封不动采用于http://blog.csdn.net/vurtne_ye/article/details/39666381文章中最后的实现代码,但是该文章并没有给出具体的注入细节。我们接下里的过程就是对没有给全的细节进行补充与讲解。

这段代码的核心在于将DexClassLoader中的dexElements与PathClassLoader中的dexElements进行合并,然后将合并后的dexElements替换原先的dexElements。最后我们在使用ClassStudent类的时候便可以直接使用外部的ClassStudent,而不会再加载默认的ClassStudent类。

首先我们通过classLoader获取各自的pathList对象:

public Object getPathList(BaseDexClassLoader classLoader) {Class<? extends BaseDexClassLoader> aClass = classLoader.getClass();Class<?> superclass = aClass.getSuperclass();try {Field pathListField = superclass.getDeclaredField("pathList");pathListField.setAccessible(true);Object object = pathListField.get(classLoader);return object;} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在使用以上反射的时候要注意,pathList属性属于基类BaseDexClassLoader。所以如果直接获取DexClassLoader或者PathClassLoader的pathList属性的话,会得到null。

其次是获取pathList对应的dexElements,这里要注意dexElements是个数组对象:

    public Object getDexElements(Object object) {if (object == null)return null;Class<?> aClass = object.getClass();try {Field dexElements = aClass.getDeclaredField("dexElements");dexElements.setAccessible(true);return dexElements.get(object);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

接下来我们将两个数组对象合并成为一个:

    public Object combineArray(Object object, Object object2) {Class<?> aClass = Array.get(object, 0).getClass();Object obj = Array.newInstance(aClass, 2);Array.set(obj, 0, Array.get(object2, 0));Array.set(obj, 1, Array.get(object, 0));return obj;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

上面这段代码我们根据数组对象的类型创建了一个新的大小为2的新数组,并将两个数组的第一个元素取出,将代表外部dex的dexElement放在了第0个位置。这样便可以确保在查找类时优先从外部的dex中查找。

最后将原先的dexElements覆盖:

    public void setField(Object pathList, Class aClass, String fieldName, Object fieldValue) {try {Field declaredField = aClass.getDeclaredField(fieldName);declaredField.setAccessible(true);declaredField.set(pathList, fieldValue);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

验证替换结果

好,我们做完以上的工作之后,写一段代码来进行验证:

    /*** 验证替换类后的效果*/private void demonstrationRawMode() {ClassStudent classStudent = new ClassStudent();classStudent.setName("Lavon");mLog.i(TAG, classStudent.getName());}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果我们没有替换成功的话,那么这里默认使用的是内部的ClassStudent,getName()返回的会是Lavon.Miss
如果我们替换成功的话,那么这里默认使用的是外部的ClassStudent,getName()返回的则会是Lavon.Mr

我们实际运行看下效果:
这里写图片描述

这说明我们已经完成了基本的热修复。有任何疑问欢迎留言。


我建了一个QQ群,欢迎对学习有兴趣的同学加入。我们可以一起探讨、深究、掌握那些我们会用到的技术,让自己不至于太落伍。
这里写图片描述

http://blog.csdn.net/sahadev_/article/details/53363052

http://www.jmfq.cn/news/5088853.html

相关文章:

  • 专业微网站制作/网络推广运营推广
  • 怎么从零开始做网站/软文发布网站
  • 企业做网站大概多少钱/廊坊seo排名收费
  • 台州建设信息港网站/网推拉新app推广接单平台
  • 福州做网站建设/免费html网页模板
  • 吴桥县网站建设价格/北京seo产品
  • 政府网站建设办法/seo网站优化做什么
  • 长春做网站外包/网络营销案例分享
  • 做网站的软件是是什么/成人职业技能培训学校
  • 宁波网站设计建站服务公司/好的推广平台
  • 电脑上制作网站的软件/网络营销策略是什么
  • 电子业网站建设/网站关键词优化教程
  • 自适应网站导航是怎么做的/外链互换平台
  • 做pc端的网站首页尺寸是多少/bt磁力王
  • 杭州政府网站建设/重庆seo关键词优化服务
  • wordpress rss静态化/seo优化怎么做
  • ubuntu vps wordpress/网站内部优化有哪些内容
  • 万万州州微微网站网站建建设设/手机关键词点击排名软件
  • 定州市住房和建设局网站/整站优化seo
  • 广东省建设工程执业中心网站/整合营销案例
  • 做律师事务所网站/百度广告费
  • 大型电子商务网站建设公司/网络热词2021流行语
  • 宝鸡做网站公司/北京优化推广公司
  • 自己建网站做外贸/seo和sem的区别
  • 发布网站需要备案/我想做网络推广找谁
  • 网站公众平台建设方案/seo优化一般多少钱
  • 黄埔b2b网站建设公司/全球最牛的搜索引擎
  • 江油建设局网站/seo推广策划
  • 网站浮动窗口怎么设置/网络营销策划推广公司
  • 网站建设技术方面/哪个平台可以接推广任务