有贊移動熱修復平臺建設

有贊移動熱修復平臺建設作者:李子部門:電商技術中心
一、背景

1.1 為什么要搭建熱修復平臺

隨著公司的快速發展,需求的快速增加,App迭代也越來越頻繁,如果移動應用出現問題,不僅僅影響用戶體驗,還會影響公司口碑,甚至可能造成資損。需要快速修復線上問題,對比常規的開發流程而言,熱修復更加靈活方便,優勢很多:

  • 無需重新發版,實時高效修復bug;
  • 用戶無感知修復,無需下載新的版本,代價小;
  • 修復成功率高,能把損失降到最低;
  • 因此熱修平臺愈加重要,需要搭建一個高效,好用且安全的熱修復平臺。

1.2 思考

搭建熱修復平臺,首先要考慮熱修方案的選擇,但這不是本文的重點,我們這里不做過多討論。目前有贊 Android 側的熱修是基于 Tinker 自建的后端服務 + Android SDK 實現的。下圖簡要描述了熱修的主要過程:有贊移動熱修復平臺建設看似簡單的流程,在多人開發團隊中,其實存在很多問題:

  • 每次版本打包發布,如何保存基準包及mapping等文件用于后續熱修生成補丁?
  • 熱修代碼的分支如何規范管理?
  • 如何構建補丁包,構建了如何保存 ?
  • 補丁包如何快速高效的本地驗證 ?
  • 補丁發布策略,發布審批等
  • 補丁下發數據如何統計?
  • 針對特定用戶怎么查詢熱修狀態?
  • 熱修出了問題怎么定責,怎么對熱修代碼追溯?

1.3 熱修平臺定義

針對以上問題,我們認為熱修平臺應具備以下特點:

  • 支持打包文件保存
  • 定義標準的熱修分支規范
  • 支持補丁包的構建保存
  • 支持方便的本地驗證測試
  • 支持權限審批
  • 支持補丁全量,灰度及條件發布
  • 支持熱修狀態查詢,數據統計
  • 支持歷史熱修代碼查看

二、熱修復平臺

2.1 寫在前面

在后面介紹熱修復平臺的過程中,會多次提到 MBD 及 APUB,這里先做下說明,便于下文理解:

  • MBD(Mobile Build): 有贊的移動應用構建平臺, 支持App構建, 熱修構建及SDK構建。
  • APUB(App Publish): 應用及熱修等發布平臺,APUB 的上游為 MBD,承接了 CI 系統的產物。下游則是 C 端用戶,作為應用發布生命周期的最后一環,為所有應用補全了熱修復 和 灰度分發相關的能力。

同時為了講清楚熱修復平臺,本文以Android為例按照熱修過程,順序介紹。

2.2 打包文件保存

Android 側使用 Tinker 首先要考慮的是構建產物及 mapping 等文件的保存,用于后續打補丁包由于有贊內部 App 發版構建, 熱修構建,SDK構建等都是通過 MBD 構建平臺,且MBD 本身已支持打包產物的自定義上傳,因此借助 MBD 構建平臺就可以做到保存 apk&mapping 文件。MBD 構建平臺打包是在運行著 GitLabRunner 的黑蘋果上進行的, GitLabRunnerGitLab 基于 Go 實現的腳本解釋器,如果感興趣可以自行了解下,這里不再展開。App 使用 MBD 打包需要先指定打包腳本,腳本為 yaml 格式,其中 artifacts 指定哪些文件要上傳到 CDN , 配置中的 paths 中指定了 Tinker 構建產物目錄 bakApk&mapping ,因此Tinker 產物會上傳到 CDN, 腳本如下:

build:Git API    artifacts:        untracked: false        name: "out"        preview_pattern: "app-full-release.apk"        cdn_path: "xxxxxxxx"        paths:            - app/build/bakApk            - app/build/outputs/apk/            - app/build/outputs/mapping/full/release/    script:        - env        - ./gradlew clean assembleFullRelease -PTINKER_ID=$CI_BUILD_ID -PBAK_PATH=$CI_PROJECT_DIR/app/build/bakApk -Paar=$JOB_COMPONENT_DEPENDENCIES -PMBD_RELEASE=$JOB_BUILD_RELEASE -PMBD_TEST_VERSION=$JOB_COMPONENT_VERSION -PMBD_BRANCH_NAME=$CI_COMMIT_REF_NAME --no-daemon                




