阿里雲熱修復sophix詳解

       現在網上有幾種常用的app熱修復技術,個人感覺阿里雲熱修復操作比較簡單,主要幾個步驟,創建app---下載sdk---集成(AS和eclipse)---生成補丁---發佈補丁(可以本地調試)。下面詳細講各個步驟:

hotfix_app_create

  • 點擊創建後,MHub控制檯可以查看到對應App。

mhub-console

  • 返回Hotfix控制檯,刷新頁面後可以看到對應的Hotfix App。

【注意】熱修復控制檯地址爲:地址

app列表,熱修復控制檯

  • RSA密鑰

在App列表點擊“管理”後,跳轉到單個App管理頁面,可以查看。

【注意】這裏的App列表是:熱修復的控制檯-管理列表地址:https://hotfix.console.aliyun.com/#/list不是創建應用的控制檯列表,請一定要明確這一點。

RSA密鑰問題

二,下載SDK


一、SDK下載入口

進入MHub控制檯下載SDK:https://mhub.console.aliyun.com/#/download

二、功能介紹

SDK下載頁面提供SDK下載及打包記錄功能,各產品SDK支持勾選合併功能,打包記錄功能保存最近五次打包記錄。

sdk-download1

三、下載SDK

請按需勾選SDK,後臺自動去除重複依賴,點擊下載按鈕後請耐心等待SDK生成完成並根據提示進行下載。

若生成過程中出現異常,請按提示重試或反饋給工作人員。

sdk-download2

SDK生成成功後將出現下載提示框,用戶可以選擇直接下載也可以後續在SDK打包記錄中選擇下載。

若SDK生成時間過長,用戶可以選擇後臺運行,後續可在SDK打包記錄中查看相應狀態。

sdk-download4

四、SDK打包記錄

SDK打包記錄爲用戶展示最近五次打包記錄,用戶可以查看SDK生成狀態並下載已生成完成的SDK。

sdk-download3


三,快速集成

1.1 Android SDK及工具下載

阿里雲Sophix 3.0版本現已上線!

Sophix提供了一套更加完美的客戶端服務端一體的熱更新方案,做到了圖形界面一鍵打包、加密傳輸、簽名校驗和服務端控制發佈與灰度功能,讓你用最少的時間實現最強大可靠的全方位熱更新。

  • 一張表格來說明一下各個版本熱修復的差別:
方案對比 Andfix開源版本 阿里Hotfix 1.X 阿里Hotfix最新版 (Sophix)
方法替換 支持,除部分情況[0] 支持,除部分情況 全部支持
方法增加減少 不支持 不支持 以冷啓動方式支持[1]
方法反射調用 只支持靜態方法 只支持靜態方法 以冷啓動方式支持
即時生效 支持 支持 視情況支持[2]
多DEX 不支持 支持 支持
資源更新 不支持 不支持 支持
so庫更新 不支持 不支持 支持
Android版本 支持2.3~7.0 支持2.3~6.0 全部支持包含7.0以上
已有機型 大部分支持[3] 大部分支持 全部支持
安全機制 加密傳輸及簽名校驗 加密傳輸及簽名校驗
性能損耗 低,幾乎無損耗 低,幾乎無損耗 低,僅冷啓動情況下有些損耗
生成補丁 繁瑣,命令行操作 繁瑣,命令行操作 便捷,圖形化界面
補丁大小 不大,僅變動的類 小,僅變動的方法 不大,僅變動的資源和代碼[4]
服務端支持 支持服務端控制[5] 支持服務端控制

說明:

  • [0] 部分情況指的是構造方法、參數數目大於8或者參數包括long,double,float基本類型的方法。
  • [1] 冷啓動方式,指的是需要重啓app在下次啓動時才能生效。
  • [2] 對於Andfix及Hotfix 1.X能夠支持的代碼變動情況,都能做到即時生效。而對於其他代碼變動較大的情況,會走冷啓動方式,此時就無法做到即時生效。
  • [3] Hotfix 1.X已經支持絕大部分主流手機,只是在X86設備以及修改了虛擬機底層結構的ROM上不支持。
  • [4] 由於支持了資源和庫,如果有這些方面的更新,就會導致的補丁變大一些,這個是很正常的。並且由於只包含差異的部分,所以補丁已經是最大程度的小了。
  • [5] 提供服務端的補丁發佈和停發、版本控制和灰度功能,存儲開發者上傳的補丁包。

