Nuwa热修复实现

from : http://blog.csdn.net/gzejia/article/details/51330663

既然前面的AndFix暂时还不可行,那只能投奔QQ团队的Nuwa了。按照开发思路,小编理应先讲讲Nuwa的优缺再讲讲其使用的,但基于对Nuwa的了解不够深厚,我们还是先看看其具体使用吧。虽然网上已经提供了很多使用解说,但这里小编只为站在低点角度帮到大家填下小坑。

添加Nuwa插件

1.编辑工程的根build.gradle文件

<code class="hljs matlab 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;">buildscript <span class="hljs-cell" style="box-sizing: border-box;">{
    repositories {
        jcenter()
    }</span>
    dependencies <span class="hljs-cell" style="box-sizing: border-box;">{
        classpath <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'com.android.tools.build:gradle:1.2.3'</span>
        classpath <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'cn.jiajixin.nuwa:gradle:1.2.2'</span>
    }</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></ul>

2.在app的build.gradle中添加依赖SDK

<code class="hljs rust 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;">dependencies {
    compile fileTree(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">dir</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'libs'</span>, include: [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'*.jar'</span>])
    testCompile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'junit:junit:4.12'</span>
    compile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'com.android.support:appcompat-v7:23.1.1'</span>
    compile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'cn.jiajixin.nuwa:nuwa:1.0.0'</span>
}

apply plugin: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"cn.jiajixin.nuwa"</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></ul>

此时引用 apply plugin: “cn.jiajixin.nuwa” 将有可能报异常Error:Cannot get property ‘taskDependencies’ on null object,其解决方法是将Gradle Plugin的版本降低至1.2.3就可以了,当然Gradle Version也要相应的降低至2.8。

设置plugin版本


使用Nuwa

1.在自定义Application当中初始化

<code class="hljs cs 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;">@Override
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">attachBaseContext</span>(Context <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">base</span>) {
    super.attachBaseContext(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">base</span>);
    Nuwa.init(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);
    Nuwa.loadPatch(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/sdcard/patch.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><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></ul>

这里有个需要注意的地方是自定义Application必须是直接继承自Application的类,如若自定义类AClazz继承自Application,又自定义类BClazz继承自AClazz并在注册表声明为BClazz,那么就会出现以下异常。也就是我们的初始化操作必须放在直属继承Application的AClazz当中。

<code class="hljs applescript 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;">java.lang.NoClassDefFoundError: Failed resolution <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">of</span>: Lcn/jiajixin/nuwa/Hack;
                                                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">at</span> archmages.github.hotfixsamples.HFApplication.<init>(HFApplication.java:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">17</span>)
                                                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">at</span> archmages.github.hotfixsamples.MyApplication.<init>(MyApplication.java:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">12</span>)
                                                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">at</span> java.lang.reflect.Constructor.newInstance(Native Method)

Caused <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">by</span>: java.lang.ClassNotFoundException: Didn't find <span class="hljs-type" style="box-sizing: border-box;">class</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"cn.jiajixin.nuwa.Hack"</span> <span class="hljs-function_start" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">on</span></span> path: DexPathList[[zip <span class="hljs-type" style="box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/app/archmages.github.hotfixsamples-1/base.apk"</span>],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
                                                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">at</span> dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">56</span>)
                                                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">at</span> java.lang.ClassLoader.loadClass(ClassLoader.java:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">511</span>)
                                                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">at</span> java.lang.ClassLoader.loadClass(ClassLoader.java:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">469</span>)
                                                     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">at</span> archmages.github.hotfixsamples.HFApplication.<init>(HFApplication.java:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">17</span>) 
                                                            ... more</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></ul>

2.运行并成功安装APK 
运行过程中可能会中途报错Execution failed for task ‘app:nuwaClassBeforeDexDebug’并在控制台将会输出以下信息

运行时有误

为解决以上遇到的问题,我们需要在app底下的build.gradle中加入multiDexEnabled true