2.3 熱修分支規范

MBD 操作拉取分支修復問題移動團隊達到一定規模后,需要同步制定相應的分支規范,其中熱修相關的分支管理需要考慮兩個問題:

1. 應該從哪個分支拉取代碼修改打補丁?2. 修復問題后熱修代碼合并問題?

這里有必要簡單說明下:有贊每次發版都會有開車的概念,所有待發布的功能都會上車合并到一個從master 分支拉出的 bus/${version}-${date}的分支,在 bus/${version}-${date}分支打出包后,開發同學自測然后交由項目的測試回歸,沒問題后,最后經App的測試同學回歸,回歸通過后開發同學會將 bus/${version}-${date} 分支合入master 構建 release 包。由于考慮到也可能會拉分支對老版本發布熱修,因此上述MBD構建成功后也會入庫記錄該 release版本構建時的 commit hash。基于以上兩點我們規定每個 release版本都有一個固定的熱修分支為 hotfix/${version}-mbd,熱修分支的管理也是直接由MBD構建平臺統一規范處理的如圖所示:有贊移動熱修復平臺建設MBD 構建平臺每個App構建,熱修構建,SDK構建都是一個集成單(多次構建行為的集合,每次正式構建前都可能會有若干次測試構建),舉例來說如 App2.3.5 版本發現問題需要熱修復:有贊移動熱修復平臺建設

  1. 首先要在MBD 構建平臺搜索 2.3.5版本的 release集成單, release集成單中包含一個熱修復按鈕
  2. 點擊熱修復按鈕判斷 2.3.5 版本是否已經存在 hotfix/2.3.5-mbd 分支?
  3. 存在直接創建熱修復集成單,不存在MBD平臺調用 GitLabAPI 創建 hotfix/2.3.5-mbd 分支
  4. 開發者在 hotfix/2.3.5-mbd 拉取創建修改問題的分支,如 hotfix/xxx_bugfix

至此解決了 應該從哪個分支拉取代碼修改打補丁? 的問題,合并到哪個分支的問題,暫且不表,下文會講到。

2.4 補丁構建及保存

如上所述,熱修構建也是在MBD平臺完成的,由于之前app發版構建的產物已經打包 上傳到了 CDN,再次構建時 MBD 平臺只需把產物下載解壓到 Tinker 基準包路徑, 同App打包邏輯,熱修構建也是通過 yaml腳本配置,指定要上傳補丁文件的相對路徑,補丁構建命令執行結束后會上傳補丁文件到 CDN,用于后續補丁下發,簡要過程如圖:有贊移動熱修復平臺建設補丁構建腳本

patch:    artifacts:        untracked: false        name: "patch"        preview_pattern: "patch_signed.apk"        paths:          - app/build/outputs/apk/full/tinkerPatch/full/release/patch_signed_7zip.apk          - app/build/outputs/apk/full/tinkerPatch/full/release/patch_signed.apk    script:        - env        - pwd        - mv app/build/bakApk base/        - ls base/        - ./gradlew clean tinkerPatchFullRelease -Paar=$JOB_COMPONENT_DEPENDENCIES --no-daemon -POLD_BUILD_FLAVOR=$CI_PROJECT_DIR/base        - rm -rf base

2.5 驗證熱修

補丁上傳到CDN 后,為了確保下發的補丁沒問題,需要驗證補丁,這是至關重要的一步。那怎么加載補丁呢?Tinker 也提供了加載本地補丁包的 API

TinkerInstaller.onReceiveUpgradePatch(context, 補丁包的本地路徑);

因此我們只需要把 CDN 文件下載到特定路徑,在App重啟時檢測補丁文件是否已下載,如果已下載直接加載補丁即可。驗證補丁首先要考慮怎么方便開發者使用,步驟越少越快越好,因為通常發布熱修本身就是非常緊急的問題,由于有贊內部有移動助手App(支持常用的開發功能,開發環境切換,抓包等) 移動同學都會使用,因此可以把熱修驗證功能放在移動助手App。從使用簡便程度上來說,二維碼似乎是不錯的選擇,因此我們定下的方案是,移動助手App 掃碼獲取二維碼信息,二維碼中包含:

  1. 補丁MD5 安全校驗 、簽名
  2. 補丁 CDN 地址
  3. 補丁對應App版本及基準包 CDN 地址
  4. 補丁對應App包名

