前言
最近年底項(xiàng)目也沒(méi)事做了,琢磨著研究一下熱修復(fù)方案。市面上出現(xiàn)很多熱修復(fù)方案,大致分為幾種,一種是dex插樁的、一種Instant run、還有一種是通過(guò)底層做修改。本文主要研究阿里云最新的熱修復(fù)方案Sophix,Sophix較其他的優(yōu)劣勢(shì)如下,對(duì)比發(fā)現(xiàn)Sophix熱修復(fù)最大的特點(diǎn)就是即使生效(已有方法修改)和冷啟動(dòng)修復(fù)(新增方法和資源修改),并且Sophix已經(jīng)做到兼容Android P,目前市場(chǎng)上比較成熟的主要是微信Tinker和阿里的Sophix,另一篇Android——Tinker熱修復(fù)接入

創(chuàng)建項(xiàng)目
1.1 注冊(cè)登錄
阿里云官網(wǎng)->登陸賬號(hào)->產(chǎn)品->企業(yè)應(yīng)用->移動(dòng)云下面的熱修復(fù),切換到當(dāng)前頁(yè)面先去注冊(cè)登錄,登錄之后,如果是之前沒(méi)用過(guò),會(huì)顯示立即開(kāi)通,之前已經(jīng)開(kāi)通的話會(huì)直接顯示管理控制臺(tái)如下圖所示:

1.2 開(kāi)通產(chǎn)品
如果是第一次使用阿里云產(chǎn)品會(huì)先開(kāi)通使用產(chǎn)品,開(kāi)通之后如下圖所示,點(diǎn)擊加號(hào)開(kāi)通產(chǎn)品,產(chǎn)品里面包含一系列,相當(dāng)于一個(gè)產(chǎn)品集合,暫時(shí)只使用熱修復(fù),我開(kāi)通的如下:

1.3 創(chuàng)建熱修復(fù)項(xiàng)目
點(diǎn)擊下圖的加號(hào)即可創(chuàng)建項(xiàng)目,創(chuàng)建總分為三步,具體如下圖:


