Tinker熱修復(fù)集成

Tinker與Tinker Patch平臺(tái)介紹


什么是 Tinker?


Tinker 是一個(gè)開(kāi)源項(xiàng)目(Github鏈接),它是微信官方的 Android 熱補(bǔ)丁解決方案,它支持動(dòng)態(tài)下發(fā)代碼、So 庫(kù)以及資源,讓?xiě)?yīng)用能夠在不需要重新安裝的情況下實(shí)現(xiàn)更新。

Tinker 的優(yōu)勢(shì)


當(dāng)前市面的熱補(bǔ)丁方案有很多,其中比較出名的有阿里的 AndFix、美團(tuán)的 Robust 以及 QZone 的超級(jí)補(bǔ)丁方案。但它們都存在無(wú)法解決的問(wèn)題,具體支持程度如下:

image

Tinker方案優(yōu)勢(shì)

  1. 不用在構(gòu)造函數(shù)插入代碼,防止verify(全量合成Dex以避免verify標(biāo)志的異常)。
  2. 支持新增類和資源、so等。
  3. dexDiff算法使得補(bǔ)丁文件較小。
  4. gradle支持,再自己定義下可以一鍵打補(bǔ)丁包。
  5. 擴(kuò)展性良好,代碼中處處為開(kāi)發(fā)者留出開(kāi)放接口,簡(jiǎn)直業(yè)界良心。
  6. 支持多次補(bǔ)丁及補(bǔ)丁清除。
  7. Application 和其提前加載的類都是可以進(jìn)行修復(fù)的。

Tinker 詳細(xì)使用文檔見(jiàn) [Tinker Github Wiki]。

Tinker的不足


由于原理與系統(tǒng)限制,Tinker有以下已知問(wèn)題:

  1. Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大組件(1.9.0支持新增非export的Activity);
  2. 由于Google Play的開(kāi)發(fā)者條款限制,不建議在GP渠道動(dòng)態(tài)更新代碼;
  3. 在Android N上,補(bǔ)丁對(duì)應(yīng)用啟動(dòng)時(shí)間有輕微的影響;
  4. 補(bǔ)丁合成產(chǎn)物比較占手機(jī)Rom內(nèi)存空間。
  5. 包含多Dex的補(bǔ)丁,需要開(kāi)啟多個(gè)進(jìn)程分別對(duì)每個(gè)Dex進(jìn)行合并,比較占用開(kāi)銷。
  6. 不支持部分三星android-21機(jī)型,加載補(bǔ)丁時(shí)會(huì)主動(dòng)拋出”TinkerRuntimeException:checkDexInstall failed”;
  7. 對(duì)于資源替換,不支持修改remoteView。例如transition動(dòng)畫(huà),notification icon以及桌面圖標(biāo)。

Tinker的原理及工作流程簡(jiǎn)述