其中第[3]點用于檢測驗證熱修的手機當前安裝的版本是否是基準包,如果不是提示下載安裝補丁對應基準包版本,避免浪費時間。第[4]點用于補丁合成后,根據包名重啟App,主要是考慮到 Tinker 的機制補丁本地合成后,需要再次冷啟動使補丁生效。有贊移動熱修復平臺建設移動助手App 掃碼上圖中的二維碼后,請求補丁信息,執行拉取補丁本地合成補丁,如果合成成功后被熱修App啟動后會看到熱修合成成功頁面,否則不能明確的知道是否已熱修合成,開發者會比較迷惑,同時為了方便多次合成測試的場景,比如第一次補丁問題沒有修復,需要再次合成,也支持了清除補丁功能。如圖所示:有贊移動熱修復平臺建設有贊移動熱修復平臺建設

2.6 發布策略

驗證補丁沒問題后,需要根據情況選定發布策略,目前支持三種熱修發布策略

2.6.1 全量發布

全量發布,不用解釋,補丁對應版本App所有用戶都可拉取補丁

2.6.2 灰度發布

灰度下發支持按人數灰度 與 按比例灰度,按照人數灰度相對簡單,因此這里只說下按比例灰度,灰度如果按照總人數的百分比進行下發,有可能會下發到不活躍用戶的設備上,讓百分比下發失去意義。目前一個簡單的方式是實現哈希碰撞算法,概率可調,當App端請求補丁時,根據設備的唯一標識進行碰撞,落到概率區間內則下發補丁。

2.6.3 條件發布

很多時候在發布一個補丁時,需要在小范圍內進行驗證,比如特定某個系統版本或者特定某個用戶;在驗證通過后再進行全網用戶的下發,這中場景下可以使用條件下發。Apub 平臺在發布補丁時可以選擇使用條件下發,除上傳補丁外,還可以填寫條件語句,只有滿足條件的設備才會執行修復補丁。其中條件語句由 key/value/運算符 組成,條件語句的規則與代碼中的條件表達式一致,支持 “==、!=、>、<、>=、<=、&&、||” 等運算符,如:

userId == 10023451 && roleType == 1

后端對DSL解析引擎可參考:https://developer.mozilla.org/zh-CN/docs/Mozilla/Projects/Rhino另外特定版本的App 可能會發布多個補丁,如果結合使用多種下發補丁也會遇到些新的問題,舉例來說如果先條件發布了一個補丁,再全量發布了另一個補丁App應該怎么處理?因此制定了App補丁使用規則:

  • 若第一次下發補丁,包含了條件值,不符合條件的設備補丁不會生效。
  • 若非第一次下發補丁,上一個補丁版本是全量下發,不符合條件的設備會請求上一個版本補丁。
  • 若非第一次下發補丁,上一個補丁版本非全量下發(灰度/條件/開發),不符合條件的設備若之前請求過補丁,會保留執行之前的補丁,若沒有請求過補丁(新用戶),不會請求到補丁。

2.7 發布審批

在確定了補丁使用哪種發布方式后,還需要由指定人(通常為TL)統一收斂權限,同時對熱修代碼做二次檢查(Code review),有贊不會允許未經復核檢驗的熱修代碼隨意的發布線上,萬一出了問題,可能會影響大量用戶。對于有贊權限管理感興趣讀者的可以看這篇文章《有贊權限與審批流程的標準化》引用上文中舉的例子說明:如果 A 同學需要修改 App2.3.5 版本的問題,發布熱修復。

  1. 開發者需要從 hotfix/2.3.5-mbd拉取 hotfix/xxx_bugfix 分支
  2. 在 hotfix/xxx_bugfix分支修改問題并構建補丁
  3. 接著申請發布補丁,在審批通過之后,發布熱修的同學在 Apub平臺上操作下發在 MBD平臺構建并上傳到 CDN的補丁

仔細想想,是不是遺漏了什么?還記得上文說到熱修分支規范時,修復問題后熱修代碼的合并問題么?為了避免開發者在修改問題后直接發布補丁,代碼忘記合并導致后續版本也有問題的情況,同時也為了規范管理熱修分支。如圖:有贊移動熱修復平臺建設

  • Apub 發布平臺在 A 發起審批時,自動創建了 hotfix/xxx_bugfix->hotfix/2.3.5-mbdMR 并自動寫入審批單申請理由中。
  • A點擊下發補丁時調用 GitLabAPI 獲取 MR 狀態,如果 MR 已合并則允許下發,否則提示 A 催促審批人合并代碼才可下發補丁
  • 最后下次發版時將 hotfix/2.3.5-mbd 分支添加到下一趟發版列表中,將 bug 修復代碼帶到下一趟車中,最終合入 master

