阿里热修复Sophix

第一章、准备工作
1、申请阿里云账号;

2、开通阿里云移动管理服务;

3、开通阿里云移动服务平台EMAS.

4、创建一个新产品,即需要接入的APP产品。

 

第二章:接入热修复SDK

您可以在应用管理页面获取配置SDK所需要的基本信息。包括:

  • AppKey:用于AppKey是阿里云上应用的唯一标识,热修复的appId可设置AppKey。
  • RSA密钥: RSA密钥是保存在客户端本地用于解密patch包过程中使用的解密密钥。(推荐使用chrome浏览器下载)
  • AppSecret:用于URL请求时生成合法验签标识的key。

Demo程序下载地址:

https://github.com/aliyun/alicloud-android-demo

安卓Demon:

https://github.com/joedan0104/SophixDemo

1、添加热修复依赖库

在项目的app的build.gradle中添加Maven仓库

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

在dependencies增加热修复库坐标版本依赖
compile 'com.aliyun.ams:alicloud-android-hotfix:3.2.8'

2、AndroidManifest增加需要的权限

包括读写SD卡、网络权限。

<! -- 网络权限 -->
<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"/>

3、配置APP热修复相关数据

在AndroidManifest的application节点下,配置热修复字段。

        <!-- 热修复字段 -->
        <meta-data
            android:name="com.taobao.android.hotfix.IDSECRET"
            android:value="${HOTFIX_APPID}" />
        <meta-data
            android:name="com.taobao.android.hotfix.APPSECRET"
            android:value="${HOTFIX_APPSECRET}" />
        <meta-data
            android:name="com.taobao.android.hotfix.RSASECRET"
            android:value="${HOTFIX_RSA}" />

这些字段在编译的时候写入具体的值。

这几个值的阿里云控制台用户创建的APP对应的热修复的值。

其中APPID:对应的AppKey

APPSECRET:对应的AppSecret

RSA:对应的Rsa