第二步會(huì)產(chǎn)生一個(gè)json文件,是當(dāng)前項(xiàng)目所有阿里云產(chǎn)品的配置,如果只做熱修復(fù),只需要關(guān)心熱修復(fù)的三個(gè)主要參數(shù),如下圖所示的參數(shù)(appKey、hotfix.idSecret、hotfix.rsaSecret)。下面是配置信息,如果按照正常接入步驟可以按照文檔接入,本文主要采用兼容Android 9.0穩(wěn)健方式接入,下面的json配置文件盡量不要按照普通接入方式復(fù)制在項(xiàng)目下(除非是測(cè)試項(xiàng)目)。
"config": {
"emas.appKey":"27478432",
"emas.appSecret":"5e2f53a5aa6b8a48e74ac7146688b65c",
"emas.packageName":"com.example.testsophix",
"hotfix.idSecret":"2547832-1",
"hotfix.rsaSecret":"http://////",
"httpdns.accountId":"102949",
"httpdns.secretKey":"826b1d8ad5119dd34f1a855eedd3cea0"
說(shuō)明:
- 應(yīng)用名稱可以隨意填寫(xiě),建議填寫(xiě)項(xiàng)目中的appname,如果以后項(xiàng)目多避免混亂
- 包名一定要填寫(xiě)清單列表中包名
-
建議json配置不要放在項(xiàng)目中,如果忘記下載json配置也沒(méi)關(guān)系,創(chuàng)建之后如下圖所示點(diǎn)擊下載配置即可獲取配置文件
下載配置.png
項(xiàng)目接入SDK
本文主要接入Sophix穩(wěn)健方式的,兼容Android9.0,因?yàn)锳ndroid9.0對(duì)于部分熱修復(fù)方式做簡(jiǎn)單修改,如果普通接入會(huì)出現(xiàn)奔潰或者修復(fù)不成功問(wèn)題,下面是具體接入Android studio(3.0)方式,更多方式參考文檔。
2.1 Project的build.gradle配置
Project項(xiàng)目下的build.gradle文件,添加maven倉(cāng)庫(kù)地址,添加如下配置:
repositories {
maven {
url "http://maven.aliyun.com/nexus/content/repositories/releases"
}
}
2.2 module級(jí)別build.gradle配置
module下build.gradle文件添加版本依賴:
compile 'com.aliyun.ams:alicloud-android-hotfix:3.2.7'
2.3 權(quán)限配置
<! -- 網(wǎng)絡(luò)權(quán)限 -->
<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" />
<! -- 外部存儲(chǔ)讀權(quán)限,調(diào)試工具加載本地補(bǔ)丁需要 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
說(shuō)明:
- 當(dāng)使用調(diào)試工具(后面會(huì)提)調(diào)試補(bǔ)丁的時(shí)候,如果補(bǔ)丁放在本地,需要加讀權(quán)限,并且Android 6.0以上的讀寫(xiě)權(quán)限動(dòng)態(tài)申請(qǐng)
- 聯(lián)網(wǎng)權(quán)限是用于拉取阿里服務(wù)器補(bǔ)丁
2.4 配置SDK參數(shù)
配置參數(shù)有兩種方式,一種是清單列表中,第二種是在項(xiàng)目的Application中通過(guò)參數(shù)的形式,推薦使用第二種(相對(duì)較為安全)
2.4.1 AndroidManifest文件配置SDK參數(shù)
其中三個(gè)參數(shù)對(duì)應(yīng)上文提到的json文件里面的三個(gè)參數(shù)
<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密鑰" />
2.4.2 代碼中配置SDK參數(shù)
SophixManager.getInstance()
.setContext(this)
.setAppVersion(appVersion)
.setSecretMetaData(null, null, null)//這里填寫(xiě)參數(shù)
.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) {
// 如果需要在后臺(tái)重啟,建議此處用SharePreference保存狀態(tài)。
Log.i(TAG, "sophix preload patch success. restart app to make effect.");
}
}
}).initialize();
- Sophix初始化的時(shí)候.setSecretMetaData(null, null, null)設(shè)置三個(gè)參數(shù),順序依次跟AndroidManifest一致。
2.5 混淆配置
#基線包使用,生成mapping.txt
-printmapping mapping.txt
#生成的mapping.txt在app/build/outputs/mapping/release路徑下,移動(dòng)到/app路徑下
#修復(fù)后的項(xiàng)目使用,保證混淆結(jié)果一致
#-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.example.testsophix.MyRealApplication {
public <init>();
}
說(shuō)明:如果項(xiàng)目混淆開(kāi)啟的情況下,在app/build/outputs/mapping/release路徑下會(huì)生成mapping.txt,建議開(kāi)啟混淆(保證一些參數(shù)被混淆)。
2.6 SDK初始化
此穩(wěn)健方式接入,使用了最新版本的Sophix,最新版本的Sophix采用了代理Application方式接入SDK,使自身的Application和Sophix初始化解耦合。初始化在繼承SophixApplication的SophixStubApplication(名稱可以自定義)中實(shí)現(xiàn),其中自身的Application不需要做任何修改操作。
2.6.1 Application中初始化Sophix
public class SophixStubApplication extends SophixApplication {
private final String TAG = "SophixStubApplication";
private final String hotfixId = "25478432-1";
private final String hotfixappKey = "5e2f53a5aa6b8a48e74ac7146688b65c";
/**
* 此處SophixEntry應(yīng)指定真正的Application,
* 并且保證RealApplicationStub類(lèi)名不被混淆。
*
* @keep 注解已經(jīng)做好了,無(wú)需在混淆文件做處理
*/
@Keep
@SophixEntry(MyRealApplication.class)
static class RealApplicationStub {
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
//如果需要使用MultiDex,需要在此處調(diào)用。
// MultiDex.install(this);
initSophix();
}
@Override
public void onCreate() {
super.onCreate();
//聯(lián)網(wǎng)下載新的插件
SophixManager.getInstance().queryAndLoadNewPatch();
}
/**
* initialize最好放在attachBaseContext最前面
*/
private void initSophix() {
SophixManager.getInstance().setContext(this)
.setAppVersion(BuildConfig.VERSION_NAME)
.setAesKey(null)
.setSecretMetaData(hotfixId,hotfixappKey,getString(R.string.hotfixrsaSecret))
.setEnableDebug(true)
.setPatchLoadStatusStub(new PatchLoadStatusListener() {
@Override
public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
Log.e(TAG, "修復(fù)模式:" + mode);
Log.e(TAG, "修復(fù)回調(diào)code:" + code);
Log.e(TAG, "修復(fù)信息:" + info);
Log.e(TAG, "修復(fù)版本:" + handlePatchVersion);
// 補(bǔ)丁加載回調(diào)通知
if (code == PatchStatus.CODE_LOAD_SUCCESS) {
// 表明補(bǔ)丁加載成功
Log.e(TAG, "表明補(bǔ)丁加載成功");
} else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {
// 表明新補(bǔ)丁生效需要重啟. 開(kāi)發(fā)者可提示用戶或者強(qiáng)制重啟;
// 建議: 用戶可以監(jiān)聽(tīng)進(jìn)入后臺(tái)事件, 然后應(yīng)用自殺
Log.e(TAG, "表明新補(bǔ)丁生效需要重啟. 開(kāi)發(fā)者可提示用戶或者強(qiáng)制重啟");
} else if (code == PatchStatus.CODE_LOAD_FAIL) {
// 內(nèi)部引擎異常, 推薦此時(shí)清空本地補(bǔ)丁, 防止失敗補(bǔ)丁重復(fù)加載
// SophixManager.getInstance().cleanPatches();
Log.e(TAG, "內(nèi)部引擎異常, 推薦此時(shí)清空本地補(bǔ)丁, 防止失敗補(bǔ)丁重復(fù)加載");
} else {
// 其它錯(cuò)誤信息, 查看PatchStatus類(lèi)說(shuō)明
Log.e(TAG, "其它錯(cuò)誤信息, 查看PatchStatus類(lèi)說(shuō)明");
}
}
}).initialize();
}
}
2.6.2 修改AndroidManifest里面的Application名稱
<application
android:name="com.my.pkg.SophixStubApplication"
... ...>
... ...
說(shuō)明:
- 需要把AndroidManifest里面的Application名稱改為這個(gè)新增的SophixStubApplication類(lèi)(一定要修改,否則無(wú)法初始化Sophix)
- SophixStubApplication必須要繼承SophixApplication
- @SophixEntry(MyRealApplication.class)處的MyRealApplication一定要填寫(xiě)自己本身的Application
- 這里的@Keep是android.support包中的類(lèi),目的是為了防止這個(gè)內(nèi)部靜態(tài)類(lèi)的類(lèi)名被混淆,因?yàn)閟ophix內(nèi)部會(huì)反射獲取這個(gè)類(lèi)的,如果項(xiàng)目中沒(méi)有依賴android.support的話,就需要在progurad里面手動(dòng)指定RealApplicationStub不被混淆(就是自己的Application)。(詳情參見(jiàn)文檔)例子如下:
-keepclassmembers class com.my.pkg.MyRealApplication {
public <init>();
}
# 如果不使用android.support.annotation.Keep則需加上此行
# -keep class com.my.pkg.SophixStubApplication$RealApplicationStub
2.7 接口說(shuō)明
2.7.1 initialize方法
- initialize(): <必選>
該方法主要做些必要的初始化工作以及如果本地有補(bǔ)丁的話會(huì)加載補(bǔ)丁, 但不會(huì)自動(dòng)請(qǐng)求補(bǔ)丁。因此需要自行調(diào)用queryAndLoadNewPatch方法拉取補(bǔ)丁。這個(gè)方法調(diào)用需要盡可能的早, 必須在Application的attachBaseContext方法的最前面調(diào)用(在super.attachBaseContext之后,如果有Multidex,也需要在Multidex.install之后), initialize()方法調(diào)用之前你需要先調(diào)用如下幾個(gè)方法進(jìn)行一些必要的參數(shù)設(shè)置, 方法調(diào)用說(shuō)明如下: - setContext(application): <必選> 傳入入口Application即可
- setAppVersion(appVersion): <必選> 應(yīng)用的版本號(hào)
說(shuō)明:appVersion在產(chǎn)生補(bǔ)丁的兩包必須相同,否則無(wú)法加載補(bǔ)丁
appVersion默認(rèn)取的module的build.gradle里面的versionName,當(dāng)然可以自定義,推薦使用versionName,并且最好與熱修復(fù)控制臺(tái)的版本保持一致,防止版本多了混亂。 - setSecretMetaData(idSecret, appSecret, rsaSecret): <可選,推薦使用> 三個(gè)Secret分別對(duì)應(yīng)AndroidManifest里面的三個(gè),可以不在AndroidManifest設(shè)置而是用此函數(shù)來(lái)設(shè)置Secret。放到代碼里面進(jìn)行設(shè)置可以自定義混淆代碼,更加安全,此函數(shù)的設(shè)置會(huì)覆蓋AndroidManifest里面的設(shè)置,如果對(duì)應(yīng)的值設(shè)為null,默認(rèn)會(huì)在使用AndroidManifest里面的。
- setAesKey(aesKey): <可選> 用戶自定義aes秘鑰, 會(huì)對(duì)補(bǔ)丁包采用對(duì)稱加密。這個(gè)參數(shù)值必須是16位數(shù)字或字母的組合,是和補(bǔ)丁工具設(shè)置里面AES Key保持完全一致, 補(bǔ)丁才能正確被解密進(jìn)而加載。此時(shí)平臺(tái)無(wú)感知這個(gè)秘鑰, 所以不用擔(dān)心阿里云移動(dòng)平臺(tái)會(huì)利用你們的補(bǔ)丁做一些非法的事情。
- setPatchLoadStatusStub(new PatchLoadStatusListener()): <可選,推薦> 設(shè)置patch加載狀態(tài)監(jiān)聽(tīng)器, 該方法參數(shù)需要實(shí)現(xiàn)PatchLoadStatusListener接口, 接口參數(shù)說(shuō)明見(jiàn)2.7.2說(shuō)明
2.7.2 PatchLoadStatusListener接口
該接口需要自行實(shí)現(xiàn)并傳入initialize方法中, 補(bǔ)丁加載狀態(tài)會(huì)回調(diào)給該接口, 參數(shù)說(shuō)明如下:
- mode: 無(wú)實(shí)際意義, 為了兼容老版本, 默認(rèn)始終為0
- code: 補(bǔ)丁加載狀態(tài)碼(code=1代表加載成功), 更多文檔(超鏈接)PatchStatus類(lèi)說(shuō)明
- info: 補(bǔ)丁加載詳細(xì)說(shuō)明
- handlePatchVersion: 當(dāng)前處理的補(bǔ)丁版本號(hào), 0:無(wú) -1:本地補(bǔ)丁 其它:后臺(tái)補(bǔ)丁
2.7.3 queryAndLoadNewPatch方法
該方法主要用于查詢服務(wù)器是否有新的可用補(bǔ)丁. SDK內(nèi)部限制連續(xù)兩次queryAndLoadNewPatch()方法調(diào)用不能短于3s, 否則的話就會(huì)報(bào)code:19的錯(cuò)誤碼. 如果查詢到可用的話, 首先下載補(bǔ)丁到本地。
應(yīng)用原本沒(méi)有補(bǔ)丁, 那么如果當(dāng)前應(yīng)用的補(bǔ)丁是熱補(bǔ)丁, 那么會(huì)立刻加載(不管是冷補(bǔ)丁還是熱補(bǔ)丁). 如果當(dāng)前應(yīng)用的補(bǔ)丁是冷補(bǔ)丁, 那么需要重啟生效.
應(yīng)用已經(jīng)存在一個(gè)補(bǔ)丁, 請(qǐng)求發(fā)現(xiàn)有新補(bǔ)丁后,本次不受影響。并且在下次啟動(dòng)時(shí)補(bǔ)丁文件刪除, 下載并預(yù)加載新補(bǔ)丁。在下下次啟動(dòng)時(shí)應(yīng)用新補(bǔ)丁。
補(bǔ)丁在后臺(tái)發(fā)布之后, 并不會(huì)主動(dòng)下行推送到客戶端, 需要手動(dòng)調(diào)用queryAndLoadNewPatch方法查詢后臺(tái)補(bǔ)丁是否可用.
只會(huì)下載補(bǔ)丁版本號(hào)比當(dāng)前應(yīng)用存在的補(bǔ)丁版本號(hào)高的補(bǔ)丁, 比如當(dāng)前應(yīng)用已經(jīng)下載了補(bǔ)丁版本號(hào)為5的補(bǔ)丁, 那么只有后臺(tái)發(fā)布的補(bǔ)丁版本號(hào)>5才會(huì)重新下載.
同時(shí)1.4.0以上版本服務(wù)后臺(tái)上線了“一鍵清除”補(bǔ)丁的功能, 所以如果后臺(tái)點(diǎn)擊了“一鍵清除”那么這個(gè)方法將會(huì)返回code:18的狀態(tài)碼. 此時(shí)本地補(bǔ)丁將會(huì)被強(qiáng)制清除, 同時(shí)不清除本地補(bǔ)丁版本號(hào)
2.7.4 killProcessSafely方法
可以在PatchLoadStatusListener監(jiān)聽(tīng)到CODE_LOAD_RELAUNCH后在合適的時(shí)機(jī),調(diào)用此方法殺死進(jìn)程。注意,不可以直接Process.killProcess(Process.myPid())來(lái)殺進(jìn)程,這樣會(huì)擾亂Sophix的內(nèi)部狀態(tài)。因此如果需要?dú)⑺肋M(jìn)程,建議使用這個(gè)方法,它在內(nèi)部做一些適當(dāng)處理后才殺死本進(jìn)程。
2.7.5 cleanPatches()方法
清空本地補(bǔ)丁,并且不再拉取被清空的版本的補(bǔ)丁。正常情況下不需要開(kāi)發(fā)者自己調(diào)用,因?yàn)镾ophix內(nèi)部會(huì)判斷對(duì)補(bǔ)丁引發(fā)崩潰的情況進(jìn)行自動(dòng)清空。
補(bǔ)丁管理
簡(jiǎn)單說(shuō)一下Sophix修復(fù)的過(guò)程,首先需要兩個(gè)apk包,一個(gè)是線上或者測(cè)試bug包,另一個(gè)是修復(fù)好問(wèn)題的apk包,通過(guò)使用補(bǔ)丁工具,兩個(gè)不同apk包會(huì)產(chǎn)生一個(gè)補(bǔ)丁,補(bǔ)丁上傳阿里服務(wù)器,掃碼下載補(bǔ)丁或者手動(dòng)存放到本地,千萬(wàn)不要一開(kāi)始就直接發(fā)布補(bǔ)丁,首先要用調(diào)試工具調(diào)試一下,查看是否完全符合自己的要求,當(dāng)補(bǔ)丁符合要求再去發(fā)布,具體發(fā)布詳情見(jiàn)下面的發(fā)布。并且要保證兩個(gè)包是同一個(gè)版本,一個(gè)版本同時(shí)只能存在一個(gè)補(bǔ)丁,所以如果當(dāng)前最近的補(bǔ)丁不是第一個(gè)補(bǔ)丁,那么最新的補(bǔ)丁一定是結(jié)合修復(fù)了之前所有補(bǔ)丁之后通過(guò)補(bǔ)丁工具生成的補(bǔ)丁。
3.1 創(chuàng)建補(bǔ)丁
3.1.1 下載補(bǔ)丁和調(diào)試工具
patch補(bǔ)丁包生成需要使用到打補(bǔ)丁工具SophixPatchTool, 如還未下載打包工具,請(qǐng)前往下載Android打包工具。
Mac版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_macos.zip
Windows版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_windows.zip
Linux版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_linux.zip
調(diào)試工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/hotfix_debug_tool-release.apk
該工具提供了Windows和macOS和Linux版本,Windows下運(yùn)行SophixPatchTool.exe,macOS下運(yùn)行SophixPatchTool.app,Linux下(Ubuntu 16.04 64bit最佳)運(yùn)行SophixPatchTool。并且需要安裝Java環(huán)境且在JDK7或以上才能正常使用。
說(shuō)明:一些注意事項(xiàng)在補(bǔ)丁工具中會(huì)介紹(兩張圖片介紹)
3.1.2 補(bǔ)丁工具使用
解壓補(bǔ)丁工具,運(yùn)行SophixPatchTool.exe,如下圖:


