热更新——Sophix

热更新——Sophfix


牢骚

前些时间,公司因为服务器调整,有些特定接口IP需要更换,其中包括一个更新接口。从接到通知更换服务器到更换完成,前端开发人员只有两个小时的准备时间,其中一个小时我还在来公司的路上(晚上十点接到通知)
两个小时内及时发包也不能保证用户的更新,况且还是在晚上。
所以这几天一直很迫切需要一款热更新框架,Sophix就出现了。

介绍

官方文档

Sophix是阿里爸爸推出的第三款热更新开源框架,这里有官方给的数据对比:

方案对比Andfix开源版本阿里Hotfix 1.X阿里Hotfix最新版 (Sophix)
方法替换支持,除部分情况支持,除部分情况全部支持
方法增加减少不支持不支持以冷启动方式支持
方法反射调用只支持静态方法只支持静态方法以冷启动方式支持
即时生效支持支持视情况支持
多DEX不支持支持支持
资源更新不支持不支持支持
so库更新不支持不支持
Android版本支持2.3~7.0支持2.3~6.0全部支持包含7.0以上
已有机型大部分支持大部分支持全部支持
安全机制加密传输及签名校验加密传输及签名校验
性能损耗低,几乎无损耗低,几乎无损耗低,仅冷启动情况下有些损耗
生成补丁繁琐,命令行操作繁琐,命令行操作便捷,图形化界面
补丁大小不大,仅变动的类小,仅变动的方法不大,仅变动的资源和代码
服务端支持支持服务端控制支持服务端控制

看着就感觉非常强大,最吸引我的还是便捷,图形化界面,让我这种脑子不够用的最喜欢了。

下面介绍的集成过程,只是相对官网简化一些,添加一些集成过程中踩到的坑。
如果想要更加详细的集成文档,请点击官方文档

集成准备

一、添加产品

  • 首先进入阿里云管理控制台,点击产品与服务,在移动服务栏点击移动热修复。

添加产品步骤

阿里爸爸需要同意的,就同意吧……

  • 点击添加产品,名称随意,与热更新的项目无关。

添加产品

  • 点击添加好的产品,进入后添加应用,应用名可以随意,但包名必须与热更新的项目统一。

添加好后,界面如下:

添加应用后界面

  • 下载aliyun-emas-services.json文件
    后面配置需要的数据,都在该文件中

二、SDK引入

SDK引入有以下两种方式,官方更推荐第一种。

1. gradle远程仓库依赖

添加maven仓库地址

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

在app.gradle中添加依赖

/*
    Android Studio 3.0以后,官方推荐使用  implementation 或 api 添加依赖
    如果是之前的版本,使用compile
 */
implementation 'com.aliyun.ams:alicloud-android-hotfix:3.2.3'
2. SDK下载

SDK下载地址

三、添加必要权限

<!-- 网络权限-->
<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" />
<!--
    外部存储读权限,调试工具加载本地补丁需要
    仅调试工具获取外部补丁需要,不影响线上发布的补丁加载,调试时请自行做好android6.0以上的运行时权限获取。
-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

四、添加meta-data

AndroidManifest.xml文件的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密钥" />

这三个值需要到前面下载的aliyun-emas-services.json文件里查找,对应关系如下:

value名对应字段
App IDhotfix.idSecret
App Secretemas.appSecret
RSA密钥hotfix.rsaSecret

不用怀疑,RSA秘钥就是这么长

官方文档建议,使用setSecretMetaData这个方法进行设置。后面代码配置中会讲到。

五、混淆配置(可选)

#基线包使用,生成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.**{*;}
#防止inline
-dontoptimize

这样,前期的配置准备就完成了。将项目编译以下,准备后面的代码配置。

代码配置

这里我直接贴上初始化的代码,在注释中详细介绍:

