以往当Android App出现bug的时候,甚至仅仅是修改一行代码,都要重新发布新版本对bug进行修复,这样带来的缺点是明显的,需要用户重新升级app,覆盖率太慢,成本太高。所以就出现了热修复技术,通过打补丁的方式,通过从服务器下载补丁包,然后对有问题的类中出问题的方法,进行替换,优点是用户无感知修复,无需下载新的应用,代价小。对比其他的热修复方案,来耍一耍阿里-Sophix 。
介绍
“冷热”
- 插件化 - apk 分为宿主和插件部分,插件在需要的时候才加载进来
- 热修复 – 更新的类或者插件粒度较小的时候,我们会称之为热修复,一般用于修复bug
- 热更新 – 2016 Google 的 Android Studio 推出了Instant Run 功能 同时提出了3个名词
- 热部署 – 方法内的简单修改,无需重启app和Activity。
- 暖部署 – app无需重启,但是activity需要重启,比如资源的修改。
- 冷部署 – app需要重启,比如继承关系的改变或方法的签名变化等。
热修复特点
- 无需重新发版,实时高效热修复
- 用户无感知修复,无需下载新的应用,无需重装App,代价小
- 修复成功率高,把损失降到最低
阿里热修复方案对比
方案对比 | Andfix开源版本 | 阿里Hotfix 1.X | 阿里Hotfix最新版 (Sophix) |
---|---|---|---|
方法替换 | 支持,除部分情况[0] | 支持,除部分情况 | 全部支持 |
方法增加减少 | 不支持 | 不支持 | 以冷启动方式支持[1] |
方法反射调用 | 只支持静态方法 | 只支持静态方法 | 以冷启动方式支持 |
即时生效 | 支持 | 支持 | 视情况支持[2] |
多DEX | 不支持 | 支持 | 支持 |
资源更新 | 不支持 | 不支持 | 支持 |
so库更新 | 不支持 | 不支持 | 支持 |
Android版本 | 支持2.3~7.0 | 支持2.3~6.0 | 全部支持包含7.0以上 |
已有机型 | 大部分支持[3] | 大部分支持 | 全部支持 |
安全机制 | 无 | 加密传输及签名校验 | 加密传输及签名校验 |
性能损耗 | 低,几乎无损耗 | 低,几乎无损耗 | 低,仅冷启动情况下有些损耗 |
生成补丁 | 繁琐,命令行操作 | 繁琐,命令行操作 | 便捷,图形化界面 |
补丁大小 | 不大,仅变动的类 | 小,仅变动的方法 | 不大,仅变动的资源和代码[4] |
服务端支持 | 无 | 支持服务端控制[5] | 支持服务端控制 |
说明:
- [0] 部分情况指的是构造方法、参数数目大于8或者参数包括long,double,float基本类型的方法。
- [1] 冷启动方式,指的是需要重启app在下次启动时才能生效。
- [2] 对于Andfix及Hotfix 1.X能够支持的代码变动情况,都能做到即时生效。而对于其他代码变动较大的情况,会走冷启动方式,此时就无法做到即时生效。
- [3] Hotfix 1.X已经支持绝大部分主流手机,只是在X86设备以及修改了虚拟机底层结构的ROM上不支持。
- [4] 由于支持了资源和库,如果有这些方面的更新,就会导致的补丁变大一些,这个是很正常的。并且由于只包含差异的部分,所以补丁已经是最大程度的小了。
- [5] 提供服务端的补丁发布和停发、版本控制和灰度功能,存储开发者上传的补丁包。
其他热修复方案
方案 | 作者 |
---|---|
Tinker | 微信(apk补丁) |
Robust | 美团 |
Amigo | 饿了么(apk补丁) |
Nuwa | 个人开发者 |
Dexposed | |
RocooFix | 个人开发者 |
集成Sophix
注册阿里云账号
- 注册完开发者账号,成功登录后进入控制台,添加移动热修复服务。
开通热修复服务后,跳转到热修复产品界面-App管理,创建App “Sophix测试”,创建完成后会出现两个平台的App列表:iOS和Android
点击管理进入Android平台,在客户端里,需要使用到AppId、APPSecret、RSA密钥
客户端集成
引入maven依赖仓库
在项目app下的build.gradle中添加maven仓库地址和版本依赖添加maven仓库地址:
1
2
3
4
5repositories {
maven {
url "http://maven.aliyun.com/nexus/content/repositories/releases"
}
}添加依赖:
1
compile 'com.aliyun.ams:alicloud-android-hotfix:3.1.2'
添加使用权限
1
2
3
4
5
6<! -- 网络权限 -->
<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"/>配置AndroidManifest文件
在application节点里添加配置,用之前在阿里云上创建的App的配置信息AppId、APPSecret、RSA密钥替换value的值:1
2
3
4
5
6
7
8
9
10
11
12<application>
<meta-data
android:name="com.taobao.android.hotfix.IDSECRET"
android:value="App ID" />
<meta-data
android:name="com.taobao.android.hotfix.APPSECRET"
android:value="App Secret" />
<meta-data
android:name="com.taobao.android.hotfix.RSASECRET"
android:value="RSA密钥" />
···
</application>
可参考官方的动图示例:
- Application接入SDK
其他接口使用请查看SDK文档1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56/**
* 初始化Sophix
*/
private void initSophix()
{
String appVersion;
try
{
appVersion = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
}
catch (Exception e)
{
e.printStackTrace();
appVersion = "1.0.0";
}
SophixManager.getInstance().setContext(this).setAppVersion(appVersion).setAesKey(null).setEnableDebug(true).setPatchLoadStatusStub(new PatchLoadStatusListener()
{
@Override
public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion)
{
// 补丁加载回调信息
StringBuilder msg = new StringBuilder();
msg.append("Mode:").append(mode).append("\n");
msg.append("Code:").append(code).append("\n");
msg.append("Info:").append(info).append("\n");
msg.append("HandlePatchVersion:").append(handlePatchVersion).append("\n");
if (mDisplayListener != null)
mDisplayListener.handle(msg.toString());
// 补丁加载回调通知
switch (code)
{
case PatchStatus.CODE_LOAD_SUCCESS:
// 表明补丁加载成功
break;
case PatchStatus.CODE_LOAD_RELAUNCH:
// 表明新补丁生效需要重启. 开发者可提示用户或者强制重启;
// 建议: 用户可以监听进入后台事件,然后调用killProcessSafely自杀
// 注意:不可以直接Process.killProcess(Process.myPid())来杀进程,这样会扰乱Sophix的内部状态。
break;
case PatchStatus.CODE_LOAD_FAIL:
// 内部引擎异常,推荐此时清空本地补丁,防止失败补丁重复加载
SophixManager.getInstance().cleanPatches();
break;
default:
// 其它错误信息,查看PatchStatus类说明
break;
}
}
}).initialize();
// 加载新的补丁包
SophixManager.getInstance().queryAndLoadNewPatch();
}
至此,Sophix配置完成。
测试
- 客户端第一版本,如图,打包成Sophix_V1.apk
客户端补丁版本,如图,打包成Sophix_V2.apk
生成补丁,生成补丁文档传送门
Windows下载阿里补丁工具SophixPatchTool,运行SophixPatchTool.exe,添加包,如果有签名等设置,则点击设置,配置相应的签名等,然后点击“Go”,生成补丁,即sophix-patch.jar:上传补丁
进入阿里云热修复App管理的Android平台里,即查看AppId、APPSecret、RSA密钥那个页面,添加新版本,成功添加版本后,点击查看详情进入,上传刚刚生成的sophix-patch.jar补丁。本地测试
安装Sophix_V1.apk,同时将补丁sophix-patch.jar放到Android设备的目录里:/sdcard/sophix-patch.jar
,下载hotfixdebug工具,安装后,打开进入调试apk,配置如下:
测试成功
- 发布
进入阿里云的补丁详情页面,点击发布。再次进行调试,这次不用Sophix调试工具;先卸载已安装的Sophix_V1,重新安装,打开后再次等待检测补丁更新,再次出现提示ok。
推广
有兴趣的童鞋可以看看阿里出品的热修复原理宝典