android-热修复-sophix

前言

目前Android业内,热修复技术百花齐放,各大厂都推出了自己的热修复方案,使用的技术方案也各有所异,当然各个方案也都存在各自的局限性。在面对众多的方案,希望通过梳理这些热修复方案的对比及实现原理,掌握热修复技术的本质,同时也对项目接入做好准备。

什么是热修复技术?

关于热修复这个名词,并不陌生。相信大家都有过更新window补丁的经历,通过补丁可以动态修复系统的漏洞,只不过这个过程对用户而言是可选及自行操作。

那么关于Android平台的热修复技术,简单来说,就是通过下发补丁包,让已安装的客户端动态更新,让用户可以不用重新安装APP,就能够修复软件缺陷的一种技术。

为什么要使用热修复技术?

在回答这个问题之前,我觉得应该先思考如下几个问题。

  1. 开发上线的版本能保证不存在Bug么?
  2. 修复后的版本能保证用户都及时更新么?
  3. 如何最大化减少线上Bug对业务的影响?

从这些角度来说,相信大家应该都能有所体会,热修复技术带来的优势不言而喻。

  1. 可快速修复,避免线上Bug带来的业务损失,把损失降到最低。
  2. 保证客户端的更新率,无须用户进行版本升级安装
  3. 良好的用户体验,无感知修复异常。节省用户下载安装成本。

 

怎么选择热修复技术方案?

国内主流的技术方案

1、阿里系

名称 说明
AndFix 开源,实时生效
HotFix 阿里百川,未开源,免费、实时生效
Sophix 未开源,商业收费,实时生效/冷启动修复

HotFix是AndFix的优化版本,Sophix是HotFix的优化版本。目前阿里系主推是Sophix。

2、腾讯系

名称 说明
Qzone超级补丁 QQ空间,未开源,冷启动修复
QFix 手Q团队,开源,冷启动修复
Tinker 微信团队,开源,冷启动修复。提供分发管理,基础版免费

3、其他

名称 说明
Robust 美团, 开源,实时修复
Nuwa 大众点评,开源,冷启动修复
Amigo 饿了么,开源,冷启动修复

方案对比

方案对比 Sophix Tinker nuwa AndFix Robust Amigo
类替换 yes yes yes no no yes
So替换 yes yes no no no yes
资源替换 yes yes yes no no yes
全平台支持 yes yes yes no yes yes
即时生效 同时支持 no no yes yes no
性能损耗 较少 较小 较大 较小 较小 较小
补丁包大小 较小 较大 一般 一般 较大
开发透明 yes yes yes no no yes
复杂度 傻瓜式接入 复杂 较低 复杂 复杂 较低
Rom体积 较小 Dalvik较大 较小 较小 较小
成功率 较高 较高 一般 最高 较高
热度
开源 no yes yes yes yes yes
收费 收费(设有免费阈值) 收费(基础版免费,但有限制) 免费 免费 免费 免费
监控 提供分发控制及监控 提供分发控制及监控 no no no no

综上所述。我选择了sophix

开始傻瓜式接入:

1.首先去官网登陆创建应用(需要APP包名)

官网地址

android-热修复-sophix_第1张图片

2.Project-build.gradle

   maven {
            url "http://maven.aliyun.com/nexus/content/repositories/releases"
        }

3.APP-build.gradle

 compile 'com.aliyun.ams:alicloud-android-hotfix:3.2.8'

4.Mainfest-添加权限

 //-- 网络权限 -->
    
    
    
    // -- 外部存储读权限,调试工具加载本地补丁需要  6.0注意特殊处理 -->
    

5.Mainfest-application  查看配置-见5.1

  
        
        

5.1应用配置查看

android-热修复-sophix_第2张图片

6.新建MyApplication,SophixStubApplication.

package com.example.duqianlong.sophixtest;

import android.app.Application;

/**
 * Created by Duqianlong on 2019/8/22.
 */

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //自己正常需要做的事情
    }
}
package com.example.administrator.standardOA.application;

/**
 * Created by Duqianlong on 2019/8/21.
 */

import android.content.Context;
import android.os.Looper;
import android.support.annotation.Keep;
import android.util.Log;
import android.widget.Toast;

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;