def config = rootProject.ext// android基本配置
android {
    compileSdkVersion config.android.compileSdkVersion
    buildToolsVersion config.android.buildToolsVersion
    defaultConfig {
        applicationId "com.cdel.sophixdemo"
        minSdkVersion config.android.minSdkVersion
        targetSdkVersion config.android.targetSdkVersion
        versionCode 1
        versionName "1.0.1"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        // dex突破65535的限制
        multiDexEnabled true
        //个别机器添加热修复导致Vitamio 崩溃问题
        ndk {
            abiFilters "armeabi", "armeabi-v7a"
        }
        // AndroidManifest替换参数
        manifestPlaceholders = [
                HOTFIX_APPID            : "25994860",
                HOTFIX_APPSECRET        : "f63fcee692a46eb81da4c7a10fe1cd4f",
                HOTFIX_RSA              : "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCiD+oeBqhp79WsNwHUjzUy6ljWM6LgATtXoSFm0KErs8DeF3BUPx9P0fSF8grXh7/OoLlAk5uLC11v51mSbKP9OhQ67doHFBhJT8Og5ixIaUT9vV05KksxM85cXV/Ze7o9rjzLtHKbg4ySe/LjiQNdp7SLAhauUXHrEMJpGJaORFVQVtqCrkMjgsvx1ZPmhI8mg6U6VOYcVD2rkLV1jyQcSvcJXtJtERtRBLK2R3IRiC2Oy/IosYJjGeOrN/KMWbMQOC36p7rMOj+xYeOiDyxHX9v+5TRUZ/NXjku57CmjIVcBfF7goBvtay1TIsp1ggDp51Wsg/fGB5KIT6ZPdhzhAgMBAAECggEAYVc1w/szxQ2tRdd0Xfv2dDKWUXKKbgnPXv8FVQATDnDVc5CYg8G2SPdO6/VJ1dNPvgiDvOnsD0QwRzqqbmyaw0rTQ+IBhybmv4INeuNFzeiM6+uFxwRETbVUSd476CGM5+dz1Nb5z7bgBEw2w7xULTjCFIyYmvOIfSx/2ShPpfsiRES9fL3LOau5GqFeHczjwr0nFVuAALB4xnS8cw5z9dZfawcJUOCQKTYzUpSlLvetEAYRDXdl66mPQVdG0VLtKuyxZfIFNyyifY7IaClPvZt1ZZXgr+rKRj+m+vbVU6r5eHnQTqC4m5AVRtCA97SXYPTFFR1QH8a7YWki0/sTUQKBgQD/xnpD+mZfxdexEMlVfBIjrVfcEBeky2hVNgCXDqd2oe/NKQC3vbcgDV9NslhlBTIdXvHvvLUHSSoBlK8lic/53VYUbLQtyEmEM7k5gV6zJBLudyfXgMd30Jyq6Y4w6J4UKOCy/vxOu8DVbMBG56XpnjvyoEVBCSuJXPDXSnUE2wKBgQCiNFyC9eF/r2j12K5vERIUzGH11w6T7yIcY66JKce2m1oqucyo7ZBX3HXxOUMM6676QmesMJF2/01vZrEe8usg0zFpyhKXLc9sk8nEYd5Ip9Gui2LmAsRXTzXNR7tVI4Bxueqrb7GKrOMteplMy0sze/nOAOnZbszSxiXjqsbT8wKBgDC52e77U+do5EdKIGDVqwr66eL1edueGHkrOX+Nfh+eh/V4mzdlv+4uPfqqQCa2j66CuOpn88C4knUMozUuhN1f6hcoAkc6ga7av62R1L2h4K1nK8LlOJq9tirlJX5xwjOq+et/ogdJw1mlRxf652OTDm6RU8ApBA8+Em+hMpvDAoGAZoZSMzTXY62r2jkriGhx1VOaV5mnTTpJhUg8edY+td1cEMV/5wbBxcdDhUV8bB5Ma0Kt5NiOGXklqNRv/+/rTsQu538iYQxDn42KauaxaZspnfnceSYmlEks6KP+dMIL3dZ1zga7YbwFnClx3GhjEBe8vck2BolSTaeRK2Y2ZqECgYAHBocOQA8zhUhTMaA/yPM1gP6V+bQu92wLf318OpXRMr6/DNKnoujhFCB3wsemBWrJCdpIZifdOaNQnw6ZIyPiK88q9yA8PYUBeF+KjX0mk8k8/vLoUUJqe2bf7WV+3M0jxjlBhWpeN8rFSbuMN1gEvX1dRKIs8yNbY9FBePejTw==",
        ]
    }

4、创建Sophix入口程序

/**
 * 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(MyRealApplication.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) {
                        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();
    }
}

注意:SophixEntry应指定项目中原先真正的Application(原项目里application的android::name指定的),这里用MyRealApplication指代。并且保证RealApplicationStub类名不被混淆。而SophixStubApplication的类名和包名可以自行取名。

    @Keep
    @SophixEntry(MyRealApplication.class)
    static class RealApplicationStub {}

 

这里的Keep是android.support包中的类,目的是为了防止这个内部静态类的类名被混淆,因为sophix内部会反射获取这个类的SophixEntry。如果项目中没有依赖android.support的话,就需要在progurad里面手动指定RealApplicationStub不被混淆,详见下文。

把AndroidManifest里面的application改为这个新增的SophixStubApplication类:

    <application
        android:name=".SophixStubApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

这样便完成了新方式的初始化接入改造。

总结一下,过程一共有四个步骤:

  1. 把此SophixStubApplication入口类添加进项目中,所有Sophix相关初始化放在此类中。并且不应包含开发者的任何业务逻辑代码。 若使用了MultiDex,也应在SophixStubApplication的initSophix之前添加,并且需要记得在原来的Application里面去除MultiDex,避免重复调用导致问题。
  2. 把RealApplicationStub的SophixEntry注解的内容改为自己原先真正的MyRealApplication类。
  3. 混淆文件中确保某些内容不被混淆。
  4. AndroidManifest里面的application改为新增的SophixStubApplication入口类。

5、配置热修复混淆

混淆配置文件proguard-rules.pro增加热修复相关配置

#基线包使用,生成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
-keepclassmembers class com.cdel.sophixdemo.ModelApplication {
    public <init>();
}
# 如果不使用android.support.annotation.Keep则需加上此行
# -keep class com.my.pkg.SophixStubApplication$RealApplicationStub

注意:

*生成基线包,使用

-printmapping mapping.txt

*生成补丁后的包,使用

-applymapping mapping.txt

然后把基线包的mapping文件拷贝到app下边。

两者不能同时出现。

6、查询和下载热修复补丁

// queryAndLoadNewPatch不可放在attachBaseContext 中,否则无网络权限,建议放在后面任意时刻,如onCreate中

SophixManager.getInstance().queryAndLoadNewPatch();

热修复补丁下载完成以后,等APP完全退出,下载APP启动的时候自动安装。

 

第三章 生成补丁包

生成补丁包的过程。

1)生成基线包

混淆文件中配置

*生成基线包,使用

-printmapping mapping.txt

打包生成基线包。

2)生成修复包

混淆文件中配置

*生成补丁后的包,使用

-applymapping mapping.txt

把基线包的mapping文件复制到app目录下。打包生成修复包。

3)生成补丁包

下载安装补丁环境

3.1.1 下载打包工具

patch补丁包生成需要使用到打补丁工具SophixPatchTool, 如还未下载打包工具,请前往下载Android打包工具。

该工具提供了Windows和macOS和Linux版本,Windows下运行SophixPatchTool.exe,macOS下运行SophixPatchTool.app,Linux下(Ubuntu 16.04 64bit最佳)运行SophixPatchTool。并且需要安装Java环境且在JDK7或以上才能正常使用。

3.1.2 生成Patch

3.1.2.1 主对话框

sophix1

  • 旧包:<必填> 选择基线包路径(有问题的APK)。
  • 新包:<必填> 选择新包路径(修复过该问题APK)。
  • 日志:打开日志输出窗口。
  • 高级:展开高级选项,见1.2.2。
  • 设置:配置其他信息。
  • GO!:开始生成补丁。

3.1.2.3 设置对话框

tool

  • 补丁输出路径:<必填> 指定生成补丁之后补丁的存放位置,必须是已存在的目录。
  • Key Store Path:<选填>本地的签名文件的路径,不输入则不做签名。如果基线包是签名包,此处需要选择keystore文件。如果用户的keystore文件显示不出来,可以将原来keystore的文件拷贝一份,重命名为keystore.xxx,这样就可以显示出来。
  • Key Store Password:<选填>证书文件的密码。Key Store Path设置时必填
  • Key Alias:<选填>Key的别名。Key Store Path设置时必填
  • Key Passwrod:<选填>Key的密码。Key Store Path设置时必填
  • AES Key:<选填>自定义aes秘钥, 必须是16位数字或字母的组合。必须与setAesKey中设置的秘钥一致。可不填。
  • Filter Class File:<选填>本地的白名单类列表文件的路径,放进去的类不会再计算patch,文件格式: 一行一个类名。

3.1.2.3 生成补丁包

点击GO 按钮,生成补丁包。

sophix-patch就是生成的补丁包。

第四章 发布补丁包

发布补丁


HotFix提供了多种发布方式,方便您根据自身业务需要选择性使用。

  • 上传补丁后,会展示补丁列表信息,点击“详情”,进入发布页面

patch_details

  • 进入详情页面,点击“新建发布”,进入发布流程

新建发布

 

1.1 本地测试

HotFix提供了调试工具实现本地测试,方便您在正式发布前,在您的手机本地进行测试。

步骤如下:

1.2 灰度发布

HotFix提供灰度发布模式,您可以在控制台发布灰度批次,并为该批次指定灰度人数标签,客户端拉取到补丁时会消耗该灰度人数,达到指定数量后,灰度批次自动置为停止状态。

发布灰度批次

1.2.1 发布人数

此项为设置最多可供设备请求到该批次更新补丁的次数。该计数以请求到更新补丁的次数为准,如:

试用

 
  1. 1个设备请求到更新补丁之后,删除本地缓存再次请求成功1次,则总共会消耗掉2个次数。

1.2.2 指定标签

注:Android SDK从 3.2.7 版本开始支持设置标签,若接入的SDK低于该版本,新建灰度批次时忽略此项即可。

此项为设置灰度附带的标签条件。只有设置了对应标签的设备,才能请求到本批次的更新补丁。如:

试用

 
  1. 端上设置标签为["tag1"], 发布时指定标签为["tag1"], 能拉取到;
  2. 端上设置标签为["tag1","tag2"], 发布时指定标签为["tag1"], 能拉取到;
  3. 端上设置标签为["tag1"], 发布时指定标签为["tag1","tag2"], 能拉取到;
  4. 端上设置标签为["tag1","tag3"], 发布时指定标签为["tag1", "tag3"], 能拉取到;

可以看到,只要端上设置的标签[组],和发布灰度批次时指定的标签[组],交集不为空,就能拉取到更新补丁。

特别注意:

1. 输入标签后,按回车,该标签输入才算成功;您可以通过多次输入,多次回车,来实现输入标签组;

2. 不输入任何标签,则该批次不会对端上携带的标签做任何校验;

1.2.3 后置操作

发布灰度批次后可以根据实际需要停止灰度批次,停止后可以选择:

  • 发布新的灰度批次;
  • 发布新的全量批次;
  • 回滚版本(如果存在历史版本)见 2.9 发布回滚

 

1.3 全量发布

HotFix提供全量发布模式,选择全量发布后,将对所有安装了当前应用版本(即之前创建应用时所填写的应用版本号)的设备推送该补丁。

与灰度发布类似,在全量发布会可以根据自身需要停止本次全量发布,停止发布后可以选择:

  • 继续全量发布。
  • 回滚版本(如果存在历史已经发布过全量批次的版本),见2.9 发布回滚

 

1.4 停止发布

HotFix提供停止发布功能,用户停止某个发布批次后,系统将停止该批次补丁的继续发布,但已加载该补丁的设备会依然保持安装该补丁的状态。

 

1.5 发布回滚

HotFix提供发布回滚功能,用户选择回滚的目标补丁后,确认回滚后,所有该应用版本下设备都会获取到该目标补丁,从而实现回滚。

使用回滚功能必需要具备以下条件:

  • 该版本之前存在至少一个全量发布的历史版本。

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值