說(shuō)明:
- 簽名是必須要填寫(xiě)的,高級(jí)設(shè)置里面一些參數(shù),具體情況而定
- 產(chǎn)生的補(bǔ)丁一定不要修改名稱(補(bǔ)丁名稱:sophix-patch.jar)
3.2 上傳補(bǔ)丁
進(jìn)入阿里云控制臺(tái),點(diǎn)擊右側(cè)的移動(dòng)熱修復(fù),進(jìn)入項(xiàng)目補(bǔ)丁管理

如上圖在管理控制臺(tái),找到質(zhì)量管理下面的移動(dòng)熱修復(fù)進(jìn)入到補(bǔ)丁管理頁(yè)面
3.2.1 添加補(bǔ)丁版本
此處添加的版本盡量與項(xiàng)目中的versionname保持一致

3.2.2 上傳補(bǔ)丁
上傳補(bǔ)丁里面描述,盡量要描述當(dāng)前補(bǔ)丁修復(fù)那些內(nèi)容,方便以后版本的回滾

3.2.3 發(fā)布調(diào)試補(bǔ)丁
點(diǎn)擊發(fā)布之后,需要我們進(jìn)行調(diào)試發(fā)布補(bǔ)丁,接下來(lái)進(jìn)入調(diào)試、發(fā)布補(bǔ)丁階段