1.2 集成準備

1.2.1 android studio集成方式

gradle遠程倉庫依賴, 打開項目找到app的build.gradle文件,添加如下配置:

添加maven倉庫地址:

  1. repositories {
  2. maven {
  3. url "http://maven.aliyun.com/nexus/content/repositories/releases"
  4. }
  5. }

添加gradle座標版本依賴:

  1. compile 'com.aliyun.ams:alicloud-android-hotfix:3.1.1'

傳遞性依賴utdid這個sdk, 所以不需要重複依賴utdid.但是另一方面其它阿里系SDK也可能依賴了utdid這個SDK, 如果編譯期間報utdid重複, 所以此時進行如下處理即可, 關閉傳遞性依賴:

  1. compile ('com.aliyun.ams:alicloud-android-hotfix:3.1.1') {
  2. exclude(module:'alicloud-android-utdid')
  3. }

utdid實際上是爲設備生成唯一deviceid的一個基礎類庫

如若倉庫訪問失敗, 那麼用本地依賴的方式進行依賴, SDK下載見“1.5 客戶端本地SDK及DEMO下載”節。

1.2.2 eclipse集成方式

  • 下載OneSDk.zip,解壓出hotfix_core-release.aar文件後再解壓這個aar文件(不能直接解壓的話,點其他壓縮命令,用壓縮文件(我的是360壓縮)打開,再解壓到具體位置)
  • 複製解壓文件jni目錄下的libsophix.so到自己的jni目錄下, eclipse jni目錄一般指的就是項目libs目錄
  • 複製utdid4all-1.1.5.3_proguard.jar和alicloud-android-utils-1.0.3.jar文件到項目libs目錄下
  • 重命名classes.jar爲sophix.jar並複製到項目libs目錄下
  • 合併AndroidManifest.xml文件中的內容到本項目AndroidManifest.xml文件,service一定要合併。

編譯期間報utdid類重複異常, 那麼步驟2中添加的utdid4all-1.1.5.3_proguard.jar從項目libs目錄移除即可

1.2.3 權限說明

Sophix SDK使用到以下權限

  1. <! -- 網絡權限 -->
  2. <uses-permission android:name="android.permission.INTERNET" />
  3. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  4. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  5. <! -- 外部存儲讀權限,調試工具加載本地補丁需要 -->
  6. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

READ_EXTERNAL_STORAGE/ACCESS_WIFI_STATE權限屬於Dangerous Permissions,自行做好android6.0以上的運行時權限獲取

1.2.4 配置AndroidManifest文件

AndroidManifest.xml中間的application節點下添加如下配置:

  1. <meta-data
  2. android:name="com.taobao.android.hotfix.IDSECRET"
  3. android:value="App ID" />
  4. <meta-data
  5. android:name="com.taobao.android.hotfix.APPSECRET"
  6. android:value="App Secret" />
  7. <meta-data
  8. android:name="com.taobao.android.hotfix.RSASECRET"
  9. android:value="RSA密鑰" />

將上述value中的值分別改爲通過平臺HotFix服務申請得到的App Secret和RSA密鑰,出於安全考慮,建議使用setSecretMetaData這個方法進行設置,詳見1.3.2.1的方法說明。

1.2.5 混淆配置

混淆感覺沒什麼用,eclipse不混淆也可以
  1. #基線包使用,生成mapping.txt
  2. -printmapping mapping.txt
  3. #生成的mapping.txt在app/buidl/outputs/mapping/release路徑下,移動到/app路徑下
  4. #修復後的項目使用,保證混淆結果一致
  5. #-applymapping mapping.txt
  6. #hotfix
  7. -keep class com.taobao.sophix.**{*;}
  8. -keep class com.ta.utdid2.device.**{*;}
  9. #防止inline
  10. -dontoptimize

1.3 SDK接口使用說明

1.3.1 接入範例