public class App extends Application {

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        initSophix();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        /*
            queryAndLoadNewPatch不可放在attachBaseContext 中,
            否则无网络权限,建议放在后面任意时刻,如onCreate中
          */
        SophixManager.getInstance().queryAndLoadNewPatch();
    }

    /**
     * 初始化Sophix
     * 需要在attachBaseContext方法里面调用
     * 并且要在super.attachBaseContext(base);和Multidex.install方法之后调用
     * 且在其他方法之前
     */
    private void initSophix() {
        String appVersion = "1.0";
        try {
            PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
            appVersion = packageInfo.versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        SophixManager.getInstance().setContext(this)
                /*
                    设置版本号,版本号与控制台的版本号统一,才可以更新
                    这里我踩的坑,控制台上添加版本,是添加需要更新的版本,与版本升级没有关系
                 */
                .setAppVersion(appVersion)
                //<可选>用户自定义aes秘钥, 会对补丁包采用对称加密
                .setAesKey(null)
                /*
                    <可选> isEnabled默认为false, 是否调试模式, 调试模式下会输出日志以及不进行补丁签名校验.
                    线下调试此参数可以设置为true, 查看日志过滤TAG
                    正式发布必须改为false,否则存在安全风险
                 */
                .setEnableDebug(true)
                /*
                     <可选,推荐使用> 三个Secret分别对应AndroidManifest里面的三个,
                     可以不在AndroidManifest设置而是用此函数来设置Secret
                 */
                .setSecretMetaData(null, null, null)
                /*
                     <可选> 设置patch加载状态监听器,
                    该方法参数需要实现PatchLoadStatusListener接口
                 */
                .setPatchLoadStatusStub(new PatchLoadStatusListener() {
                    @Override
                    public void onLoad(int mode, int code, String info, int handlePatchVersion) {
                        // 补丁加载回调通知
                        Log.e("sophix", "onLoad: 补丁加载回调通知  code = " + code);
                        if (code == PatchStatus.CODE_LOAD_SUCCESS) {
                            // 表明补丁加载成功
                            Log.e("sophix", "onLoad: 表明补丁加载成功");
                        } else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {
                            // 表明新补丁生效需要重启. 开发者可提示用户或者强制重启;
                            // 建议: 用户可以监听进入后台事件, 然后调用killProcessSafely自杀,以此加快应用补丁,详见1.3.2.3
                            Log.e("sophix", "onLoad: 表明新补丁生效需要重启. 开发者可提示用户或者强制重启");
                            SophixManager.getInstance().killProcessSafely();
                        } else {
                            // 其它错误信息, 查看PatchStatus类说明
                            Log.e("sophix", "onLoad: 其它错误信息, 查看PatchStatus类说明");
                        }
                    }
                }).initialize();
    }
}

上面描述有够详细吧。这里贴上code的各个返回码含义:

//兼容老版本的code说明
    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;//注入异常

补丁包生成

万事俱备,只欠补丁了。听说最强的武器就是补丁。

补丁生成器下载及介绍

这里就不多废话了,点击上面的链接,里面有很详细的介绍。
注意:两个APK之间一定要有差距啊!

补丁包上传

点击控制台的热修复
→添加版本
→输入版本号(这里版本号要与项目版本相同)
→上传补丁(选择上一步生成的补丁包)

补丁包上传

扫码验证补丁(可选,官方推荐,稳定保证)

在正式发布补丁之前,官方推荐先通过测试。

点开补丁详情,在右上角,之后就是人性化(傻瓜式)操作了,不做赘述。
扫码验证补丁

发布补丁

做了这么多事,其实补丁还在自己家呢。我们需要点击下方的新建发布,选择合适的发布方式,这里我选择的全量发布。

打印一下日志:

08-11 16:24:21.506 14363-14435/com.martin.sophixstudy E/sophix: onLoad: 补丁加载回调通知  code = 9
    onLoad: 其它错误信息, 查看PatchStatus类说明
08-11 16:24:21.746 14363-14448/com.martin.sophixstudy E/sophix: onLoad: 补丁加载回调通知  code = 100
    onLoad: 其它错误信息, 查看PatchStatus类说明
    onLoad: 补丁加载回调通知  code = 12
    onLoad: 表明新补丁生效需要重启. 开发者可提示用户或者强制重启

上面代码中,强制杀死了APP进程,现在重新打开,嗯~可以看到更新的内容了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值