調(diào)試補(bǔ)丁
4.1 調(diào)試工具使用

使用說(shuō)明:
1、使用工具調(diào)試之前一定要先安裝有bug的版本
2 、接下來(lái)連接應(yīng)用
3、加載補(bǔ)丁有兩種方式,一種是掃碼二維碼的方式,第二種是加載補(bǔ)丁放在本地,直接加載(本地加載需要讀權(quán)限,涉及到Android6.0動(dòng)態(tài)權(quán)限的設(shè)置),推薦使用掃描方式加載補(bǔ)丁。
4、通過(guò)下方的日志獲取當(dāng)前補(bǔ)丁的加載過(guò)程
4.2 加載補(bǔ)丁

掃描補(bǔ)丁之后查看調(diào)試工具日志輸出,查看補(bǔ)丁情況,如果之前打補(bǔ)丁的時(shí)候高級(jí)設(shè)置里面設(shè)置強(qiáng)制冷啟動(dòng),一定要先殺死當(dāng)前測(cè)試熱修復(fù)應(yīng)用的進(jìn)程,然后再次打開(kāi)查看打補(bǔ)丁之后的情況。下面列舉日志code碼經(jīng)常出現(xiàn)的幾種情況更多code值請(qǐng)查看接口文檔(超鏈接):
4.3 輸出補(bǔ)丁日志