initialize的調用應該儘可能的早,必須在Application.attachBaseContext()或者Application.onCreate()的最開始進行SDK初始化操作,否則極有可能導致崩潰。而查詢服務器是否有可用補丁的操作可以在後面的任意地方。

  1. // initialize最好放在attachBaseContext最前面
  2. SophixManager.getInstance().setContext(this)
  3. .setAppVersion(appVersion)
  4. .setAesKey(null)
  5. .setEnableDebug(true)
  6. .setPatchLoadStatusStub(new PatchLoadStatusListener() {
  7. @Override
  8. public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
  9. // 補丁加載回調通知
  10. if (code == PatchStatus.CODE_LOAD_SUCCESS) {
  11. // 表明補丁加載成功
  12. } else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {
  13. // 表明新補丁生效需要重啓. 開發者可提示用戶或者強制重啓;
  14. // 建議: 用戶可以監聽進入後臺事件, 然後調用killProcessSafely自殺,以此加快應用補丁,詳見1.3.2.3
  15. } else {
  16. // 其它錯誤信息, 查看PatchStatus類說明
  17. }
  18. }
  19. }).initialize();

  1. // queryAndLoadNewPatch不可放在attachBaseContext 中,否則無網絡權限,建議放在後面任意時刻,如onCreate中
  2. SophixManager.getInstance().queryAndLoadNewPatch();
  上面這方法可以放到mainactivity的oncreate中

1.3.2 接口說明

1.3.2.1 initialize方法

  • initialize(): <必選>

    該方法主要做些必要的初始化工作以及如果本地有補丁的話會加載補丁, 但不會自動請求補丁。因此需要自行調用queryAndLoadNewPatch方法拉取補丁。這個方法調用需要儘可能的早, 推薦在Application的onCreate方法中調用, initialize()方法調用之前你需要先調用如下幾個方法, 方法調用說明如下:

  • setContext(application): <必選> 傳入入口Application即可

  • setAppVersion(appVersion): <必選> 應用的版本號

  • setSecretMetaData(idSecret, appSecret, rsaSecret): <可選,推薦使用> 三個Secret分別對應AndroidManifest裏面的三個,可以不在AndroidManifest設置而是用此函數來設置Secret。放到代碼裏面進行設置可以自定義混淆代碼,更加安全,此函數的設置會覆蓋AndroidManifest裏面的設置,如果對應的值設爲null,默認會在使用AndroidManifest裏面的。

  • setEnableDebug(isEnabled): <可選> isEnabled默認爲false, 是否調試模式, 調試模式下會輸出日誌以及不進行補丁簽名校驗. 線下調試此參數可以設置爲true, 查看日誌過濾TAG:Sophix, 同時強制不對補丁進行簽名校驗, 所有就算補丁未簽名或者簽名失敗也發現可以加載成功. 但是正式發佈該參數必須爲false, false會對補丁做簽名校驗, 否則就可能存在安全漏洞風險

  • setAesKey(aesKey): <可選> 用戶自定義aes祕鑰, 會對補丁包採用對稱加密。這個參數值必須是16位數字或字母的組合,是和補丁工具設置裏面AES Key保持完全一致, 補丁才能正確被解密進而加載。此時平臺無感知這個祕鑰, 所以不用擔心阿里雲移動平臺會利用你們的補丁做一些非法的事情。

  • setPatchLoadStatusStub(new PatchLoadStatusListener()): <可選> 設置patch加載狀態監聽器, 該方法參數需要實現PatchLoadStatusListener接口, 接口說明見1.3.2.2說明

  • setUnsupportedModel(modelName, sdkVersionInt):<可選> 把不支持的設備加入黑名單,加入後不會進行熱修復。modelName爲該機型上Build.MODEL的值,這個值也可以通過adb shell getprop | grep ro.product.model取得。sdkVersionInt就是該機型的Android版本,也就是Build.VERSION.SDK_INT,若設爲0,則對應該機型所有安卓版本。

1.3.2.2 queryAndLoadNewPatch方法