<code class="hljs bash 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;">defaultConfig {
    applicationId <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"archmages.github.hotfixsamples"</span>
    minSdkVersion <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>
    targetSdkVersion <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">23</span>
    versionCode <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>
    versionName <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"1.0"</span>
    multiDexEnabled <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</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></ul>

顺利运行并安装APK完成之后可以在app\bulid\outputs\目录下发现nuwa\debug\patch\目录。此时我们需要把该目录复制到本地任意位置下,譬如将该目录直接放置到D:\目录下,应该是D:\nuwa\debug\patch\。目录必须是酱紫,否则将无法生成.jar补丁文件。

nuwa目录

补丁文件.jar生成

1.移动hash.txt文件 
在复制好nuwa目录后,若将当前apk视为存在bug的apk,这是我们要把nuwa\debug\目录下的hash.txt文件复制到本地目录D:\nuwa\debug\下。

2.生成补丁命令 
这里小编建议是在执行命令前都应该先Clean以下项目(app\bulid\outputs\ 内容将重置)。之后执行命令只要在项目的根目录下直接执行就可以了(根目录下存在gradlew与gradlew.bat两个文件)。

  • Mac:gradlew clean nuwaDebugPatch -P NuwaDir=D:\nuwa
  • Windows:gradlew.bat clean nuwaDebugPatch -P NuwaDir=D:\nuwa

执行命令过程也未必是一帆丰顺,或许我们会遇到如下问题$ANDROID_HOME is not defined导致失败跳出命令。

<code class="hljs http 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;">FAILURE</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">Build failed with an exception.</span>

<span class="vbnet" style="box-sizing: border-box;">* What went wrong:
Execution failed <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> task <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">':app:nuwaDebugPatch'.</span>
> $ANDROID_HOME <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">not</span> defined

* <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Try</span>:         
Run <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> --stacktrace <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">option</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> the stack trace. Run <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> --info <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">or</span> --debug <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">option</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> more log output.

BUILD FAILED   </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></ul>

以上问题比较好解决,上去百度下说是给‘ANDRIOD_HOME’设置下SDK的目录就OK了。亲测了一下果然可以,命令如下。之后再次执行生成.jar补丁的命令就没什么问题了。如果有发现执行命令结果提示成功但是没有生成补丁文件的,请确保以上操作无误或已经正确修改了相关BUG内容

成功执行命令并在app\bulid\outputs\nuwa\debug目录下生成补丁文件patch.jar的亲,只要把其放置到初始化时指定的补丁获取位置下重启APP即可生效,当然这只是本地操作,最终还是得通过下载实现的。

<code class="hljs bash 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: rgb(0, 0, 136); box-sizing: border-box;">set</span> ANDROID_HOME=D:\个人SDK根目录</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>

聊聊Nuwa情况

回到一开始小编说的,讲完整个引用过程后,就该讲讲Nuwa的其他琐事了。这里先声明只是小编本人的见解,只是聊聊,后面依然会根据使用情况继续更新本块内容。

情况1:部分手机无修复效果 
具体是由于什么原因照成的小编也不是很清楚,只是在测试中发现HTC6.0.1与MEIZU5.1的手机存在该情况。最终的解决方案是将app下bulid.gardle当中的targetSdkVersion值修改为22就可以了,这得感谢我的组长kakash提出的想法哈哈。

情况2:修改.xml文件内容无效 
顺利引用后小编试过增删图片资源,class文件以及.xml文件,结果都能在补丁文件中达到操作效果。但奇怪的是,如果当当只是编辑已有.xml文件内容,却无法生成补丁文件,这是为何?这里又得感谢我的另一个同事wneng,因为这是他发现的问题,并且还从hash.txt文件当中分析为何没能生成补丁文件的缘故,发现其中指定需要被生成为补丁的内容是有限制的,所以才无法生成补丁文件以及修复效果。具体有兴趣的亲可以继续探索下。

情况3:对比AndFix 
可修复文件类型更广阔,AndFix只能对应class文件做修复工作;执行过程并不比AndFix复杂;兼容性处理相对上比AndFix要稳定得多;需要重启APP应用才能生效,AndFix则是当次生效;除此以外Nuwa本身也还有很多不完善的地方,可参考下面内容深入了解。

情况4:patch.jar影响之源远流长 
[160509]为什么说有Nuwa生成的patch.jar补丁影响会源远流长呢?很好解释哈哈,因为原有补丁将会影响应用程序的后继研发。在这里必须加强各补丁的版本控制,要不就得在后继研发中动态控制补丁是否加载。否则就会有一堆莫名奇妙的异常错误出现,让人不知所措。

这里写图片描述

情况5:支持 gradle:1.5.0 
从上面可以发现小编叙述的Nuwa仅仅支持gradle:1.2.3版本。其原因这里就不描述了,或许只是为了跟上2.0的Instance Run。小编满怀欣喜的拿下demo尝试一番,结果发行运行成功后并没有在build下出现传说中的nuwa目录,具体解决方案跟进中。

其他情况:参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值