int CODE_LOAD_SUCCESS = 1;//加載階段, 成功
int CODE_ERR_INBLACKLIST = 4;//加載階段, 失敗設(shè)備不支持
int CODE_REQ_NOUPDATE = 6;//查詢階段, 沒(méi)有發(fā)布新補(bǔ)丁
int CODE_REQ_NOTNEWEST = 7;//查詢階段, 補(bǔ)丁不是最新的
int CODE_DOWNLOAD_SUCCESS = 9;//查詢階段, 補(bǔ)丁下載成功
int CODE_DOWNLOAD_BROKEN = 10;//查詢階段, 補(bǔ)丁文件損壞下載失敗
int CODE_UNZIP_FAIL = 11;//查詢階段, 補(bǔ)丁解密失敗
int CODE_LOAD_RELAUNCH = 12;//預(yù)加載階段, 需要重啟
int CODE_REQ_APPIDERR = 15;//查詢階段, appid異常
int CODE_REQ_SIGNERR = 16;//查詢階段, 簽名異常
int CODE_REQ_UNAVAIABLE = 17;//查詢階段, 系統(tǒng)無(wú)效
int CODE_REQ_SYSTEMERR = 22;//查詢階段, 系統(tǒng)異常
int CODE_REQ_CLEARPATCH = 18;//查詢階段, 一鍵清除補(bǔ)丁
int CODE_PATCH_INVAILD = 20;//加載階段, 補(bǔ)丁格式非法
4.4 補(bǔ)丁說(shuō)明
說(shuō)明一:patch是針對(duì)客戶端具體某個(gè)版本的,patch和具體版本綁定
- 應(yīng)用當(dāng)前版本號(hào)是1.1.0, 那么只能在后臺(tái)查詢到1.1.0版本對(duì)應(yīng)發(fā)布的補(bǔ)丁, 而查詢不到之前1.0.0舊版本發(fā)布的補(bǔ)丁.
說(shuō)明二:針對(duì)某個(gè)具體版本發(fā)布的新補(bǔ)丁, 必須包含所有的bugfix, 而不能依賴補(bǔ)丁遞增修復(fù)的方式, 因?yàn)閼?yīng)用僅可能加載一個(gè)補(bǔ)丁
- 針對(duì)1.0.0版本在后臺(tái)發(fā)布了一個(gè)補(bǔ)丁版本號(hào)為1的補(bǔ)丁修復(fù)了bug1, 然后發(fā)現(xiàn)此時(shí)針對(duì)這個(gè)版本補(bǔ)丁1修復(fù)的不完全, 代碼還有bug2, 在后臺(tái)重新發(fā)布一個(gè)補(bǔ)丁版本號(hào)為2的補(bǔ)丁, 那么此時(shí)補(bǔ)丁2就必須同時(shí)包含bug1和bug2的修復(fù)才行, 而不是只包含bug2的修復(fù)(bug1就沒(méi)被修復(fù)了)
發(fā)布補(bǔ)丁
發(fā)布前請(qǐng)嚴(yán)格按照:掃碼內(nèi)測(cè) => 灰度發(fā)布 => 全量發(fā)布的流程進(jìn)行,以保證補(bǔ)丁包能夠正常在所有Android版本的機(jī)型上生效。為了保險(xiǎn)起見(jiàn),理論上應(yīng)該對(duì)每個(gè)版本的android手機(jī)都測(cè)一遍是否生效會(huì)比較好。不過(guò),其實(shí)只需測(cè)試通過(guò)以下具有代表性的Android版本就基本沒(méi)什么大問(wèn)題了:4.0、4.4、5.1、7.0
注意事項(xiàng)
具體接入細(xì)節(jié)請(qǐng)參考官方文檔:
非穩(wěn)健方式接入
穩(wěn)健方式接入