該方法主要用於查詢服務器是否有新的可用補丁. SDK內部限制連續兩次queryAndLoadNewPatch()方法調用不能短於3s, 否則的話就會報code:19的錯誤碼. 如果查詢到可用的話, 首先下載補丁到本地, 然後

  • 應用原本沒有補丁, 那麼如果當前應用的補丁是熱補丁, 那麼會立刻加載(不管是冷補丁還是熱補丁). 如果當前應用的補丁是冷補丁, 那麼需要重啓生效.
  • 應用已經存在一個補丁, 請求發現有新補丁後,本次不受影響。並且在下次啓動時補丁文件刪除, 下載並預加載新補丁。在下下次啓動時應用新補丁。

    補丁在後臺發佈之後, 並不會主動下行推送到客戶端, 需要手動調用queryAndLoadNewPatch方法查詢後臺補丁是否可用.

  • 只會下載補丁版本號比當前應用存在的補丁版本號高的補丁, 比如當前應用已經下載了補丁版本號爲5的補丁, 那麼只有後臺發佈的補丁版本號>5纔會重新下載.

同時1.4.0以上版本服務後臺上線了“一鍵清除”補丁的功能, 所以如果後臺點擊了“一鍵清除”那麼這個方法將會返回code:18的狀態碼. 此時本地補丁將會被強制清除, 同時不清除本地補丁版本號

1.3.2.3 killProcessSafely方法

可以在PatchLoadStatusListener監聽到CODE_LOAD_RELAUNCH後在合適的時機,調用此方法殺死進程。注意,不可以直接Process.killProcess(Process.myPid())來殺進程,這樣會擾亂Sophix的內部狀態。因此如果需要殺死進程,建議使用這個方法,它在內部做一些適當處理後才殺死本進程。

1.3.2.4 cleanPatches()方法

清空本地補丁,並且不再拉取被清空的版本的補丁。正常情況下不需要開發者自己調用,因爲Sophix內部會判斷對補丁引發崩潰的情況進行自動清空。

1.3.2.5 PatchLoadStatusListener接口

該接口需要自行實現並傳入initialize方法中, 補丁加載狀態會回調給該接口, 參數說明如下:

  • mode: 補丁模式, 0:正常請求模式 1:掃碼模式 2:本地補丁模式
  • code: 補丁加載狀態碼, 詳情查看PatchStatusCode類說明
  • info: 補丁加載詳細說明, 詳情查看PatchStatusCode類說明
  • handlePatchVersion: 當前處理的補丁版本號, 0:無 -1:本地補丁 其它:後臺補丁

這裏列舉幾個常見的code碼說明,

  • code: 1 補丁加載成功
  • code: 6 服務端沒有最新可用的補丁
  • code: 11 RSASECRET錯誤,官網中的密鑰是否正確請檢查
  • code: 12 當前應用已經存在一箇舊補丁, 應用重啓嘗試加載新補丁
  • code: 13 補丁加載失敗, 導致的原因很多種, 比如UnsatisfiedLinkError等異常, 此時應該嚴格檢查logcat異常日誌
  • code: 16 APPSECRET錯誤,官網中的密鑰是否正確請檢查
  • code: 18 一鍵清除補丁
  • code: 19 連續兩次queryAndLoadNewPatch()方法調用不能短於3s

