Android 热修复:阿里Sophix的集成

1. 前言

当我们刚发布一个版本后,突然发现了一个严重的bug。由于刚发布版本,这时候如果再紧接着发布一个版本,这时候给用户的体验肯定很差。而热修复技术可以在用户不知道的情况下修复已知的bug。目前各大厂都推出了自己的热修复方案,各个方案的差别如下(这是阿里巴巴给的对比):

热修复方案比较

平台 阿里云移动热修复 Amigo(饿了吗) Tinker(微信) Qzone(QQ空间) Robust(美团)
即时生效 yes yes no no yes
性能损耗 较小 较小 较大 较大 较小
侵入式打包 无侵入式打包 无侵入式打包 依赖侵入式打包 依赖侵入式打包 依赖侵入式打包
Rom体积 较小 较小 较大 较小 较小
接入复杂度 傻瓜式接入 比较简单 复杂 比较简单 复杂
补丁包大小 较小 较小 较小 较大 一般
全平台支持 yes yes yes yes yes
类替换 yes yes yes yes no
so替换 yes no yes no no
资源替换 yes no yes yes no

此篇文章并不讲述热修复的原理,只是整理了Sophix的接入过程。

2. Sophix介绍

Sophix 是阿里云提供的全平台App热修复服务方案。产品基于阿里巴巴首创hotpatch技术,提供最细粒度热修复能力,让您无需等待实时修复应用线上问题。

主要解决问题

  • (1)产品已有功能,出现问题,无需发版,即可发补丁,实时修复。
  • (2)存量功能微调。

3. Sophix 的集成 

3.1 开发工具

Android studio 3.5

在 Android studio 中已经没有 instant run ,无需再关闭了。

3.2 gradle 中添加配置

打开项目找到app的build.gradle文件,添加如下配置:

添加maven仓库地址:

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

 添加 sophix 版本依赖:

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

 3.3 添加产品

在阿里的管理控制台申请APP,获取如下信息:

详细信息参考:https://help.aliyun.com/document_detail/53238.html?spm=a2c4g.11186623.6.556.13005482ekgO0n 

3.4 SDK 稳健接入

加入以下这个类:

package cn.zzw.sophixdemo;

import android.content.Context;
import android.util.Log;

import androidx.annotation.Keep;

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(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();
    }

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

 其中:MyRealApplication 是原来APP中对应的Application 类,继承于Application。

queryAndLoadNewPatch 主要用于查询服务器是否有新的可用补丁。不可放在attachBaseContext 中,否则无网络权限,建议放在后面任意时刻,如onCreate中。

参考:https://help.aliyun.com/document_detail/61082.html?spm=a2c4g.11186623.6.560.46525abdB7ZdTf#h2-1-3-sdk-3

3.5 修改 AndroidManifest.xml 文件

需要的权限:

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

 在 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密钥" />

3种信息从 3.3 中的截图中去获取。

3.6 混淆配置

在 proguard-rules.pro 中添加如下信息:这里也包含了 glide 的混淆配置

#基线包使用,生成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
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

3.7 打包签名生成旧版本的APP

此步骤跟 sophix 没有什么关系,Android studio 怎么打包签名问度娘吧。

3.8 修改代码,并重新打包

这里修复前和修复后的代码只修改了 mWifePath 中的值,其他的并未修改。

package cn.zzw.sophixdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

import com.bumptech.glide.Glide;

public class MainActivity extends AppCompatActivity {
    String mWifePath = "https://timgsa.baidu.com/timg?image&quali" +
            "ty=80&size=b9999_10000&sec=1569899302358&di=527629cb21" +
            "3ba016d1d7870c039cd7a0&imgtype=0&src=http%3A%2F%2Fimg2." +
            "dzwww.com%3A8888%2Ftupian%2F20180123%2F201801230218b226c429421520.jpg";
    ImageView mImg;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImg = findViewById(R.id.mImg);
        mImg.setVisibility(View.VISIBLE);
        Glide.with(this)
                .load(mWifePath)
                .into(mImg);

    }
}

3.9 生成补丁

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

生成补丁:

生成后补丁必须命名为:sophix-patch.jar

具体参考:https://help.aliyun.com/document_detail/93826.html?spm=a2c4g.11186623.2.10.71705b84F2jqaa

3.10 创建版本以及上传/发布补丁

具体参考如下:

https://help.aliyun.com/document_detail/93805.html?spm=a2c4g.11186623.6.557.30c82dee8gN4kl

https://help.aliyun.com/document_detail/93806.html?spm=a2c4g.11186623.6.558.12be6f60gYn71i

https://help.aliyun.com/document_detail/93808.html?spm=a2c4g.11186623.6.559.4ad52deeJmFx2D

3.11 修复结果

这里先安装了旧版本的APP,然后按 back 键后,再次进入APP,发现图片已经做了修改。

 

4. 总结 

这里只是简单的讲了 sophix 的集成, 后续将会梳理下热修复的原理。如果想要更多的范例请参考 sophix 在GitHub 上面的例子:https://github.com/aliyun/alicloud-android-demo/tree/master/hotfix_android_demo?spm=a2c4g.11186623.2.23.75525482pLFpAC

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章