前面几篇博文已经介绍了2种热修复框架的使用及源码分析,AndFix兼容性比较好,而Dexposed Art处于Beta版。
AndFix和Dexposed都是阿里的开源项目。
Alibaba-AndFix Bug热修复框架的使用
Alibaba-AndFix Bug热修复框架原理及源码解析
Alibaba-Dexposed框架在线热补丁修复的使用
Alibaba-Dexposed Bug框架原理及源码解析
今天主要介绍的框架是根据腾讯的博客使用ClassLoader写的热修复框架。
腾讯博客:【新技能get】让App像Web一样发布新版本
首先,看需要修复的类部分:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">package</span> cn.coolspan.open.fixbug; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.io.File; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.app.Activity; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.os.Bundle; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.os.Environment; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.util.Log; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.view.View; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.view.View.OnClickListener; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.widget.Toast; <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * MainActivity 2015-12-22 下午10:30:57 * *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @author</span> 乔晓松 965266509@qq.com */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">class</span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">MainActivity</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">extends</span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">Activity</span> {</span> <span class="hljs-annotation" style="color:#9b859d;box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>(Bundle savedInstanceState) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">super</span>.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.button1).setOnClickListener(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> OnClickListener() { <span class="hljs-annotation" style="color:#9b859d;box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View view) { MyApplication myApplication = (MyApplication) getApplication(); File patch = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> File( Environment.getExternalStorageDirectory(), <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"patch.jar"</span>); Log.e(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"file:"</span>, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">""</span> + patch.exists()); myApplication.fixBugManage.addPatch(patch.getAbsolutePath()); } }); findViewById(R.id.button2).setOnClickListener(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> OnClickListener() { <span class="hljs-annotation" style="color:#9b859d;box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View view) { <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//修复此位置的bug</span> Toast.makeText(MainActivity.<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"...bug..."</span>, Toast.LENGTH_SHORT).show(); } }); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li></ul>
以上是手机上安装的apk存在bug的位置。
接下,是修复完成Bug后的类:
<code class="hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-attribute" style="box-sizing: border-box;">...</span><span class="hljs-attribute" style="box-sizing: border-box;">...</span> <span class="hljs-attribute" style="box-sizing: border-box;">...</span><span class="hljs-attribute" style="box-sizing: border-box;">...</span> findViewById(R<span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">.</span>id<span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">.</span>button2)<span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">.</span>setOnClickListener(<span class="hljs-literal" style="color:#06666;box-sizing: border-box;">new</span> OnClickListener() { @Override <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-literal" style="color:#06666;box-sizing: border-box;">void</span> onClick(View view) { Toast<span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">.</span>makeText(MainActivity<span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">.</span>this, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"fix...bug..."</span>, Toast<span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">.</span>LENGTH_SHORT)<span class="hljs-built_in" style="color:#66066;box-sizing: border-box;">.</span>show(); } }); <span class="hljs-attribute" style="box-sizing: border-box;">...</span><span class="hljs-attribute" style="box-sizing: border-box;">...</span> <span class="hljs-attribute" style="box-sizing: border-box;">...</span><span class="hljs-attribute" style="box-sizing: border-box;">...</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>
修复好了,build工程(工具也会自动build),把java编译成class文件。
由于我使用debug模式调试安装的apk,所以我build完成后找的也是debug下的class文件,如下:
红色框标注的部分就是MainActivity build完成后生成class文件,如果你想问我怎么是三个class文件,原因是:onCreate中有2个注册的点击时间监听器,每个监听器都生成了一个新的class文件。
把相关修复bug的类的class文件复制到一个文件下(fixbugdex),当前我也保存了class所在的包。如下:
以下,拷贝方式不可取:
如果在工具中看class文件,效果如下:
这里看到的仅有一个MainActivity.class,切记,这是工具为了方便你查看class文件,显示上做了处理。不能从此位置单独一个个class文件拷贝,例如从此位置单独拷贝出MainActivity.class,这个class就不是完成的类了,文件内容如下:
所以此方式不可取,当然可以直接拷贝整个包。
然后cmd到刚才的fixbugdex文件
然后执行命令 jar cvf fixbug.jar cn/*
这条命令就是把cn下的所有文件打包到fixbug.jar文件中
执行完成后:
查看fixbug.jar内容:
接下,需要把jar文件转换成dex文件:
工具:dx
下载工具并解压到AndroidSdk–>platform-tools目录
同时,也可以把fixbug.jar文件拷贝到AndroidSdk–>platform-tools目录,然后你也可以使用绝对路径.
cmd到AndroidSdk–>platform-tools目录下执行命令:
<code class="hljs brainfuck has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color:#8800;box-sizing: border-box;">dx</span> <span class="hljs-literal" style="color:#06666;box-sizing: border-box;">-</span><span class="hljs-literal" style="color:#06666;box-sizing: border-box;">-</span><span class="hljs-comment" style="color:#8800;box-sizing: border-box;">dex</span> <span class="hljs-literal" style="color:#06666;box-sizing: border-box;">-</span><span class="hljs-literal" style="color:#06666;box-sizing: border-box;">-</span><span class="hljs-comment" style="color:#8800;box-sizing: border-box;">output</span> <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">patch</span><span class="hljs-string" style="color:#0880;box-sizing: border-box;">.</span><span class="hljs-comment" style="color:#8800;box-sizing: border-box;">jar</span> <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">fixbug</span><span class="hljs-string" style="color:#0880;box-sizing: border-box;">.</span><span class="hljs-comment" style="color:#8800;box-sizing: border-box;">jar</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
注:–output 后面可以接绝对路径。
执行完成后的结果:
查看一下patch.jar文件的内容:
打开应用执行Toast按钮:
我为了测试方便,把patch.jar文件放到了sdcard根目录中,当然也可以选择网上下载的方式,其实都是一样的。
启动后效果如下:
然后,点击加载补丁文件,并推出应用重新进入,并点击Toast按钮:
到此,bug已经被修复完成。
Api接口介绍:
首先,把FixBugManage.java文件引入到你的项目中
首先,在自定义Application中初始化:
init(versionCode);
当versionCode与之前的versionCode不同,会自动清除掉之前addPatch所有的补丁文件
当versionCode与之前的versionCode相同,会自动加载之前addPatch所有的补丁文件
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">package</span> cn.coolspan.open.fixbug; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.app.Application; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">class</span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">MyApplication</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">extends</span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">Application</span> {</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> FixBugManage fixBugManage; <span class="hljs-annotation" style="color:#9b859d;box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>() { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">super</span>.onCreate(); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.fixBugManage = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> FixBugManage(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.fixBugManage.init(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"1.0"</span>); } } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
添加新补丁文件接口:
addPatch(patchPath);
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> MyApplication myApplication = (MyApplication) getApplication()<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">;</span> File patch = new File( Environment<span class="hljs-preprocessor" style="color:#444444;box-sizing: border-box;">.getExternalStorageDirectory</span>(), <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"patch.jar"</span>)<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">;</span> myApplication<span class="hljs-preprocessor" style="color:#444444;box-sizing: border-box;">.fixBugManage</span><span class="hljs-preprocessor" style="color:#444444;box-sizing: border-box;">.addPatch</span>(patch<span class="hljs-preprocessor" style="color:#444444;box-sizing: border-box;">.getAbsolutePath</span>())<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
清除所有补丁文件的接口:
<code class="hljs dos has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color:#8800;box-sizing: border-box;">removeAllPatch();</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
到此接口已介绍完。
中途遇到的坑:
执行jar cvf fixbug.jar cn/*
异常:bad class file magic (cafebabe) or version (0033.0000)
解决方法:在build.gradle中jdk的版本修改为1.6
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> compileOptions { sourceCompatibility JavaVersion<span class="hljs-preprocessor" style="color:#444444;box-sizing: border-box;">.VERSION</span>_1_6 targetCompatibility JavaVersion<span class="hljs-preprocessor" style="color:#444444;box-sizing: border-box;">.VERSION</span>_1_6 }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
FixBugManage源码分析:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">package</span> cn.coolspan.open.fixbug; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.io.BufferedInputStream; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.io.BufferedOutputStream; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.io.File; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.io.FileInputStream; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.io.FileOutputStream; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.io.IOException; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.io.OutputStream; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.lang.reflect.Array; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.lang.reflect.Field; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.math.BigInteger; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> java.security.MessageDigest; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> dalvik.system.DexClassLoader; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> dalvik.system.PathClassLoader; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.content.Context; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">import</span> android.content.SharedPreferences; <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * FixBugManage 2015-12-22 下午9:59:28 * *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @author</span> 乔晓松 965266509@qq.com */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">class</span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">FixBugManage</span> {</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> Context context; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> BUF_SIZE = <span class="hljs-number" style="color:#06666;box-sizing: border-box;">2048</span>; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> File patchs; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> File patchsOptFile; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">FixBugManage</span>(Context context) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.context = context; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.patchs = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> File(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.context.getFilesDir(), <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"patchs"</span>);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 存放补丁文件</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.patchsOptFile = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> File(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.context.getFilesDir(), <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"patchsopt"</span>);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 存放预处理补丁文件压缩处理后的dex文件</span> } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * 初始化版本号 * *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @param</span> versionCode */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">init</span>(String versionCode) { SharedPreferences sharedPreferences = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.context .getSharedPreferences(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"fixbug"</span>, Context.MODE_PRIVATE); String oldVersionCode = sharedPreferences .getString(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"versionCode"</span>, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (oldVersionCode == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span> || !oldVersionCode.equalsIgnoreCase(versionCode)) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.initPatchsDir();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 初始化补丁文件目录</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.clearPaths();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 清楚所有的补丁文件</span> sharedPreferences.edit().clear().putString(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"versionCode"</span>, versionCode) .commit();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 存储版本号</span> } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.loadPatchs();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 加载已经添加的补丁文件(.jar)</span> } } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * 读取补丁文件夹并加载 */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loadPatchs</span>() { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (patchs.exists() && patchs.isDirectory()) {<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 判断文件是否存在并判断是否是文件夹</span> File patchFiles[] = patchs.listFiles();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 获取文件夹下的所有的文件</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>; i < patchFiles.length; i++) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (patchFiles[i].getName().lastIndexOf(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">".jar"</span>) == patchFiles[i] .getName().length() - <span class="hljs-number" style="color:#06666;box-sizing: border-box;">4</span>) {<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 仅处理.jar文件</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.loadPatch(patchFiles[i].getAbsolutePath());<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 加载jar文件</span> } } } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.initPatchsDir(); } } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * 加载单个补丁文件 * *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @param</span> patchPath */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loadPatch</span>(String patchPath) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">try</span> { injectDexAtFirst(patchPath, patchsOptFile.getAbsolutePath());<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 读取jar文件中dex内容</span> } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">catch</span> (Exception e) { e.printStackTrace(); } } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * patch所在文件目录 * *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @param</span> patchPath */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">addPatch</span>(String patchPath) { File inFile = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> File(patchPath); File outFile = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> File(patchs, inFile.getName()); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.copyFile(outFile, inFile); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.loadPatch(patchPath); } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * 移除所有的patch文件 */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">removeAllPatch</span>() { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.clearPaths(); } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * 清除所有的补丁文件 */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">clearPaths</span>() { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (patchs.exists() && patchs.isDirectory()) { File patchFiles[] = patchs.listFiles(); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>; i < patchFiles.length; i++) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (patchFiles[i].getName().lastIndexOf(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">".jar"</span>) == patchFiles[i] .getName().length() - <span class="hljs-number" style="color:#06666;box-sizing: border-box;">4</span>) { patchFiles[i].delete(); } } } } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * 初始化存放补丁的文件目录 */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">initPatchsDir</span>() { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (!<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.patchs.exists()) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.patchs.mkdirs(); } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (!<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.patchsOptFile.exists()) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>.patchsOptFile.mkdirs(); } } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * 复制文件从inFile到outFile * *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @param</span> outFile *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @param</span> inFile *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @return</span> */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">copyFile</span>(File outFile, File inFile) { BufferedInputStream bis = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>; OutputStream dexWriter = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">try</span> { MessageDigest digests = MessageDigest.getInstance(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"MD5"</span>); bis = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> BufferedInputStream(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> FileInputStream(inFile)); dexWriter = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> BufferedOutputStream(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> FileOutputStream(outFile)); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">byte</span>[] buf = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">byte</span>[BUF_SIZE]; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> len; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">while</span> ((len = bis.read(buf, <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>, BUF_SIZE)) > <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>) { digests.update(buf, <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>, len); dexWriter.write(buf, <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>, len); } dexWriter.close(); bis.close(); BigInteger bi = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> BigInteger(<span class="hljs-number" style="color:#06666;box-sizing: border-box;">1</span>, digests.digest()); String result = bi.toString(<span class="hljs-number" style="color:#06666;box-sizing: border-box;">16</span>); File toFile = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> File(outFile.getParentFile(), result + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">".jar"</span>); outFile.renameTo(toFile); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>; } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">catch</span> (Exception e) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (dexWriter != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">try</span> { dexWriter.close(); } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">catch</span> (IOException ioe) { ioe.printStackTrace(); } } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (bis != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">try</span> { bis.close(); } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">catch</span> (IOException ioe) { ioe.printStackTrace(); } } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>; } } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">injectDexAtFirst</span>(String dexPath, String defaultDexOptPath) <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throws</span> NoSuchFieldException, IllegalAccessException, ClassNotFoundException { DexClassLoader dexClassLoader = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> DexClassLoader(dexPath, defaultDexOptPath, dexPath, getPathClassLoader());<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 把dexPath文件补丁处理后放入到defaultDexOptPath目录中</span> Object baseDexElements = getDexElements(getPathList(getPathClassLoader()));<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 获取当面应用Dex的内容</span> Object newDexElements = getDexElements(getPathList(dexClassLoader));<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 获取补丁文件Dex的内容</span> Object allDexElements = combineArray(newDexElements, baseDexElements);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 把当前apk的dex和补丁文件的dex进行合并</span> Object pathList = getPathList(getPathClassLoader());<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 获取当前的patchList对象</span> setField(pathList, pathList.getClass(), <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"dexElements"</span>, allDexElements);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 利用反射设置对象的值</span> } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> PathClassLoader <span class="hljs-title" style="box-sizing: border-box;">getPathClassLoader</span>() { PathClassLoader pathClassLoader = (PathClassLoader) FixBugManage.class .getClassLoader();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 获取类加载器</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> pathClassLoader; } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> Object <span class="hljs-title" style="box-sizing: border-box;">getDexElements</span>(Object paramObject) <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throws</span> IllegalArgumentException, NoSuchFieldException, IllegalAccessException { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> getField(paramObject, paramObject.getClass(), <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"dexElements"</span>);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 利用反射获取到dexElements属性</span> } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> Object <span class="hljs-title" style="box-sizing: border-box;">getPathList</span>(Object baseDexClassLoader) <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throws</span> IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> getField(baseDexClassLoader, Class.forName(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"dalvik.system.BaseDexClassLoader"</span>), <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"pathList"</span>);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 利用反射获取到pathList属性</span> } <span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/** * 此方法是合并2个数组,把补丁dex中的内容放到数组最前,达到修复bug的目的 * *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @param</span> firstArray *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @param</span> secondArray *<span class="hljs-javadoctag" style="color:#66066;box-sizing: border-box;"> @return</span> */</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> Object <span class="hljs-title" style="box-sizing: border-box;">combineArray</span>(Object firstArray, Object secondArray) { Class<?> localClass = firstArray.getClass().getComponentType(); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> firstArrayLength = Array.getLength(firstArray); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> allLength = firstArrayLength + Array.getLength(secondArray); Object result = Array.newInstance(localClass, allLength); <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> k = <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>; k < allLength; ++k) { <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (k < firstArrayLength) { Array.set(result, k, Array.get(firstArray, k)); } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> { Array.set(result, k, Array.get(secondArray, k - firstArrayLength)); } } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> result; } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> Object <span class="hljs-title" style="box-sizing: border-box;">getField</span>(Object obj, Class<?> cl, String field) <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throws</span> NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field localField = cl.getDeclaredField(field); localField.setAccessible(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 强制反射</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> localField.get(obj);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 获取值</span> } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setField</span>(Object obj, Class<?> cl, String field, Object value) <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throws</span> NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field localField = cl.getDeclaredField(field); localField.setAccessible(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 强制反射</span> localField.set(obj, value);<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 设置值</span> } } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li><li style="box-sizing: border-box; padding: 0px 5px;">111</li><li style="box-sizing: border-box; padding: 0px 5px;">112</li><li style="box-sizing: border-box; padding: 0px 5px;">113</li><li style="box-sizing: border-box; padding: 0px 5px;">114</li><li style="box-sizing: border-box; padding: 0px 5px;">115</li><li style="box-sizing: border-box; padding: 0px 5px;">116</li><li style="box-sizing: border-box; padding: 0px 5px;">117</li><li style="box-sizing: border-box; padding: 0px 5px;">118</li><li style="box-sizing: border-box; padding: 0px 5px;">119</li><li style="box-sizing: border-box; padding: 0px 5px;">120</li><li style="box-sizing: border-box; padding: 0px 5px;">121</li><li style="box-sizing: border-box; padding: 0px 5px;">122</li><li style="box-sizing: border-box; padding: 0px 5px;">123</li><li style="box-sizing: border-box; padding: 0px 5px;">124</li><li style="box-sizing: border-box; padding: 0px 5px;">125</li><li style="box-sizing: border-box; padding: 0px 5px;">126</li><li style="box-sizing: border-box; padding: 0px 5px;">127</li><li style="box-sizing: border-box; padding: 0px 5px;">128</li><li style="box-sizing: border-box; padding: 0px 5px;">129</li><li style="box-sizing: border-box; padding: 0px 5px;">130</li><li style="box-sizing: border-box; padding: 0px 5px;">131</li><li style="box-sizing: border-box; padding: 0px 5px;">132</li><li style="box-sizing: border-box; padding: 0px 5px;">133</li><li style="box-sizing: border-box; padding: 0px 5px;">134</li><li style="box-sizing: border-box; padding: 0px 5px;">135</li><li style="box-sizing: border-box; padding: 0px 5px;">136</li><li style="box-sizing: border-box; padding: 0px 5px;">137</li><li style="box-sizing: border-box; padding: 0px 5px;">138</li><li style="box-sizing: border-box; padding: 0px 5px;">139</li><li style="box-sizing: border-box; padding: 0px 5px;">140</li><li style="box-sizing: border-box; padding: 0px 5px;">141</li><li style="box-sizing: border-box; padding: 0px 5px;">142</li><li style="box-sizing: border-box; padding: 0px 5px;">143</li><li style="box-sizing: border-box; padding: 0px 5px;">144</li><li style="box-sizing: border-box; padding: 0px 5px;">145</li><li style="box-sizing: border-box; padding: 0px 5px;">146</li><li style="box-sizing: border-box; padding: 0px 5px;">147</li><li style="box-sizing: border-box; padding: 0px 5px;">148</li><li style="box-sizing: border-box; padding: 0px 5px;">149</li><li style="box-sizing: border-box; padding: 0px 5px;">150</li><li style="box-sizing: border-box; padding: 0px 5px;">151</li><li style="box-sizing: border-box; padding: 0px 5px;">152</li><li style="box-sizing: border-box; padding: 0px 5px;">153</li><li style="box-sizing: border-box; padding: 0px 5px;">154</li><li style="box-sizing: border-box; padding: 0px 5px;">155</li><li style="box-sizing: border-box; padding: 0px 5px;">156</li><li style="box-sizing: border-box; padding: 0px 5px;">157</li><li style="box-sizing: border-box; padding: 0px 5px;">158</li><li style="box-sizing: border-box; padding: 0px 5px;">159</li><li style="box-sizing: border-box; padding: 0px 5px;">160</li><li style="box-sizing: border-box; padding: 0px 5px;">161</li><li style="box-sizing: border-box; padding: 0px 5px;">162</li><li style="box-sizing: border-box; padding: 0px 5px;">163</li><li style="box-sizing: border-box; padding: 0px 5px;">164</li><li style="box-sizing: border-box; padding: 0px 5px;">165</li><li style="box-sizing: border-box; padding: 0px 5px;">166</li><li style="box-sizing: border-box; padding: 0px 5px;">167</li><li style="box-sizing: border-box; padding: 0px 5px;">168</li><li style="box-sizing: border-box; padding: 0px 5px;">169</li><li style="box-sizing: border-box; padding: 0px 5px;">170</li><li style="box-sizing: border-box; padding: 0px 5px;">171</li><li style="box-sizing: border-box; padding: 0px 5px;">172</li><li style="box-sizing: border-box; padding: 0px 5px;">173</li><li style="box-sizing: border-box; padding: 0px 5px;">174</li><li style="box-sizing: border-box; padding: 0px 5px;">175</li><li style="box-sizing: border-box; padding: 0px 5px;">176</li><li style="box-sizing: border-box; padding: 0px 5px;">177</li><li style="box-sizing: border-box; padding: 0px 5px;">178</li><li style="box-sizing: border-box; padding: 0px 5px;">179</li><li style="box-sizing: border-box; padding: 0px 5px;">180</li><li style="box-sizing: border-box; padding: 0px 5px;">181</li><li style="box-sizing: border-box; padding: 0px 5px;">182</li><li style="box-sizing: border-box; padding: 0px 5px;">183</li><li style="box-sizing: border-box; padding: 0px 5px;">184</li><li style="box-sizing: border-box; padding: 0px 5px;">185</li><li style="box-sizing: border-box; padding: 0px 5px;">186</li><li style="box-sizing: border-box; padding: 0px 5px;">187</li><li style="box-sizing: border-box; padding: 0px 5px;">188</li><li style="box-sizing: border-box; padding: 0px 5px;">189</li><li style="box-sizing: border-box; padding: 0px 5px;">190</li><li style="box-sizing: border-box; padding: 0px 5px;">191</li><li style="box-sizing: border-box; padding: 0px 5px;">192</li><li style="box-sizing: border-box; padding: 0px 5px;">193</li><li style="box-sizing: border-box; padding: 0px 5px;">194</li><li style="box-sizing: border-box; padding: 0px 5px;">195</li><li style="box-sizing: border-box; padding: 0px 5px;">196</li><li style="box-sizing: border-box; padding: 0px 5px;">197</li><li style="box-sizing: border-box; padding: 0px 5px;">198</li><li style="box-sizing: border-box; padding: 0px 5px;">199</li><li style="box-sizing: border-box; padding: 0px 5px;">200</li><li style="box-sizing: border-box; padding: 0px 5px;">201</li><li style="box-sizing: border-box; padding: 0px 5px;">202</li><li style="box-sizing: border-box; padding: 0px 5px;">203</li><li style="box-sizing: border-box; padding: 0px 5px;">204</li><li style="box-sizing: border-box; padding: 0px 5px;">205</li><li style="box-sizing: border-box; padding: 0px 5px;">206</li><li style="box-sizing: border-box; padding: 0px 5px;">207</li><li style="box-sizing: border-box; padding: 0px 5px;">208</li><li style="box-sizing: border-box; padding: 0px 5px;">209</li><li style="box-sizing: border-box; padding: 0px 5px;">210</li><li style="box-sizing: border-box; padding: 0px 5px;">211</li><li style="box-sizing: border-box; padding: 0px 5px;">212</li><li style="box-sizing: border-box; padding: 0px 5px;">213</li><li style="box-sizing: border-box; padding: 0px 5px;">214</li><li style="box-sizing: border-box; padding: 0px 5px;">215</li><li style="box-sizing: border-box; padding: 0px 5px;">216</li><li style="box-sizing: border-box; padding: 0px 5px;">217</li><li style="box-sizing: border-box; padding: 0px 5px;">218</li><li style="box-sizing: border-box; padding: 0px 5px;">219</li><li style="box-sizing: border-box; padding: 0px 5px;">220</li><li style="box-sizing: border-box; padding: 0px 5px;">221</li><li style="box-sizing: border-box; padding: 0px 5px;">222</li><li style="box-sizing: border-box; padding: 0px 5px;">223</li><li style="box-sizing: border-box; padding: 0px 5px;">224</li><li style="box-sizing: border-box; padding: 0px 5px;">225</li><li style="box-sizing: border-box; padding: 0px 5px;">226</li><li style="box-sizing: border-box; padding: 0px 5px;">227</li><li style="box-sizing: border-box; padding: 0px 5px;">228</li><li style="box-sizing: border-box; padding: 0px 5px;">229</li><li style="box-sizing: border-box; padding: 0px 5px;">230</li><li style="box-sizing: border-box; padding: 0px 5px;">231</li><li style="box-sizing: border-box; padding: 0px 5px;">232</li><li style="box-sizing: border-box; padding: 0px 5px;">233</li><li style="box-sizing: border-box; padding: 0px 5px;">234</li><li style="box-sizing: border-box; padding: 0px 5px;">235</li><li style="box-sizing: border-box; padding: 0px 5px;">236</li><li style="box-sizing: border-box; padding: 0px 5px;">237</li><li style="box-sizing: border-box; padding: 0px 5px;">238</li><li style="box-sizing: border-box; padding: 0px 5px;">239</li><li style="box-sizing: border-box; padding: 0px 5px;">240</li><li style="box-sizing: border-box; padding: 0px 5px;">241</li><li style="box-sizing: border-box; padding: 0px 5px;">242</li><li style="box-sizing: border-box; padding: 0px 5px;">243</li><li style="box-sizing: border-box; padding: 0px 5px;">244</li><li style="box-sizing: border-box; padding: 0px 5px;">245</li><li style="box-sizing: border-box; padding: 0px 5px;">246</li><li style="box-sizing: border-box; padding: 0px 5px;">247</li><li style="box-sizing: border-box; padding: 0px 5px;">248</li><li style="box-sizing: border-box; padding: 0px 5px;">249</li><li style="box-sizing: border-box; padding: 0px 5px;">250</li><li style="box-sizing: border-box; padding: 0px 5px;">251</li><li style="box-sizing: border-box; padding: 0px 5px;">252</li><li style="box-sizing: border-box; padding: 0px 5px;">253</li><li style="box-sizing: border-box; padding: 0px 5px;">254</li><li style="box-sizing: border-box; padding: 0px 5px;">255</li><li style="box-sizing: border-box; padding: 0px 5px;">256</li></ul>
如有bug或者不足,可以即时告知我,我会即时修改。
原文地址: http://blog.csdn.net/qxs965266509/article/details/50390325