與其他熱更新方案不同的是,tinker使用自研的DexDiff算法生成補(bǔ)丁包(關(guān)于DexDiff的亮點(diǎn)見(jiàn) https://www.zybuluo.com/dodola/note/554061),
然后將補(bǔ)丁包與基線包合并成新的dex文件,從而全量替換原有的dex,而不是像某些熱修復(fù)方案那樣將補(bǔ)丁放到另一個(gè)dex中。即全量合成Dex以避免verify標(biāo)志的異常。

image.png

image.png

TinkerPatch 平臺(tái)


使用tinker之后,需要管理自己的補(bǔ)丁包以及對(duì)應(yīng)的基礎(chǔ)版本,并且需要開(kāi)發(fā)一套補(bǔ)丁下發(fā)的后端服務(wù),并且需要支持開(kāi)發(fā)調(diào)試、灰度測(cè)試、正式發(fā)布等功能,而且需要保證傳輸安全(畢竟補(bǔ)丁包是直接作用于我們的APP的,被人攔截將是災(zāi)難性的打擊)。
干這些事情的平臺(tái)其實(shí)有很多,而TinkerPatch平臺(tái)就是其中之一,而且它是官方推薦的一個(gè)平臺(tái)。它的開(kāi)發(fā)者本身也是來(lái)自tinker團(tuán)隊(duì),所以這里面的官方支持程度可想而知。

TinkerPatch 平臺(tái)幫你做了這些工作,提供了補(bǔ)丁后臺(tái)托管,版本管理,保證傳輸安全等功能,讓你無(wú)需搭建一個(gè)后臺(tái),無(wú)需關(guān)心部署操作,只需引入一個(gè) SDK 即可立即使用 Tinker。
此外,通過(guò)深入研究 Tinker 源碼,TinkerTinkerPatch 平臺(tái)在 Tinker的基礎(chǔ)上加入了以下特性:

  1. 一鍵傻瓜式接入;無(wú)需理解復(fù)雜的熱修復(fù)原理,一行代碼即可接入熱修復(fù)。實(shí)現(xiàn)了自動(dòng)反射 Appliction 與 Library,使用者無(wú)需對(duì)自己的項(xiàng)目做任何的改動(dòng);
  2. 補(bǔ)丁管理;實(shí)現(xiàn)了熱補(bǔ)丁的版本管理,補(bǔ)丁的自動(dòng)重試與異常時(shí)自動(dòng)回退等功能。同時(shí)我們可以簡(jiǎn)單實(shí)現(xiàn)條件下發(fā)補(bǔ)丁,在出現(xiàn)異常情況時(shí),我們也可以快速回滾補(bǔ)丁;
  3. 編譯優(yōu)化;簡(jiǎn)化了 Tinker 的編譯復(fù)雜度,實(shí)現(xiàn)了備份路徑選擇,功能開(kāi)關(guān)等功能。

TinkerPatch 平臺(tái)在 Github 為大家提供了各種各樣的 Sample,大家可點(diǎn)擊前往 [TinkerPatch Github].

官方對(duì)它的優(yōu)勢(shì)總結(jié)如下:

image

其他


  1. 它支持開(kāi)發(fā)預(yù)覽
  2. 它支持補(bǔ)丁回滾
  3. 支持灰度下發(fā)、條件下發(fā)
  4. 支持配置具體的補(bǔ)丁拉取策略
  5. 支持新增Activity,但是不支持新增Service

集成步驟


  1. 引入tinker patch gradle插件
  2. 引入tinker patch SDK
  3. 配置tinker patch
  4. 在代碼中添加支持,設(shè)置補(bǔ)丁下發(fā)策略、回滾策略、補(bǔ)丁生效機(jī)制等等
  5. 生成基線包,正常打包,由于引入了tinker patch gradle插件,所以打包時(shí)會(huì)自動(dòng)生成當(dāng)前基線包以及附屬的文件
  6. 業(yè)務(wù)需要、緊急修復(fù),修改代碼
  7. 使用tinkerPatchRelease任務(wù),生成補(bǔ)丁包,該補(bǔ)丁包是相對(duì)于指定的基線包而言的
  8. 在tinker patch后臺(tái)上傳補(bǔ)丁包,選擇‘開(kāi)發(fā)調(diào)試’模式下發(fā)
  9. 開(kāi)發(fā)調(diào)試,測(cè)試是否生效,以及是否有其他bug
  10. 灰度測(cè)試
  11. 正式全量下發(fā)

具體實(shí)施過(guò)程


1. 引入tinker patch gradle插件

在工程根目錄

// TinkerPatch 插件
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.8"
image

2. 引入tinker patch SDK

在moudle的build.gradle文件中加入如下依賴包:

compile "com.android.support:multidex:1.0.3"
//無(wú)需引入tinker的任何庫(kù),使用tinkerpatch sdk即可
compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.8")
image

3. 配置tinker patch

首先,將官方提供的tinkerpatch.gradle腳本文件放到moudle根目錄下(根build.gradle在相同目錄),然后在build.gradle中加入:

apply from: 'tinkerpatch.gradle'
configurations.all { resolutionStrategy.cacheChangingModulesFor 0, 'seconds'}

其次,修改tinkerpatch.gralde中的配置:

image

詳細(xì)說(shuō)明見(jiàn)tinkerpatch.gralde文件中的注釋。注意,這里面會(huì)配置一個(gè)appVersion字段,這個(gè)字段的值一定要跟在tinker patch平臺(tái)創(chuàng)建的版本一致

4. 在代碼中添加支持,設(shè)置補(bǔ)丁下發(fā)策略、回滾策略、補(bǔ)丁生效機(jī)制等等

首先有兩種方式,第一種是修改Application類,將我們的Application類繼承DefaultApplicationLike類,然后在其中做配置;第二種是直接在我們現(xiàn)有的Application類中添加代碼。
1.獲取TinkerPatchApplicationLike對(duì)象
tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();

2.配置:詳見(jiàn)官方文檔:http://www.tinkerpatch.com/Docs/api

image

5. 正常打包以生成基線包

注意在打包后,需要將tinker生成的bakApk目錄相關(guān)文件歸檔保存。

6. 打補(bǔ)丁包

執(zhí)行TinkerPatchRelease任務(wù)即可。

image

生成的文件如下:

image

其中patch_signed_7zip.apk是經(jīng)過(guò)7zip壓縮的,不過(guò)當(dāng)補(bǔ)丁文件本身較小的時(shí)候,壓縮后的包會(huì)大于原大小,我們只需要選擇最小的那個(gè)即可。

7. 上傳到tinker patch平臺(tái),選擇開(kāi)發(fā)調(diào)試

其實(shí),集成起來(lái),我們按照上述步驟來(lái)就行了。比較簡(jiǎn)單。關(guān)鍵就是在不同場(chǎng)景需求下能想出對(duì)應(yīng)的解決辦法。比如,遇到緊急問(wèn)題時(shí),我們可以采用上述方式發(fā)布補(bǔ)丁,再比如當(dāng)補(bǔ)丁本身出現(xiàn)問(wèn)題時(shí),我們可以使用它的回滾功能來(lái)回滾補(bǔ)丁。

8. 開(kāi)發(fā)調(diào)試

1.首先要將tinkerPatch平臺(tái)的appkey在代碼里設(shè)置好
在文件tinkerpatch.gradle中,tinkerpatchSupport后面的閉包里,設(shè)置:

image

2.然后將打好的補(bǔ)丁包上傳到tinker patch平臺(tái):
http://www.tinkerpatch.com/Apps
上傳補(bǔ)丁時(shí)選擇“開(kāi)發(fā)預(yù)覽”

是不是簡(jiǎn)單到你都不想看~~ 那就對(duì)了,這就是tinker patch的優(yōu)勢(shì)

image

3.將開(kāi)發(fā)調(diào)試工具安裝到你要調(diào)試的設(shè)備上:

以下為官方給的工具及說(shuō)明:
“由于 Tinker 與代碼相關(guān),我們不能通過(guò)在代碼設(shè)置是否為 debug 模式。這里我們提供了 debug 調(diào)試工具,它的 Github 地址為 tinkerpatch-debug-tool。 我們也可以通過(guò)點(diǎn)擊此鏈接下載?!?/p>

4.在debug tool中打開(kāi)開(kāi)關(guān),然后重啟你的APP,然后你的熱更新補(bǔ)丁就會(huì)下載、合并到本地。此時(shí)可以觀察logcat日志,有相關(guān)的日志打印出來(lái):

image

9. 條件下發(fā)

1.在代碼中添加條件

image

在發(fā)布補(bǔ)丁時(shí),選擇條件下發(fā):

image

注意,在代碼中設(shè)置條件時(shí),我們?cè)O(shè)置的是String->String這樣的鍵值對(duì),這里條件下發(fā)時(shí),條件寫(xiě)的是test>9,能生效嗎?能,因?yàn)樵诒容^的時(shí)候,tinkerpatch會(huì)將之前代碼中設(shè)置的值轉(zhuǎn)為數(shù)值再比較。這里注意兩點(diǎn):
1.代碼中設(shè)置的條件是可以設(shè)置多個(gè)的。
2.在選擇條件下發(fā)時(shí),條件表達(dá)式也是可以組合的,具體規(guī)則如下:
官方文檔中對(duì)于條件下發(fā)的說(shuō)明

