1. 程式人生 > >Bugly Android熱更新總結篇

Bugly Android熱更新總結篇

前言

之前發過一篇文章——Bugly熱更新SDK你需要知道的一些事,那是Bugly整合Tinker之後正式釋出的第一個版本—1.2.0,針對我們熱更新能力進行的一些說明,經過之後的版本迭代當中也是不斷的跟進Tinker版本並且不斷優化和簡化開發者的接入,讓開發者能夠將熱更新能力真正代入產品的使用當中。

在開發者使用熱更新SDK的過程中我們很多問題的反饋,大部分是對熱更新不夠了解導致的,這個也正如Tinker作者所說的:

熱更新不是請客吃飯。

我們也希望開發者在使用我們SDK的時候應該對熱更新有一個清晰的認識,那就是:

我們所採用的熱更新方案能做什麼和不能夠做些什麼?

實際開發當中我們有哪些東西可能是我們需要修改的,或者說產品上線之後會面臨修復的? 我們可以列舉一下:

  • 類檔案
  • So庫
  • 資源

這三個東西Tinker都是完全支援的,類和資源在實際開發中最有可能需要通過熱更新來修復,而So庫場景可能會相對少一點。

那麼Tinker不支援你修改什麼?

  • AndroidManifest檔案
  • 新增四大元件

關於Tinker的能力,大家可以移步看下Tinker Wiki

開發者為什麼這麼熱衷於熱更新?

熱更新解決了開發者的一個痛點就是程式邏輯出現bug了,導致業務邏輯混亂或者導致程式崩潰,但這些bug不會導致App完全不可用,如果通過發版來解決問題的話週期又太長

,那麼通過熱更新下發補丁能夠幫助產品及時修復問題,而不需要等待版本更新。這也是為什麼國內稍微大一點的產品都有自己的熱更新方案,通過避免頻繁發版來保證產品的穩定性。不過熱更新能力對於一些開發者來說可能更多是一種事後救火的行為,對產品質量不夠信心,才想著有這麼一個東西就算出現問題也不需要太大的擔心,有這樣想法的同學是非常危險的。

開發者最好不要依賴熱更新來保證產品質量,建議在產品需要緊急修復問題的情況下才應該考慮熱更新。

Bugly跟Tinker有什麼不同?

有很多開發者問,Bugly跟Tinker有什麼不同,它們之間有什麼關係呢?這裡正式把這個問題說清楚:

Tinker是一個開源框架,而Bugly熱更新SDK是基於這套框架進行的能力封裝,提供介面方便開發者能夠快速實現熱更新能力。而Tinker只是開源了客戶端程式碼,並沒有開源補丁管理後臺,我們Bugly也提供了補丁管理後臺,所以開發者只需要接入我們SDK就無需自己搭建補丁管理後臺。所以說Bugly提供的是一整套熱更新能力解決方案,而不僅僅是客戶端的能力。

這裡還需要提及一些技術實現,Tinker補丁的生成是通過Gradle外掛來實現的,整個打補丁的過程對開發者來說是透明的,Bugly在Tinker外掛基礎上開發了TinkerSupport外掛來生成符合我們平臺規則的補丁,主要就是在TinkerPatch外掛生成的補丁插入一個配置檔案-YAPATCH.MF

這裡寫圖片描述

如何在實際開發中使用熱更新能力

很多開發者在使用熱更新能力的時候,測試的時候還好,但一到正式使用但時候就有點蒙圈,這也是對熱更新不夠理解的一種表現,下面筆者針對一些需要開發者去理解的概念。

基線版本vs補丁版本

在使用外掛打補丁的時候需要我們去指定基線版本,那麼我們需要怎麼去理解這個概念呢,簡單來說就是你已經上線版本的apk,而這個apk能打補丁的前提是已經整合過熱更新SDK。

無論使用什麼熱更新方案,都是基於某一個版本進行打補丁,而被打補丁的版本就是基線版本。

在使用tinker-support外掛進行打補丁我們需要配置以下幾個內容:

  • 基線版本Apk
  • 基線版本的mapping檔案
  • 基線版本的R檔案

最佳實踐就是你通過持續整合系統發版前編譯生成以上幾個檔案,然後對程式碼版本庫進行打tag,如果線上版本出現問題就通過tag來拉取程式碼,將持續整合系統生成對基線版本對應的三個檔案下載放到工程的某個目錄,然後對外掛進行引數配置,接著就是通過外掛進行打補丁包,最後將補丁包上傳到Bugly平臺進行下發。

補丁版本就沒啥好說的,就是針對基線版本修復問題到版本,它也是需要走編譯打包流程的,因為基線版本需要跟補丁版本進行比較才能差分生成補丁包。

關於tinker-support打補丁配置如下圖所示:

這裡寫圖片描述

tinkerId到底有什麼作用,每次打補丁都需要修改?

前面說到打補丁的時候會在補丁基礎上插入一個配置檔案— YAPATCH.MF,裡面有兩個配置引數:

From:表示你是基於某個基線版本打的補丁包
To: 表示的是你當前打補丁的版本