詳情查看SDK中PatchStatus類的代碼,有具體說明:

  1. package com.taobao.sophix;
  2. public class PatchStatus {
  3. public final static int CODE_REQ_START = 0;
  4. public final static String INFO_REQ_START = "ready to start.";
  5. public final static int CODE_LOAD_SUCCESS = 1;
  6. public final static String INFO_LOAD_SUCCESS = "load new patch success.";
  7. public final static int CODE_ERR_NOTINIT = 2;
  8. public final static String INFO_ERR_NOTINIT = "didn't initialize hotfix sdk or initialize fail.";
  9. public final static int CODE_ERR_NOTMAIN = 3;
  10. public final static String INFO_ERR_NOTMAIN = "only allow query in main process.";
  11. public final static int CODE_ERR_INBLACKLIST = 4;
  12. public final static String INFO_ERR_INBLACKLIST = "current device does't support hotfix.";
  13. public final static int CODE_REQ_ERR = 5;
  14. public final static String INFO_REQ_ERR = "pull patch info detail fail, please check log.";
  15. public final static int CODE_REQ_NOUPDATE = 6;
  16. public final static String INFO_REQ_NOUPDATE = "there is not update.";
  17. public final static int CODE_REQ_NOTNEWEST = 7;
  18. public final static String INFO_REQ_NOTNEWEST = "the query patchversion equals or less than current patchversion, stop download.";
  19. public final static int CODE_DOWNLOAD_FAIL = 8;
  20. public final static int CODE_DOWNLOAD_SUCCESS = 9;
  21. public final static String INFO_DOWNLOAD_SUCCESS = "patch download success.";
  22. public final static int CODE_DOWNLOAD_BROKEN = 10;
  23. public final static String INFO_DOWNLOAD_BROKEN = "patch file is broken.";
  24. public final static int CODE_UNZIP_FAIL = 11;
  25. public final static String INFO_UNZIP_FAIL = "unzip patch file error, please check value of AndroidMenifest.xml RSASECRET or initialize param aesKey.";
  26. public final static int CODE_LOAD_RELAUNCH = 12;
  27. public final static String INFO_LOAD_RELAUNCH = "please relaunch app to load new patch.";
  28. public final static int CODE_LOAD_FAIL = 13;
  29. public final static String INFO_LOAD_FAIL = "load patch fail, please check stack trace of an exception: ";
  30. public final static int CODE_LOAD_NOPATCH = 14;
  31. public final static String INFO_LOAD_NOPATCH = "do not found any patch file to load.";
  32. public final static int CODE_REQ_APPIDERR = 15;
  33. public final static String INFO_REQ_APPIDERR = "appid is not found.";
  34. public final static int CODE_REQ_SIGNERR = 16;
  35. public final static String INFO_REQ_SIGNERR = "token is invaild, please check APPSECRET.";
  36. public final static int CODE_REQ_UNAVAIABLE = 17;
  37. public final static String INFO_REQ_UNAVAIABLE = "req is unavailable as has already been in arrearage.";
  38. public final static int CODE_REQ_CLEARPATCH = 18;
  39. public final static String INFO_REQ_CLEARPATCH = "clean client patch as server publish clear cmd.";
  40. public final static int CODE_REQ_TOOFAST = 19;
  41. public final static String INFO_REQ_TOOFAST = "two consecutive request should not short then 3s.";
  42. public final static int CODE_PATCH_INVAILD = 20;
  43. public static final String INFO_PATCH_INVAILD = "patch invaild, as patch not exist or is dir or not a jar compress file.";
  44. public final static int CODE_LOAD_FORBIDDEN = 21;
  45. public static final String INFO_LOAD_FORBIDDEN = "debuggable is false! forbid loading local patch for secure reason!";
  46. }

1.4 版本管理說明

說明一:patch是針對客戶端具體某個版本的,patch和具體版本綁定

  • eg. 應用當前版本號是1.1.0, 那麼只能在後臺查詢到1.1.0版本對應發佈的補丁, 而查詢不到之前1.0.0舊版本發佈的補丁.

說明二:針對某個具體版本發佈的新補丁, 必須包含所有的bugfix, 而不能依賴補丁遞增修復的方式, 因爲應用僅可能加載一個補丁

  • eg. 針對1.0.0版本在後臺發佈了一個補丁版本號爲1的補丁修復了bug1, 然後發現此時針對這個版本補丁1修復的不完全, 代碼還有bug2, 在後臺重新發佈一個補丁版本號爲2的補丁, 那麼此時補丁2就必須同時包含bug1和bug2的修復才行, 而不是隻包含bug2的修復(bug1就沒被修復了)

1.5 客戶端本地SDK及DEMO下載

下載客戶端SDK並集成(下載地址),Demo程序(Github)

1.6 注意事項

發佈前請嚴格按照:掃碼內測 => 灰度發佈 => 全量發佈的流程進行,以保證補丁包能夠正常在所有Android版本的機型上生效。爲了保險起見,理論上應該對每個版本的android手機都測一遍是否生效會比較好。不過,其實只需測試通過以下具有代表性的Android版本就基本沒什麼大問題了:4.0、4.4、5.1、7.0

四,生成補丁

2.1 下載打包工具

patch補丁包生成需要使用到打補丁工具SophixPatchTool, 如還未下載打包工具,請前往下載Android打包工具。

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

2.2 生成Patch

2.2.1 主對話框

