# 阿里热更新方案

1.什么叫热更新

热更新是一种各大手游等众多App常用的更新方式。简单来说,就是在用户通过App Store下载App之后,打开App时遇到的即时更新。

2.为什么要做热更新

当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App、测试、向各个应用市场和渠道换包、提示用户升级、用户下载、覆盖安装。
重点是还会有原来的版本遗留,无论你怎么提示都有人放弃治疗,不愿意升级,强制不能使用体验又足够糟糕到让人不能启齿。
如果这是一个影响公司收入或者体验影响极其不好的Bug,那完蛋了,可能公司老板会对整个技术团队的技术能力丧失信心,其对技术人员的伤害是致命的。

热更新的方案

技术派系:
• Native,代表有阿里的Dexposed、AndFix与腾讯的内部方案KKFix;
• Java,代表有Qzone的超级补丁、大众点评的nuwa、百度金融的rocooFix, 饿了么的amigo以及美团的robust。
Native流派与Java流派都有着自己的优缺点,它们具体差异大家可参考上文。事实上从来都没有最好的方案,只有最适合自己的。

ClassLoader

我们知道Java在运行时加载对应的类是通过ClassLoader来实现的,ClassLoader本身是一个抽象类,Android中使用PathClassLoader类作为Android的默认的类加载器,
PathClassLoader其实实现的就是简单的从文件系统中加载类文件。PathClassLoade本身继承自BaseDexClassLoader,BaseDexClassLoader重写了findClass方法,
该方法是ClassLoader的核心

@Override
protected Class

实现

上面分析了Android中的类的加载的流程,可以看出来DexPathList对象中的dexElements列表是类加载的一个核心,一个类如果能被成功加载,那么它的dex一定
会出现在dexElements所对应的dex文件中,并且dexElements中出现的顺序也很重要,在dexElements前面出现的dex会被优先加载,一旦Class被加载成功,
就会立即返回,也就是说,我们的如果想做hotpatch,一定要保证我们的hotpacth dex文件出现在dexElements列表的前面。

要实现热更新,就需要我们在运行时去更改PathClassLoader.pathList.dexElements,由于这些属性都是private的,因此需要通过反射来修改。另外,构造我们自己的dex文件
所对应的dexElements数组的时候,我们也可以采取一个比较取巧的方式,就是通过构造一个DexClassLoader对象来加载我们的dex文件,并且调用一次dexClassLoader.loadClass(dummyClassName);
方法,这样,dexClassLoader.pathList.dexElements中,就会包含我们的dex,通过把dexClassLoader.pathList.dexElements插入到系统默认的classLoader.pathList.dexElements列表前面,就可以让系统优先加载我们的dex中的类,从而可以实现热更新了。

说了那么多,下面我们就以阿里百川HotFix热更新集成加使用

首先创建开发者账号,并创建一个应用如下:参数填入到对应的位置在清单文件中
# 阿里热更新方案

1.Androidstutio集成:

首先还是按照阿里文档集成,有可能不成功的(文档上面说了注意: 1.4.0版本的仓库地址已经发生了变更, 请更新到上述百川最新的仓库地址),反正我是没有成功
我的(这是根据阿里给的dome里面配置的):

2.先在project的gradle里面添加:

allprojects {
repositories {
jcenter()
maven {
//百川仓库, ut/utdid
url “http://repo.baichuan-android.taobao.com/content/groups/BaichuanRepositories
}
}
}

然后在module的gradle中添加:

dependencies {
compile ‘com.taobao.android:alisdk-hotfix:1.4.0’
}

3.创建一个Application

/**
* Created by Laer on 2016/12/20.
*/
public class Myapplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HotFixManager.getInstance().setContext(this)
.setAppVersion(“你的版本号”)
.setAppId(“你在开发者平台创建应用的appId”)
.setAesKey(null)//如果对补丁进行了Aes加密,这里就要填上,具体见开发文档
.setSupportHotpatch(true)
.setEnableDebug(true)
.setPatchLoadStatusStub(new PatchLoadStatusListener() {
@Override
public void onload(final int mode, final int code, final String info, final int handlePatchVersion) {
// 补丁加载回调通知
if (code == PatchStatusCode.CODE_SUCCESS_LOAD) {
// TODO: 10/24/16 表明补丁加载成功
} else if (code == PatchStatusCode.CODE_ERROR_NEEDRESTART) {
// TODO: 10/24/16 表明新补丁生效需要重启. 业务方可自行实现逻辑, 提示用户或者强制重启, 建议: 用户可以监听进入后台事件, 然后应用自杀
} else if (code == PatchStatusCode.CODE_ERROR_INNERENGINEFAIL) {
// 内部引擎加载异常, 推荐此时清空本地补丁, 但是不清空本地版本号, 防止失败补丁重复加载
//HotFixManager.getInstance().cleanPatches(false);
} else {
// TODO: 10/25/16 其它错误信息, 查看PatchStatusCode类说明
}
}
}).initialize();
}
}

4.添加网络权限

uses-permission android:name=”android.permission.INTERNET” />
uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” />
uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />
uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE”/>
在清单文件中添加key

至此我们的集成过程就已经完成了,下面进入调试使用阶段

首先我们要创建一个old.apk(也就是有问题的apk)
首先将Myapplication中的.setAppVersion(“1.0”)//设置一个版本号,随便设置,后面再上传补丁的时候会将补丁的版本号改成这个,这两个地方的版本哈要一致
接下来我们发布一个有问题的apk或是说old.apk,并将这个old.apk放到一个单独的地方(我的:C:\Users\Laer\Desktop\oldApk\old.apk),以免发布新版本的时候覆盖这个旧版本(这个old.apk会在生成补丁时用到)
然后更改想要修改的代码,直接发布生成一个new.apk,同理将这个新的apk放到一个特定的位置(我的: C:\Users\Laer\Desktop\newApk\new.apk)

接下来我们就要使用阿里提供的生成补丁的工具了:

http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_windows.zip
下载后解压,点击SophixPatchTool.exe 可能会出现无响应等一下就好
# 阿里热更新方案
设置响应的参数
# 阿里热更新方案

然后点击go,稍等一下,即可生成响应的补丁:

然后登陆阿里云找到对应的移动热修复进行如下操作即可
# 阿里热更新方案

# 阿里热更新方案

这样一个完整的热修复就做完了,如有疑问请移步到https://help.aliyun.com/document_detail/53247.html?spm=5176.product51340.6.549.ZMQ9JH