image

下發(fā)后,在重啟APP之后就會(huì)有如下的日志打印出來(lái)。

image

然后新的代碼就生效了。

另外有個(gè)問(wèn)題

假如,我們?cè)诨€包中設(shè)置的條件是("test","1"),然后在補(bǔ)丁包中修改了這個(gè)值為("test","10"),那么,在下次條件下發(fā)補(bǔ)丁的時(shí)候,下發(fā)條件設(shè)置為test>9,這個(gè)時(shí)候能不能成功下發(fā)呢?

答案是,能,因?yàn)樵谇耙粋€(gè)補(bǔ)丁中,已經(jīng)修改了這個(gè)值。

10. 補(bǔ)丁回滾

如果我們?cè)谙掳l(fā)一個(gè)補(bǔ)丁之后,發(fā)現(xiàn)修改bug的補(bǔ)丁,自己又產(chǎn)生了bug,也就是改了一個(gè)bug之后,同時(shí)又寫(xiě)了一個(gè)更牛逼的bug??????,那么這個(gè)時(shí)候怎么辦呢?
有兩個(gè)辦法:
1.如果新的bug只是小問(wèn)題,而且錯(cuò)誤代碼的范圍是比較小的。那么就簡(jiǎn)單了。直接再來(lái)個(gè)補(bǔ)丁就行。
2.但是如果你寫(xiě)的這個(gè)bug確實(shí)比較牛逼,而且影響范圍巨大,比如,合并代碼時(shí),合錯(cuò)分支了,而且又比較緊急(比如做了個(gè)發(fā)紅包的活動(dòng),。然后如果要修改的話又需要比較久的時(shí)間。這個(gè)時(shí)候如果線上用戶再等你修改好再發(fā)一個(gè)補(bǔ)丁,估計(jì)都涼涼了。

雖然tinker很牛逼,但是這種情況還是比較麻煩的。
首先,得在tinker patch后臺(tái)刪除整個(gè)基線版本。
然后,在客戶端下次重啟APP的時(shí)候就會(huì)執(zhí)行清理補(bǔ)丁動(dòng)作,并會(huì)將版本回退到基線版本。
然后,等你慢慢整理好代碼確保沒(méi)問(wèn)題之后,可以使用最新的代碼基于最開(kāi)始的基線版本,重新打個(gè)補(bǔ)丁,然后再重新發(fā)布。

tinker清除補(bǔ)丁對(duì)應(yīng)日志如下:

image
image

參考:https://blog.csdn.net/u010386612/article/details/51077291等等

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容