一、为啥用热修复?
Apk难免出现bug。有了bug咋办?
发新版?
强更吗?用户体验不好。不强更?bug怎么修复啊!
再者,发新版要打包、加固、上线、审核等一系列婆婆妈妈的事情,bug肯定不能及时修复。
此时,热修复登场了,短时间查找修复bug,生成补丁上传,一般一小时内就可以解决bug。
小情况,可以即时生效;略大情况,冷启动下次也可以修复在线bug。
二、热修复的选择
国内大厂基本都有自己的热修复工具,So,我们小厂可以选择参考借用。
1、阿里系
AndFix 开源,实时生效
HotFix 阿里百川,未开源,免费、实时生效
Sophix 未开源,商业收费,实时生效/冷启动修复
HotFix是AndFix的优化版本,Sophix是HotFix的优化版本。目前阿里系主推是Sophix。
2、腾讯系
Qzone超级补丁 QQ空间,未开源,冷启动修复
QFix 手Q团队,开源,冷启动修复
Tinker 微信团队,开源,冷启动修复。提供分发管理,基础版免费
3、其他
Robust 美团, 开源,实时修复
Nuwa 大众点评,开源,冷启动修复
Amigo 饿了么,开源,冷启动修复
汇总:选择Tinker或者Sophix。鉴于阿里号称第一Java大厂,所以我选Sophix。
哈哈。其实:
有些人可能考虑免费AndFix、HotFix,但github给出的代码并不好,而且两年多不更新。而且作为它们的升级版,应该选Sophix方案。
Sophix提供了一套更加完美的客户端服务端一体的热更新方案,做到了图形界面一键打包、加密传输、签名校验和服务端控制发布与灰度功能,让你用最少的时间实现最强大可靠的全方位热更新。
三、Sophix的接入
借鉴官方文档and加以提炼补充
引入
gradle远程仓库依赖, 打开项目找到app的build.gradle文件,添加如下配置:
添加maven仓库地址:
repositories {
maven {
url "http://maven.aliyun.com/nexus/content/repositories/releases"
}
}
添加gradle坐标版本依赖:
compile 'com.aliyun.ams:alicloud-android-hotfix:3.2.12'
配置AndroidManifest文件
添加权限
<! -- 网络权限 -->
<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"/>
注意:READ_EXTERNAL_STORAGE权限属于Dangerous Permissions,仅调试工具获取外部补丁需要,不影响 线上发布的补丁加载,调试时请自行做好android6.0以上的运行时权限获取。
替换application的name
<application
android:name="com.my.pkg.SophixStubApplication"
... ...>
... ...
配置id、Secrect、Rsa
//该三项配置也可在SophixApplication中进行配置,配置注意不要多空格或少复制,尤其RSA等问题
<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密钥" /
混淆配置
#基线包使用,生成mapping.txt
-printmapping mapping.txt
#生成的mapping.txt在app/build/outputs/mapping/release路径下,移动到/app路径下
#修复后的项目使用,保证混淆结果一致
#-applymapping mapping.txt
#hotfix
-keep class com.taobao.sophix.**{*;}
-keep class com.ta.utdid2.device.**{*;}
-dontwarn com.alibaba.sdk.android.utils.**
#防止inline
-dontoptimize
引入配置类
/**
* Sophix入口类,专门用于初始化Sophix,不应包含任何业务逻辑。
* 此类必须继承自SophixApplication,onCreate方法不需要实现。
* 此类不应与项目中的其他类有任何互相调用的逻辑,必须完全做到隔离。
* AndroidManifest中设置application为此类,而SophixEntry中设为原先Application类。
* 注意原先Application里不需要再重复初始化Sophix,并且需要避免混淆原先Application类。
* 如有其它自定义改造,请咨询官方后妥善处理。
*/
public class SophixStubApplication extends SophixApplication {
private final String TAG = "SophixStubApplication";
// 此处SophixEntry应指定真正的Application,并且保证RealApplicationStub类名不被混淆。
@Keep
@SophixEntry(BaseApplication.class)
static class RealApplicationStub {
}
//上面这个类不要动
public static final String LOADED = "loaded";
public static final String PRELOADED = "preloaded";
private Context mContext = null;
public static CallBackLoadedPatch callBackLoadedPatch;
public static void getData(CallBackLoadedPatch callBackLoadedPatch){
SophixStubApplication.callBackLoadedPatch = callBackLoadedPatch;
}
public interface CallBackLoadedPatch{
void setData(String s);
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// 如果需要使用MultiDex,需要在此处调用。
// MultiDex.install(this);
mContext = base;
initSophix();
}
private void initSophix() {
String appVersion = "0.0.0";
try {
appVersion = this.getPackageManager()
.getPackageInfo(this.getPackageName(), 0)
.versionName;
} catch (Exception e) {
}
final SophixManager instance = SophixManager.getInstance();
instance.setContext(this)
.setAppVersion(appVersion)
.setSecretMetaData(null, null, null)
.setEnableDebug(true)
.setEnableFullLog()
.setPatchLoadStatusStub(new PatchLoadStatusListener() {
@Override
public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
//handlePatchVersion当前处理的补丁版本号, 0:无 -1:本地补丁 其它:后台补丁
if (code == PatchStatus.CODE_LOAD_SUCCESS) { //加载成功
//如需要判断patch版本,保存加载成功patch版本,可在此处理
} else if (code == PatchStatus.CODE_LOAD_RELAUNCH) { //预加载阶段,需要重启
// 如果需要在后台重启,建议此处用SharePreference保存状态。
} else {
// 其它错误信息, 查看PatchStatus类说明
}
}
}).initialize();
}
}
查询补丁并加载
在代码相应类中,调用以下方法,进去查询并加载补丁
//注意该接口的调用涉及收费,下一部分提供一个简单的降费策略。
queryAndLoadNewPatch()
至此:你便完成了补丁的加载。
四、补丁的生成
需要下载:SophixPatchTool.exe 去使用新旧app去生成差异补丁。
注意事项:
生成补丁时:
高级配置默认选中:
强制冷启动:所以,即时生效不会生效。
检查初始化:
快速打包:
优化资源补丁:
未选中:
不比较资源
不比较So库
设置:基本不动修改。
五、补丁的测试
1、手机安卓old apk
2、手机安卓 Sophix调试工具.apk
3、方式1:通过扫阿里云控制后台二维码测试
方式2:通过补丁copy到手机,引用本地补丁测试
六、补丁的发布
目前阿里云只提供了,官方后台发布、管理补丁,不对外提供相关操作接口,所以我们就用下他们的后台吧。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191223182000445.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hnaGdsZw==,size_16,color_FFFFFF,t_70)
图形界面操作,没啥好说的,提几点注意事项:
1、每个应用版本,对应若干补丁;
2、同一时间段,只会有一个补丁生效,新补丁的的发布会覆盖掉旧补丁。
3、补丁回滚:该版本号下,有过全量发布,而且不是手动点的停止,可以回滚,其他的都不能回滚
4、扫描验证补丁:在发布详情内,我们可以使用测试即将发布的补丁。
5、 过滤机型、统计加载数据等功能都比较一般。
七、优化发布
需求1:只有AndroidX版本出现问题,只想热更X版本怎么办?
需求2:频繁调用 queryAndLoadNewPatch() 引发收费问题怎么办?
此时:我们可以主动提供一个后台接口
请求: 安卓版本号,
返回:补丁id、修复Android版本、是否强更
代码处理:
判断补丁不存在,不处理;
补丁存在,判断安卓版本;补丁版本存在于本地,不处理;
新补丁(包括第一次)存在,判断强更强更,非强更默认更。
八、注意事项
1. Sophix SDK版本
3.2.13 //2020-02-05
支持Testin加固
3.2.11 // AndroidX的资源库兼容
Android 10的加固兼容
3.2.10
3.2.9 //2019-10-18 支持android10系统
3.2.8 //2018-11-30 增加埋点信息
3.2.7 //2018-11-13 补丁包tag feather
sdk稳定性增强
P版本强制稳健接入
3.2.6 //2018-9-19 支持自定义classLoader下的getResourceAsStream
兼容索尼低版本机型资源修复
3.2.4 //2018-6-27 支持安卓P dp3
修复8.x版本JIT问题
修复稳定接入初次启动帮后偶现问题
3.2.3 //2018-5-15 完善崩溃清除机制
修复360加固标志识别问题
2. 阿里云后台相关
注意区分:安卓版本号、引用版本号、补丁版本号、批次号
批次号是补丁的唯一标识,批次号即为回调方法
onLoad(final int mode, final int code, final String info, final int handlePatchVersion)
中 handlePatchVersion