1. 程式人生 > >Android Mobile Hotfix(阿里雲——移動熱修復接入)

Android Mobile Hotfix(阿里雲——移動熱修復接入)

首先你需要註冊並登陸 阿里雲移動研發平臺,檢視官方文件,下載SDK等,整合過程並不複雜。本文主要記錄接入流程跟遇到的問題

什麼是熱修復

熱修復,是一種使用補丁來更新修復的手段。不需要通過重新發布App,下載安裝等一系列繁瑣的過程。

熱修復原理

總結參考文件,修復框架很多,但熱修復框架的核心技術主要有三類

  • 程式碼修復
  • 資源修復
  • 動態連結庫修復

程式碼修復主要有三個方案,分別是底層替換方案、類載入方案和Instant Run方案,具體請參考以下連結

參考文件:

https://www.jianshu.com/p/a4bf979cce3b(Android熱更新之初探)

https://blog.csdn.net/itachi85/article/details/79522200(Android熱修復原理)

外掛化開發

將整個app拆分成多個模組,每個模組都是一個app,這些模組包括一個宿主和多個外掛。(解決 65535 問題)

外掛化Small方案:http://code.wequick.net/Small/cn/quickstart

元件化開發

將整個app拆分成多個模組,每個模組都是一個元件(Module),也就是lib。專案功能需求比較複雜的時候,或者多人開發的時候,非常不錯的一種方案。便於開發,除錯。程式碼邏輯結構清晰,便於程式碼的維護,重用,降低耦合度。

參考文件:

https://www.jianshu.com/p/704cac3eb13d(Android 外掛化和熱修復知識梳理)

https://blog.csdn.net/guiying712/article/details/55213884(Android元件化方案)

https://blog.csdn.net/u012513972/article/details/78269288(Android熱更新技術的研究與實現)

記錄部分學習內容,下面主要介紹 Sophix接入以及簡單使用:

 官方文件:https://help.aliyun.com/product/51340.html?spm=5176.131995.673114.doc1.13e969fd9JwVdh

Android Studio 整合(快速接入)

第一步,新增依賴配置

這裡注意是都在 app的build.gradle檔案下,新增配置

repositories {
        mavenLocal()
        //阿里雲倉庫
        maven {
            url "http://maven.aliyun.com/nexus/content/repositories/releases"
        }
        mavenCentral()
        jcenter()
        flatDir {
            dirs 'libs'
        }
    }

新增依賴:

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

第二步,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" />

在Android 6.0及以上,需要對READ_EXTERNAL_STORAGE許可權做處理

還有data資料配置,我是在程式碼中進行設定的,推薦使用。避免別人解析破解

第三步,初始化處理

/**
 * Sophix入口類,專門用於初始化Sophix,穩健接入方式
 * <p>
 * Sophix入口類,專門用於初始化Sophix,不應包含任何業務邏輯。
 * 此類必須繼承自SophixApplication,onCreate方法不需要實現。
 * 此類不應與專案中的其他類有任何互相呼叫的邏輯,必須完全做到隔離。
 * AndroidManifest中設定application為此類,而SophixEntry中設為原先Application類。
 * 注意原先Application裡不需要再重複初始化Sophix,並且需要避免混淆原先Application類。
 */
public class SophixStubApplication extends SophixApplication {

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

    @Override
    public void onCreate() {
        super.onCreate();
        // queryAndLoadNewPatch不可放在attachBaseContext 中,否則無網路許可權,建議放在後面任意時刻
        SophixManager.getInstance().queryAndLoadNewPatch();
    }

    /**
     * 初始化 Sophix
     */
    private void initSophix() {

        String appVersion = "0.0.0";
        try {
            appVersion = this.getPackageManager()
                    .getPackageInfo(this.getPackageName(), 0)
                    .versionName;
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.e(TAG, "initSophix: " + appVersion);

        final SophixManager instance = SophixManager.getInstance();
        instance.setContext(this)
                .setAppVersion(appVersion)
                .setSecretMetaData(getResourceById(R.string.ali_sophix_IDSECRET), getResourceById(R.string.ali_sophix_APPSECRET), getResourceById(R.string.ali_sophix_RSASECRET))
                .setEnableDebug(true)//日誌
                .setAesKey(null)
                .setPatchLoadStatusStub(new PatchLoadStatusListener() {
                    @Override
                    public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {

                        Log.e(TAG, "onLoad: " + code);
                        if (code == PatchStatus.CODE_LOAD_SUCCESS) {
                            // 表明補丁載入成功

                        } else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {

                            // 如果需要在後臺重啟,建議此處用SharePreference儲存狀態。
                            // 表明新補丁生效需要重啟. 開發者可提示使用者或者強制重啟;
                            // 建議: 使用者可以監聽進入後臺事件, 然後呼叫killProcessSafely自殺,以此加快應用補丁,詳見1.3.2.3
                            //SophixManager.getInstance().killProcessSafely();

                        } else {

                            // 其他錯誤資訊
                            Log.e(TAG, "onLoad: " + code);

                        }
                    }
                }).initialize();
    }


    /**
     * 獲取 string 資源
     *
     * @param rid
     * @return
     */
    private String getResourceById(int rid) {
        return this.getResources().getString(rid);
    }


}

我使用 穩健接入方式

注意在@SophixEntry() 此處指定專案原有的Application,但是在AndroidManifest中引用的是SophixStubApplication

    @Keep
    @SophixEntry(MyApplication.class)
    static class RealApplicationStub {

    }

通過setSecretMetaData() 設定 阿里引數(建立專案後會看到)

 @Override
    public void onCreate() {
        super.onCreate();
        // queryAndLoadNewPatch不可放在attachBaseContext 中,否則無網路許可權,建議放在後面任意時刻
        SophixManager.getInstance().queryAndLoadNewPatch();
    }

官方文件比較詳細,僅記錄一些比較容易錯過的細節

補丁版本問題

  • 初始化通過setAppVersion()設定版本號,這個版本號將用於,客戶端(當前整合app)來比對上傳到阿里後臺的補丁版本,釋出的補丁版本號,跟程式碼中設定的要一致,否則無法載入到
  • 每一個版本,只能允許有一個補丁,若有變動,需要停止舊版本補丁的釋出,替換新補丁(所以,緊急的一些小BUG,可以用此方式,當改動比較大,需求變動多,必備的版本更新下載,重新安裝的方式,也是不可少的)

補丁相關問題

  • 打新舊包的時候,必須關閉Android Studio 的 Install Run 
  • 補丁替換,必須保證bug的疊加修復。(比如第一個補丁修復A-bug,發現 B-bug需要第二個補丁。那麼在第二個補丁中,必須修改了A+B 兩個bug)
  • 使用該熱修復,不能有增加或刪減 Android元件的變動,否則無法成功修復(還沒測試)

主要以學習記錄為目的,記錄一些不錯的文件連結。