sophix1

  • 舊包:<必填> 選擇基線包路徑(有問題的APK)。
  • 新包:<必填> 選擇新包路徑(修復過該問題APK)。
  • 日誌:打開日誌輸出窗口。
  • 高級:展開高級選項,見2.2.3。
  • 設置:配置其他信息。
  • GO!:開始生成補丁。

2.2.2 主對話框 - 高級選項

sophix2

  • 強制冷啓動:勾選的話強制生成補丁包爲需要冷啓動才能修復的格式。默認不選的話,工具會根據代碼變更情況自動選擇即時熱替換或者冷啓動修復。
  • 不比較資源:打補丁時不比較資源的變化。
  • 不比較SO庫:打補丁時不比較SO庫的變化。

2.2.3 設置對話框

tool

  • 補丁輸出路徑:<必填> 指定生成補丁之後補丁的存放位置,必須是已存在的目錄。
  • Key Store Path:<選填>本地的簽名文件的路徑,不輸入則不做簽名。
  • Key Store Password:<選填>證書文件的密碼。
  • Key Alias:<選填>Key的別名。
  • Key Passwrod:<選填>Key的密碼。
  • AES Key:<選填>自定義aes祕鑰, 必須是16位數字或字母的組合。必須與setAesKey中設置的祕鑰一致。
  • Filter Class File:<選填>本地的白名單類列表文件的路徑,放進去的類不會再計算patch,文件格式: 一行一個類名。

五,調試和發佈補丁

調試工具用於patch正式發佈前的調試環節

  • 掃碼二維碼方式,將剛剛上傳到後臺的補丁通過掃描二維碼下載到本地,嘗試加載補丁;
  • 應用本地補丁方式,傳入本地補丁的絕對路徑,嘗試加載補丁。

如還未下載調試工具,請下載Android調試工具,地址如下

調試工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/hotfix_debug_tool-release.apk

連接測試的應用

  • 在編輯框內輸入要進行測試的應用包名,確認輸入無誤後點擊連接應用按鈕;
  • 工具與測試的應用建立連接,連接成功後輸出應用的信息;aidl方式連接原應用,所以在部分機型上可能導致失敗,比如MIUI最新系統上,默認禁用了跨應用aidl,MIUI上可以設置取消這個限制,其它系統類似處理。

應用補丁

掃描二維碼方式

  • 打補丁工具生成的sophix-patch.jar補丁包上傳到hotfix產品後臺;
  • 點擊掃描二維碼按鈕,打開二維碼頁面,將二維碼置於掃描框內;
  • 掃描完成以後返回,輸出掃描到的patch地址,嚮應用發出拉取patch的請求;
  • patch拉取和加載狀態在輸出臺輸出,當顯示下載和加載成功,打開應用進行檢查。¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

應用本地補丁方式

  • 打補丁工具生成的sophix-patch.jar補丁包推送到本地存儲任何一個目錄下;
  • 應用本地補丁按鈕上面的輸入框輸入補丁在手機存儲中的絕對路徑;
  • 補丁加載狀態在輸出臺輸出,當顯示下載和加載成功,打開應用進行檢查。

斷開連接的應用

點擊斷開應用連接按鈕,將斷開與應用的連接。調試到此結束。

清除通知內容

當輸出臺顯示信息過多時,可點擊清除下列通知內容按鈕對通知信息進行清除。

使用示例

使用示例

  • 下載demo工程後, 安裝並打開old.apk, 安裝調試工具;
  • 輸入“com.taobao.hotfix.demo”包名, 連接應用, 提示連接成功;
  • 應用本地補丁示例

    • 補丁工具生成的補丁包sophix-patch.jar推送到本地的/sdcard/Download目錄, 然後輸入該補丁包的絕對路徑, 點擊應用本地補丁按鈕;
    • Mode:2 表示本地補丁模式, Code:1 表示加載成功 HandlePatchVersion:-1 表示本地補丁
  • 掃描二維碼示例

    • 補丁工具生成的補丁包sophix-patch.jar上傳到hotfix控制檯;
    • 點擊掃描二維碼按鈕掃後臺補丁二維碼;
    • Mode:1 表示掃碼模式, Code:12 表示應用當前已經有一個補丁, 所以新補丁不會立刻加載需要等下一次重啓加載, HandlePatchVersion:89 表示後臺拉取下來的補丁版本89。


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