/**
 * 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(MyApplication.class)
    static class RealApplicationStub {}
    @Override
    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() {
                    @Override
                    public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
                        Log.e(TAG,"code="+code);
                        // 补丁加载回调通知
                        if (code == PatchStatus.CODE_LOAD_SUCCESS) {
                            // 表明补丁加载成功
//                            Toast.makeText(SophixStubApplication.this, "补丁加载成功!", Toast.LENGTH_SHORT).show();
                            Log.i(TAG, "sophix load patch success!");
                            Log.e(TAG, "Sophix加载补丁成功!");
                        } else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {
                            Looper.prepare();
                            Toast.makeText(SophixStubApplication.this, "补丁预加载成功,重新启动生效!", Toast.LENGTH_SHORT).show();
                            Looper.loop();
                            // 表明新补丁生效需要重启. 开发者可提示用户或者强制重启;
                            // 建议: 用户可以监听进入后台事件, 然后调用killProcessSafely自杀,以此加快应用补丁,详见1.3.2.3
                            // 如果需要在后台重启,建议此处用SharePreference保存状态。
                            Log.i(TAG, "sophix preload patch success. restart app to make effect.");
                            Log.e(TAG, "Sophix预加载补丁成功。重新启动应用程序以生效。");

                        }else if (code==PatchStatus.CODE_REQ_NOUPDATE){
                            //查询阶段没有发现新补丁
                        }
                    }
                }).initialize();
        /**
         * int CODE_LOAD_SUCCESS = 1;//加载阶段, 成功
         int CODE_ERR_INBLACKLIST = 4;//加载阶段, 失败设备不支持
         int CODE_REQ_NOUPDATE = 6;//查询阶段, 没有发布新补丁
         int CODE_REQ_NOTNEWEST = 7;//查询阶段, 补丁不是最新的
         int CODE_DOWNLOAD_SUCCESS = 9;//查询阶段, 补丁下载成功
         int CODE_DOWNLOAD_BROKEN = 10;//查询阶段, 补丁文件损坏下载失败
         int CODE_UNZIP_FAIL = 11;//查询阶段, 补丁解密失败
         int CODE_LOAD_RELAUNCH = 12;//预加载阶段, 需要重启
         int CODE_REQ_APPIDERR = 15;//查询阶段, appid异常
         int CODE_REQ_SIGNERR = 16;//查询阶段, 签名异常
         int CODE_REQ_UNAVAIABLE = 17;//查询阶段, 系统无效
         int CODE_REQ_SYSTEMERR = 22;//查询阶段, 系统异常
         int CODE_REQ_CLEARPATCH = 18;//查询阶段, 一键清除补丁
         int CODE_PATCH_INVAILD = 20;//加载阶段, 补丁格式非法
         //查询阶段的code说明
         int CODE_QUERY_UNDEFINED = 31;//未定义异常
         int CODE_QUERY_CONNECT = 32;//连接异常
         int CODE_QUERY_STREAM = 33;//流异常
         int CODE_QUERY_EMPTY = 34;//请求空异常
         int CODE_QUERY_BROKEN = 35;//请求完整性校验失败异常
         int CODE_QUERY_PARSE = 36;//请求解析异常
         int CODE_QUERY_LACK = 37;//请求缺少必要参数异常
         //预加载阶段的code说明
         int CODE_PRELOAD_SUCCESS = 100;//预加载成功
         int CODE_PRELOAD_UNDEFINED = 101;//未定义异常
         int CODE_PRELOAD_HANDLE_DEX = 102;//dex加载异常
         int CODE_PRELOAD_NOT_ZIP_FORMAT = 103;//基线dex非zip格式异常
         int CODE_PRELOAD_REMOVE_BASEDEX = 105;//基线dex处理异常
         //加载阶段的code说明 分三部分dex加载, resource加载, lib加载
         //dex加载
         int CODE_LOAD_UNDEFINED = 71;//未定义异常
         int CODE_LOAD_AES_DECRYPT = 72;//aes对称解密异常
         int CODE_LOAD_MFITEM = 73;//补丁SOPHIX.MF文件解析异常
         int CODE_LOAD_COPY_FILE = 74;//补丁拷贝异常
         int CODE_LOAD_SIGNATURE = 75;//补丁签名校验异常
         int CODE_LOAD_SOPHIX_VERSION = 76;//补丁和补丁工具版本不一致异常
         int CODE_LOAD_NOT_ZIP_FORMAT = 77;//补丁zip解析异常
         int CODE_LOAD_DELETE_OPT = 80;//删除无效odex文件异常
         int CODE_LOAD_HANDLE_DEX = 81;//加载dex异常
         // 反射调用异常
         int CODE_LOAD_FIND_CLASS = 82;
         int CODE_LOAD_FIND_CONSTRUCTOR = 83;
         int CODE_LOAD_FIND_METHOD = 84;
         int CODE_LOAD_FIND_FIELD = 85;
         int CODE_LOAD_ILLEGAL_ACCESS = 86;
         //resource加载
         public static final int CODE_LOAD_RES_ADDASSERTPATH = 123;//新增资源补丁包异常
         //lib加载
         int CODE_LOAD_LIB_UNDEFINED = 131;//未定义异常
         int CODE_LOAD_LIB_CPUABIS = 132;//获取primaryCpuAbis异常
         int CODE_LOAD_LIB_JSON = 133;//json格式异常
         int CODE_LOAD_LIB_LOST = 134;//lib库不完整异常
         int CODE_LOAD_LIB_UNZIP = 135;//解压异常
         int CODE_LOAD_LIB_INJECT = 136;//注入异常
         * */
    }

    @Override
    public void onCreate() {
        super.onCreate();
                SophixManager.getInstance().queryAndLoadNewPatch();
    }
}

6.1Mainfest-application

android-热修复-sophix_第3张图片

7.下载补丁生成工具以及测试工具

点我下载补丁生成工具

点我下载android补丁包测试工具

8.上传补丁包

android-热修复-sophix_第4张图片

8.1.本地测试补丁包

android-热修复-sophix_第5张图片

8.2.新建发布-灰度发布/全量发布

android-热修复-sophix_第6张图片

9.打开有问题的apk,开始热修复

如果生成补丁包的时候选择了强行使用冷启动,预下载补丁包后,需要重新启动生效。

10.修复结果

android-热修复-sophix_第7张图片

11.需要注意的

1.Windows下运行补丁生成工具,需要安装Java环境且在JDK7或以上才能正常使用。

2.android studio打包的时候需要关闭 Instant Run . 如图

android-热修复-sophix_第8张图片

3.如果同一个版本需要发布两个或者多个补丁包,第二次或者第N次生成补丁包的时候,旧包依旧用第一个版本的包。

4.Sophix不能修改AndroidManifest.xml文件,不能修改资源文件,不能新增四大组件,不能修改版本号,不能。所以Sophix更适合于修复致命bug。如果是增加或修改功能等操作,还是发布新版本比较好。

5.把RealApplicationStub的SophixEntry注解的内容改为自己原先真正的MyRealApplication类。

5.1:AndroidManifest里面的application改为新增的SophixStubApplication入口类。

 

 GitHub 地址(点我)

你可能感兴趣的:(android-热修复-sophix)