為什麼要這麼設計? 主要是因為每次編譯會通過外掛在AndroidManifest檔案插入TINKER_ID的meta-data,用來唯一標識當前版本,所以你每次打包的時候都是需要修改tinkerId,我們在執行基線版本時會將tinkerId與當前版本號進行一個關聯一起上報到我們後臺,打補丁的時候外掛會讀取基線版本的tinkerId寫到From欄位,當前版本寫到To欄位,上傳補丁到管理後臺的時候前端會通過解析配置檔案讀取From欄位,然後去後臺匹配tinkerId對應的版本,這也是為什麼如果你上傳補丁From欄位的tinkerId沒有上報過聯網就匹配不到具體版本。

為什麼需要重啟補丁才能夠生效?

有很多同學對Tinker熱更新方案為什麼要重啟兩次才能夠生效,這裡需要大家先了解一下Tinker關於合成補丁的原理,Tinker採用的是ClassLoader方案,這種方案具有具有較高的穩定性和相容性。我們先看下面這張圖:

這裡寫圖片描述

可以看到補丁包是基線版本和補丁版本差分的結果,但合成補丁包的時候跟Qzone方案是有區別的,tinker是採用全量合成dex來實現熱更新,前者會將補丁包單獨做成一個dex插入到dexElements最前面,而後者是全量合成dex插入到dexElements最前面。熟悉ClassLoader機制的同學應該知道,載入類的時候會去遍歷dex檔案,並且會優先載入排在前面的dex,應用啟動的時候載入的就是已經修復問題的dex檔案。這裡有個潛規則就是:

如果已經被載入過的類,就不會重複被載入,這就解釋了為什麼要殺掉程序重啟app才能夠修復問題。

那為什麼Bugly熱更新有時候需要重啟兩次才能夠生效呢,因為這裡涉及到請求策略,下載補丁的過程,如果應用啟動的時候沒有檢測到補丁存在就不會下載補丁,我們並不會實時去檢測補丁的存在,所以只有重啟的時候才會去檢查補丁,檢查到補丁就會下載並自動合成,合成補丁之後還需要再次重啟才會生效,這也就是為什麼需要重啟兩次。

渠道包怎麼使用熱更新?

多渠道熱更新是一個坑,很多同學在接入Bugly熱更新之後就會問,怎麼支援到多渠道?這裡有兩種情況,一種是通過productFlavors來打渠道包,這種方式沒有辦法做到一個補丁修復所有渠道,因為它打出來的包dex的crc值都是不一致的,所以只能一個渠道一個補丁對應修復問題,但這個對於需要打很多渠道包的app開發者來說就是一個災難,因為需要忍受漫長的打包過程還要逐個上傳補丁包。這個肯定是不符合我們的需求的,所以我們推薦通過多渠道工具來打渠道包,具體參考筆者之前的一篇文章:Bugly多渠道熱更新解決方案

這裡要提一點,要基於tinker外掛打出來的基準包來打渠道。

加固包怎麼使用熱更新?

加固可以說是一個巨坑,tinker 1.7.5版本及以前是支援回退QZone方案來支援加固,但因為市面上沒有統一的加固方案會引入一些更加嚴重的問題,所以後面tinker官方將加固支援去掉了,但很多產品都接入了加固,如果用了加固就不能再使用熱更新,所以後面Tinker重新對市面上的加固方案重新做了相容,但需要在1.7.8版本以上才支援。

實際應用你需要做以下操作:

  1. 開啟加固模式,將isProtectedApp設定為true
  2. 將打出來的基線版本上傳到加固平臺進行加固並重簽名
  3. 打補丁是基於非加固的基線版本進行的

用一張圖解釋Bugly熱更新

這裡寫圖片描述

完整測試流程

  1. 打基準包安裝並上報聯網(注:填寫唯一的tinkerId)
  2. 對基準包的bug修復(可以是Java程式碼變更,資源的變更)
  3. 修改基準包路徑、修改補丁包tinkerId、mapping檔案路徑(如果開啟了混淆需要配置)、resId檔案路徑
  4. 執行buildTinkerPatchRelease打Release版本補丁包
  5. 選擇app/build/outputs/patch目錄下的補丁包並上傳(注:不要選擇tinkerPatch目錄下的補丁包,不然上傳會有問題)
  6. 編輯下發補丁規則,點選立即下發
  7. 殺死程序並重啟基準包,請求補丁策略(SDK會自動下載補丁併合成)
  8. 再次重啟基準包,檢驗補丁應用結果
  9. 檢視頁面,檢視啟用資料的變化

熱更新接入教程

熱更新本不是一件很容易的事情,儘管我們儘量把文件寫得比較詳細,開發者在接入過程中總會遇到一些問題,所以我們錄製了一套關於Bugly Android熱更新接入的完整教程,通過實操和講解來幫助開發者能夠減少出錯的概率,如果大家對於文件不清楚的地方或者接入過程中遇到問題,可以看下視訊哦,對應的課程連結如下:

這裡寫圖片描述

最後

Bugly熱更新自上線以來,花了很大部分時間去優化產品和教育使用者,我們的工作已經不僅僅只是做SDK這麼簡單了,作為一個SDK產品可能僅僅只是及格的水平,我們還有很多需要做的事情,比如提供更方便開發者驗證熱更新能力的功能和實踐和支援更多維度的條件下發,再或者更加極端會將tinker從SDK中進行剝離,僅提供補丁管理的能力,只提供回撥介面讓開發者自己去更新和整合tinker版本,給開發者更大的自由性,至於後面以什麼形式給到開發者我們也會繼續考量,感謝廣大使用者對我們Bugly的支援,也希望大家能夠給予我們更多的反饋,讓我們做得更好,謝謝大家。