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

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