2.8 熱修數據統計

補丁下發后,還需要實時觀察熱修生效情況,如果有問題要及時暫停下發或回滾補丁,有贊熱修提供了基礎的數據統計,包含已修復設備數量,合并失敗錯誤統計等。有贊移動熱修復平臺建設

2.9 設備熱修狀態查詢

在某些場景下,可能需要查詢特定用戶或特定用戶賬號的熱修狀態常見的一種情況是:用戶反饋了個線上問題,開發同學確認問題并修改發布補丁后,悻悻的回復用戶已經修復了,重復殺掉App打開幾次即可。用戶說好我試試,過了一段時間,又反饋說還是有問題啊,但是明明已經發布熱修復了(頭皮發麻),這時就可以根據用戶賬號信息查詢熱修狀態了,如下圖。有贊移動熱修復平臺建設

2.10 熱修代碼回溯

還有一些特殊情況,歷史版本里發布的熱修復導致了新的問題,需要確認問題責任人,或者排查特定問題,需要排除熱修代碼的影響,需要查看該版本發布的熱修復代碼。針對該情況,我們把上文中發起審批時創建的MR落庫記錄,并提供了查看代碼變更按鈕,點擊按鈕直接跳轉記錄的 GitLabMR, 即可查看代碼變更。

三、平臺架構及流程

3.1 熱修平臺架構

上面講的內容比較多也比較雜,可以結合熱修平臺架構圖來看,有個全局的視角:有贊移動熱修復平臺建設

3.2 熱修流程梳理

最后我們還以上文中的例子回顧下分享的內容,有贊發布熱修復的流程:

Android 發布熱修流程

  1. 開發者在 MBD平臺搜索需要熱修版本的集成單,點擊熱修復按鈕,MBD會創建 hotfix/2.3.5-mbd 分支,同時創建一個熱修集成單 (MBD 構建平臺每個App構建,熱修構建,SDK構建都是一個集成單)
  2. 開發者需要從 hotfix/2.3.5-mbd拉取創建 hotfix/xxx_bugfix 分支
  3. 在 hotfix/xxx_bugfix分支修改問題提交代碼并在MBD平臺創建的熱修集成單上操作構建補丁
  4. 然后使用有贊移動助手App 掃碼驗證補丁
  5. 接著在Apub發布平臺選擇熱修發布方式,填寫申請發布理由申請發布補丁,Apub 平臺會自動創建 hotfix/xxx_bugfix -> hotfix/2.3.5-mbd 的 MR,并把 MR地址自動填充到申請理由中,開發者等待審批,審批通過之后,確認 MR合并,即可發布操作下發補丁

iOS 發布熱修流程

上文很少提及iOS 熱修復,主要是因為iOS 熱修相對簡單,沒有 Android基準包等復雜邏輯:

  1. 根據具體問題,編寫熱修腳本,通過iOS 熱修SDK,本地運行調試
  2. 調試通過后在 Apub平臺上傳熱修腳本,并選擇熱修發布方式,填寫申請發布理由申請發布補丁,iOS 側由于修復機制等原因,沒有自動創建 MR 等邏輯
  3. 審批通過之后,即可下發補丁

四、總結

本文主要介紹了有贊的熱修復平臺,及在搭建過程中遇到的一些問題。熱修平臺實現了高效、穩定、可靠的熱修復補丁上傳、驗證、分發、權限管理等功能,并提供補丁基本數據統計,可以直接復用到各業務線,避免重復建設。有贊熱修復平臺,是結合有贊移動團隊實際開發過程遇到的問題,逐步解決逐漸完善的,讀者可以結合自身團隊打造合適的熱修復管理平臺,希望有贊熱修復平臺的建設經驗可以對你有所幫助。如果你有比較好的建議,可以評論回復,如有任何問題,歡迎指正。

來源:有贊coder,本文觀點不代表自營銷立場,網址:http://www.wfapiao.com/p/44361

發表評論

登錄后才能評論
侵權聯系
返回頂部
AV天堂日本AV天堂欧美AV天堂