热修复概述
近 2 年来,热修复技术飞速发展。毕竟每次一个小版本的更新都要通过发布 apk 来实现,这样用户使用感可以说也是非常差了。怎么让客户不去重新下载一个 apk 而实现一个小版本或者一次小 bug 的修复,因此,热修复应运而生。
特别是 android studio 2.0 版本后 推出了 Instant Run 这个功能,关于 Instant Run 可以看 郭大的博文。从此,各种热修复热更新技术相继出现,国内比较成熟的主流 APP 都拥有自己的热修复技术,像支付宝、QQ、微信、美团等。
之前的热修复一般只支持代码热修复,而不支持资源热修复。代码热修复只是针对一些逻辑性错误的代码修改,到了后面又相继出现资源热修复,以及 so 热修复。本文主要是说阿里的 sophix ,所以就拿阿里的各版本热修复来说明比较。具体看下图:
基本可以看清楚,阿里从 Andfix 到最新的 Sophix 正在逐步完善。
而本文就将介绍,如何在 Android 项目中集成 Sophix 以及 如何使用Sophix。
Sophix 集成和准备
集成准备
工具:android studio
环境:jdk 1.8
找到项目的 build.gradle 直接添加 maven 仓库地址:
12345repositories {maven {url "http://maven.aliyun.com/nexus/content/repositories/releases"}}然后找到 app 的 gradle 添加版本依赖:
1compile 'com.aliyun.ams:alicloud-android-hotfix:3.2.2'点击一波 sync now,完成配置。
权限说明
Siphix 需要用到 4 个基本权限:
123456<! -- 网络权限 --><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"/>第四个权限是属于 Dangerous Permissions,所以需要在 android 6.0 的版本以上进行动态权限获取。
混淆配置
需要在 proguard-rules.pro 混淆文件中加入混淆代码
12345678#hotfix-keep class com.taobao.sophix.**{*;}-keep class com.ta.utdid2.device.**{*;}#防止inline-dontoptimize-keepclassmembers class com.zyue.zyueapp.base.BaseApplication {public <init>();}Sophix 的稳健初始化方式
本文采用 Sophix 的最新版本初始化方式,该方法显得更加简单明了,而且跟原始的自己所加载的 Application 不会造成冲突。这样使得原先真正的 Application 也可以热修复,并且减少了补丁预加载的时间,同时还兼容了 Aandroid 8.0 以后的版本。
具体就是要我们自己加入一个类:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859package com.my.pkg;import android.app.Application;import android.content.Context;import android.support.annotation.Keep;import android.util.Log;import com.taobao.sophix.PatchStatus;import com.taobao.sophix.SophixApplication;import com.taobao.sophix.SophixEntry;import com.taobao.sophix.SophixManager;import com.taobao.sophix.listener.PatchLoadStatusListener;import com.my.pkg.MyRealApplication;/*** Sophix入口类,专门用于初始化Sophix,不应包含任何业务逻辑。* 此类必须继承自SophixApplication,onCreate方法不需要实现。* 此类不应与项目中的其他类有任何互相调用的逻辑,必须完全做到隔离。* AndroidManifest中设置application为此类,而SophixEntry中设为原先Application类。* 注意原先Application里不需要再重复初始化Sophix,并且需要避免混淆原先Application类。* 如有其它自定义改造,请咨询官方后妥善处理。*/public class SophixStubApplication extends SophixApplication {private final String TAG = "SophixStubApplication";// 此处SophixEntry应指定真正的Application,并且保证RealApplicationStub类名不被混淆。static class RealApplicationStub {}protected void attachBaseContext(Context base) {super.attachBaseContext(base);// 如果需要使用MultiDex,需要在此处调用。// MultiDex.install(this);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() {public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {if (code == PatchStatus.CODE_LOAD_SUCCESS) {Log.i(TAG, "sophix load patch success!");} else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {// 如果需要在后台重启,建议此处用SharePreference保存状态。Log.i(TAG, "sophix preload patch success. restart app to make effect.");}}}).initialize();}}这边的初始化动作一定要放在 attachBaseContext 中进行,onCreate 不需要自行实现。并且如果项目中因为方法类过多,超过 64K ,需要使用到MultiDex,就必须把该方法放到初始化动作之前,也就是上类中注释掉的部分。
在这个类中,关键一点要加入自己写的 Application.
123static class RealApplicationStub {}这里的 MyRealApplication 就换成自己写的 Application。
为了防止自己写的 Application 和 这个类混淆,在 proguard 文件中加入以下混淆代码:
12345-keepclassmembers class com.my.pkg.MyRealApplication {public <init>();}# 如果不使用android.support.annotation.Keep则需加上此行# -keep class com.my.pkg.SophixStubApplication$RealApplicationStub最后,将 AndoridManifest.xml 中的 application 的 name 换成这个类名。
1234<applicationandroid:name="com.my.pkg.SophixStubApplication"... ...>... ...最为关键的一步:
到此处,稳健接入初始化,还差一个步骤,就是进行补丁下拉,也就是 queryAndLoadNewPatch 这个方法的调用。我个人是直接放到了自己写的 Application onCreate中,不建议放到其他方法类下。
或者自己写个线程进行间隔拉取补丁进行热修复。
12345public void onCreate() {super.onCreate();SophixManager.getInstance().queryAndLoadNewPatch();}到这里,这样除了一个 setSecretMetaData 没有配置,其他都配置 OK 了。setSecretMetaData 里面的参数,需要在阿里控制台进行其他操作才能进行。
若有不理解处,可以具体查看官方官方技术文档。
Sophix 具体使用
首先进入阿里云的移动研发平台。找到移动热修复功能点,或者搜索。
点击添加产品
填写产品信息,创建完成后,点击该产品进入。
点击添加应用
app 名称和包名跟自己项目的保持一致,然后创建。
这里可以看到项目中所需要的 AppSecret,还有2 个参数,就点击下载 aliyun-emas-services.json,打开找 到 IDSECRET ,APPSECRET ,RSASECRET 这 3 个参数,写入到一开始稳健接入 SophixStubApplication 类中。主要设置为 setSecretMetaData 方法。
123456789101112131415161718final SophixManager instance = SophixManager.getInstance();instance.setContext(this).setAppVersion(appVersion).setSecretMetaData("IDSECRET", "APPSECRET ","RSASECRET")//填写密钥和ID.setEnableDebug(true).setEnableFullLog().setPatchLoadStatusStub(new PatchLoadStatusListener() {public void onLoad(final int mode, final int code, final String info, finalint handlePatchVersion) {if (code == PatchStatus.CODE_LOAD_SUCCESS) {Log.i(TAG, "sophix load patch success!");} else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {// 如果需要在后台重启,建议此处用SharePreference保存状态。Log.i(TAG, "sophix preload patch success. restart app to make effect.");}}}).initialize();到这一步完成,Sophix 的初始化才算真正完成。
然后点击移动热修复,点击功能。
点击添加版本
注意:这里的版本号必须跟项目中的 versionName 保持一致,否则项目拉取补丁会失败。
到这个就可以上传自己项目的补丁了。
补丁制作
是需要下载官方的一个工具,然后进行补丁打包。再将该补丁上传到该版本下。
生成补丁看这里,生成补丁.
又要注意了:这里的补丁名称不要乱修改,就得用这个工具生成的。
到了此处,终于到了补丁发布了。折腾这么久,听着流泪,闻着伤心。
上传完补丁后,点击详情,进入该补丁界面。
这个右侧有一个扫码验证补丁:点击下载 Sophix自带的一个自测 apk,安装在自己手机上,可以扫码来验证补丁是否有效,有效后,可以点击,新建发布。然后打开手机上的 app,就可以坐等热修复了。
总结
到这里,Sophix 热修复的功能就基本结束了。其中,小编自己踩的坑也都表明了注意,要是还有其他问题可以访问官方技术文档,或者进行问题搜索都可以得到一个满意的答复。